SlideShare a Scribd company logo
1 of 26
Хватит писать
инфраструктурный код
Вадим Мартынов, безработный программист
Цели и желания
○ DRY
○ Тестируемость кода
○ Quick start
○ Минимизация кода приложения
○ Прозрачность aka простота использования
○ DI (применение IOC-контейнеров)
Типовые инфраструктурные задачи
○ Доступ к хранилищу данных
○ Хостинг wcf-сервисов и клиентский вызов wcf
○ Клиентский вызов asp.net mvc web api
○ Хранение настроек
Доступ к данным
1. Есть проект с Entity framework (>= 5.0.0.0) code first.
2. Вы любите IoC, но не любите бесконечные регистрации новых сущностей.
3. В качестве контейнера используется Unity (или есть возможность потратить 10 минут на
допиливание исходников под свой контейнер).
4. Перспектива написания однотипного кода почему-то отпугивает вас.
Доступ к данным
при помощи
Rikrop.Core.Data
Доступ к данным: Rikrop.Core.Data
Подготовка инфраструктуры:
1. Для проектов с Entity: PM> Install-Package Rikrop.Core.Data
Для проекта с контекстом БД: PM> Install-Package Rikrop.Core.Data.Unity
2. container.RegisterRepositoryContext<MyDbContext>();
//container.RegisterRepositoryContext(s => new MyDbContext(s), "myConStr");
//container.RegisterRepositoryContext<MyDbContext>(
new PerRequestLifetimeManager());
container.RegisterRepositories(typeof(Department).Assembly);
3. public class Department
: Entity<Int32>, IRetrievableEntity<Department, Int32> {}
public class Employee
: DeactivatableEntity<Int32>, IRetrievableEntity<Employee,Int32> {}
Доступ к данным: Rikrop.Core.Data
Использование:
var employeeRepository = container.Resolve<IRepository<Employee, int>>();
var employees = employeeRepository.Get(q =>
{
q = q.Filter(e => e.EmploymentDate >= new DateTime(2014, 9, 1))
.Include(e => e.Department, e => e.Department.Chief)
.OrderBy(e => e.Name);
if (excludeFired)
q = q.Filter(e => !e.Fired);
});
Доступ к данным: Rikrop.Core.Data
Расширяемость:
1. public interface IPersonRepository : IDeactivatableRepository<Person, int>
{
Person RecursiveLoad(Person parentCategory);
}
2. [Repository(typeof(IPersonRepository))]
public class PersonRepository : DeactivatableRepository<Person, int>, IPersonRepository
{
public Person RecursiveLoad(Person parent)
{
Context.Entry(parent).Collection(d => d.Children).Load();
parent.Children.ForEach(x => RecursiveLoad(x));
return parent;
}
}
3. var personRepository = container.Resolve<IPersonRepository>();
var p = personRepository.RecursiveLoad(person);
Доступ к данным: Rikrop.Core.Data
Интерфейс:
public interface IRepository<TEntity, in TId> : IRepository
where TEntity : class, IRetrievableEntity<TEntity, TId>, IEntity<TId>
{
TEntity Get(TId id);
IReadOnlyCollection<TEntity> Get(Action<RepositoryQuery<TEntity>> query);
IReadOnlyCollection<TEntity> GetAll();
//IQueryable<TEntity> GetQueryable();
TEntity Save(TEntity entity);
void Delete(TEntity entity);
}
WCF
Возможно ли писать и использовать клиент-серверный код так же просто, как
локальный?
WCF. Ожидание и реальность
WCF: ожидание и реальность
Добавление нового wcf-сервиса в существующий хост
Ожидание
1. Создать ServiceContract.
2. Реализовать контракт.
3. Вызвать новый сервис на клиенте.
Реальность
1. Создать ServiceContract.
2. Реализовать контракт.
3. Добавить в хост wcf код,
инициализирующий ServiceHost для
нового сервиса.
4. Добавить конфигурацию сервиса на
сервере и не клиенте.
5. Добавить ServiceReference.
6. Зарегистрировать вклиентском IoC-
контейнере Proxy-класс нового сервиса.
7. Вызвать новый сервис на клиенте.
WCF: ожидание и реальность
Изменение настроек (адреса сервера, типа привязки)
Ожидание
1. В серверной регистрации изменить
строку с типом привязки или адресом.
2. В клиентской регистрации изменить
строку с типом тип привязки или
адресом.
Реальность
<endpoint
address="http://localhost:8500/LE/Services/Emission/EmissionReferencesService"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IEmissionReferencesService"
contract="EmissionReferencesServiceReference.IEmissionReferencesService"
name="BasicHttpBinding_IEmissionReferencesService" />
<endpoint address="http://localhost:8500/LE/Services/Emission/EmissionService"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IEmissionService"
contract="EmissionServiceReference.IEmissionService"
name="BasicHttpBinding_IEmissionService" />
<endpoint
address="http://localhost:8500/LE/Services/InjurySafety/InjurySafetyReferencesServ
ice" behaviorConfiguration="InjurySafetyReferencesServiceBehavior"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IInjurySafetyReferencesService"
contract="InjurySafetyReferencesServiceReference.IInjurySafetyReferencesService"
name="BasicHttpBinding_IInjurySafetyReferencesService" />
<endpoint
address="http://localhost:8500/LE/Services/InjurySafety/WorkplaceInjurySafetyCondi
tionsService" behaviorConfiguration="HugeDataTransferServiceBehavior"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IWorkplaceInjurySafetyConditionsService"
contract="WorkplaceInjurySafetyConditionsServiceReference.IWorkplaceInjurySafetyCo
nditionsService" name="BasicHttpBinding_IWorkplaceInjurySafetyConditionsService"
/>
<endpoint
address="http://localhost:8500/LE/Services/IndividualProtection/IndividualProtecti
onReferencesService"
behaviorConfiguration="IndividualProtectionReferencesServiceBehavior"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IIndividualProtectionReferencesService"
contract="IndividualProtectionServiceReference.IIndividualProtectionReferencesServ
ice" name="BasicHttpBinding_IIndividualProtectionReferencesService" />
WCF: Быстро. Прозрачно. Гибко
Подготовка инфраструктуры:
1. Install-Package Rikrop.Core.Wcf.Unity
2. Пишем ServiceContract и их реализации
3. На сервере и клиенте добавляем одну строку регистрации в IoC (конфиги править не надо)
4. Поднимаем хосты с двух строк:
var assembly = Assembly.GetExecutingAssembly();
_serviceHostManager.StartServices(assembly);
5. На клиенте резолвим IServiceExecutor<TService>. Эта обёртка служит для вызова методов сервиса и
скрывает работу с каналом.
6. Можно пользоваться
var articles = await _serviceExecutor.Execute(s => s.GetArticles(theme)));
WCF: Быстро. Прозрачно. Гибко
Расширяемость:
container
.RegisterType<ISessionResolver<Session>, SessionResolver<Session>>()
.RegisterServerWcf(
o => o.RegisterServiceConnection(reg => reg.NetTcp(serviceIp, servicePort))
.RegisterServiceHostFactory(reg => reg.WithBehaviors()
.AddErrorHandlersBehavior(eReg => eReg.AddBusinessErrorHandler().AddLoggingErrorHandler(NLogger.CreateEventLogTarget()))
.AddDependencyInjectionBehavior()
.AddCustomBehavior<ActionPerformanceTrackingBehavior>()
.AddServiceAuthorizationBehavior(sReg => sReg.WithStandardAuthorizationManager()
.WithStandardSessionHeaderInfo(“TimeTracker", "SessionId")
.WithOperationContextSessionIdInitializer()
.WithSessionAuthStrategy<Session>()
.WithLoginMethod<ILoginService>(s => s.Login())
.WithOperationContextSessionIdResolver()
.WithInMemorySessionRepository()
.WithStandardSessionCopier())));
WCF: Быстро. Прозрачно. Гибко
http://habrahabr.ru/post/246961/
https://github.com/Vadimyan/Rikrop.WcfExample
https://github.com/Vadimyan/Rikrop.WcfExample/tree/AuthorizationExample
https://github.com/rikrop/Rikrop.Core.Wcf
https://github.com/rikrop/Rikrop.Core.Wcf.Unity
Asp.net mvc web api 2
До чего многословное название, надеюсь, пользоваться им легче, чем
произносить
Mvc web api. Вызов из клиента .net
Ожидание
var executor = container
.Resolve<IServiceExecutor<IArticleController>>();
var articles = await executor
.Execute(c => c.GetArticles(theme.Id));
var newArticleId = await executor
.Execute(c => c.PostArticle(article));
await executor.Execute(c =>
c.Delete(newArticleId));
Реальность
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:9000/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add
(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response =
await client.GetAsync("api/articles/3");
if (response.IsSuccessStatusCode)
{
var article = await response.Content.ReadAsAsync<Article>();
}
}
Mvc web api. Сбываем мечту
container
.RegisterClientWebApi(
o => o.RegisterServiceExecutor(reg=> reg.Standard()
.WithErrorHandlers()
.AddHttpStatusCodeToExceptionHandler())
.RegisterMultipartContainer()
.RegisterConnection(reg => reg.Https(baseAddress)
.WithBehaviors()
.AddRouteResolverBehavior(x => x.AddReflectionResolver()
.AddExternalResolver<RouteActionsMapper>())
.AddAuthorizationBehavior(x => x.WithBearerAuthStrategy()
.WithInMemorySessionRepository()))
);
Mvc web api. Готовые решения: WebApiProxy
1. PM> Install-Package WebApiProxy.Csharp
2. Add configuration WebApiProxy.config:
<proxy endpoint="http://myservice.net/api" />
3. Можно пользоваться
using (var client = new PeopleClient())
{
var response = await client.GetAsync("Fanie");
var people = await response.Content.ReadAsAsync<Person[]>();
}
4. Документация:
Что ещё: Собственные наработки
• Предупреждение UI о выполнении асинхронной операции
interface IBusyServiceExecutor : IServiceExecutor { bool IsBusy {get; } }
class SingleCallBusyServiceExecutorWithPopup : BusyServiceExecutorBase
• INPC
• ILogger, ILoggerFactory и реализации
ConsoleLogger/NLogger
Что ещё
Что ещё
1. public interface IWindowPositionProvider
{
Rect Position { get; set; }
bool IsMaximazed { get; set; }
Task SaveSettings();
}
2. public class SettingsWindowPositionProvider : IWindowPositionProvider {}
public class XmlWindowPositionProvider : IWindowPositionProvider {}
3. public interface IWindowPositionProviderFactory
{
Task<IWindowPositionProvider> Get(string key);
}
Что ещё
4. public interface ISettingsProvider
{
Task<TSettings> Get<TSettings>();
Task<TSettings> Get<TSettings>(string key);
Task Save<TSettings>(TSettings settings);
Task Save<TSettings>(TSettings settings, string key);
}
5. Rikrop.Core.SettingsProvider.dll
Rikrop.Core.SettingsProvider.AppConfig.dll
Rikrop.Core.SettingsProvider.Database.EnityFramework.dll
Rikrop.Core.SettingsProvider.Xml.dll
6. https://docs.nuget.org/create/hosting-your-own-nuget-feeds
https://www.myget.org/
https://www.nuget.org/packages/upload
Что ещё: AspNetBoilerplate
• Documentation
• Overall
• NLayer Architecture
• Module System
• Startup Configuration
• Dependency Injection
• Logging
• Nuget packages
• Change logs
• Domain layer
• Entities
• Repositories
• Unit Of Work
• Domain Events (EventBus)
• Application layer
• Application Services
• Data Transfer Objects
• Validating Data Transfer Objects
• Presentation layer
• Dynamic Web API Layer
• Javascript API
• Localization
• Navigation
• Handling exceptions
• Embedded resource files
• vadim@rikrop.ru
• http://www.rikrop.ru
• https://www.nuget.org/packages?q=rikrop
• https://github.com/rikrop

More Related Content

What's hot

Caching data outside Java Heap and using Shared Memory in Java
Caching data outside Java Heap and using Shared Memory in JavaCaching data outside Java Heap and using Shared Memory in Java
Caching data outside Java Heap and using Shared Memory in JavaAndrei Pangin
 
Developing highload servers with Java
Developing highload servers with JavaDeveloping highload servers with Java
Developing highload servers with JavaAndrei Pangin
 
Kvc, kvo
Kvc, kvoKvc, kvo
Kvc, kvoNoveo
 
JavaScript-библиотека
JavaScript-библиотекаJavaScript-библиотека
JavaScript-библиотекаVasya Petrov
 
Выжимаем из сервера максимум (Андрей Паньгин)
Выжимаем из сервера максимум (Андрей Паньгин)Выжимаем из сервера максимум (Андрей Паньгин)
Выжимаем из сервера максимум (Андрей Паньгин)Ontico
 
Евгений Потапов (Сумма Айти)
Евгений Потапов (Сумма Айти)Евгений Потапов (Сумма Айти)
Евгений Потапов (Сумма Айти)Ontico
 
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...AvitoTech
 
Что нового в nginx? / Максим Дунин (Nginx, Inc.)
Что нового в nginx? / Максим Дунин (Nginx, Inc.)Что нового в nginx? / Максим Дунин (Nginx, Inc.)
Что нового в nginx? / Максим Дунин (Nginx, Inc.)Ontico
 
Незаурядная Java как инструмент разработки высоконагруженного сервера
Незаурядная Java как инструмент разработки высоконагруженного сервераНезаурядная Java как инструмент разработки высоконагруженного сервера
Незаурядная Java как инструмент разработки высоконагруженного сервераodnoklassniki.ru
 
Asynchrony and coroutines
Asynchrony and coroutinesAsynchrony and coroutines
Asynchrony and coroutinescorehard_by
 
Smirnov twisted-python
Smirnov twisted-pythonSmirnov twisted-python
Smirnov twisted-pythonAndrey Smirnov
 
Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...
Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...
Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...Alexey Makhov
 
Распределенные системы в Одноклассниках
Распределенные системы в ОдноклассникахРаспределенные системы в Одноклассниках
Распределенные системы в Одноклассникахodnoklassniki.ru
 
Анатомия веб-сервиса (РИТ-2014)
Анатомия веб-сервиса (РИТ-2014)Анатомия веб-сервиса (РИТ-2014)
Анатомия веб-сервиса (РИТ-2014)Andrey Smirnov
 
Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev FedorProgramming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev FedorFedor Lavrentyev
 
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)Yandex
 
Управление секретами в кластере Kubernetes при помощи Hashicorp Vault / Серге...
Управление секретами в кластере Kubernetes при помощи Hashicorp Vault / Серге...Управление секретами в кластере Kubernetes при помощи Hashicorp Vault / Серге...
Управление секретами в кластере Kubernetes при помощи Hashicorp Vault / Серге...Ontico
 
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...PavelKonotopov
 

What's hot (20)

Caching data outside Java Heap and using Shared Memory in Java
Caching data outside Java Heap and using Shared Memory in JavaCaching data outside Java Heap and using Shared Memory in Java
Caching data outside Java Heap and using Shared Memory in Java
 
Developing highload servers with Java
Developing highload servers with JavaDeveloping highload servers with Java
Developing highload servers with Java
 
Kvc, kvo
Kvc, kvoKvc, kvo
Kvc, kvo
 
JavaScript-библиотека
JavaScript-библиотекаJavaScript-библиотека
JavaScript-библиотека
 
Выжимаем из сервера максимум (Андрей Паньгин)
Выжимаем из сервера максимум (Андрей Паньгин)Выжимаем из сервера максимум (Андрей Паньгин)
Выжимаем из сервера максимум (Андрей Паньгин)
 
Евгений Потапов (Сумма Айти)
Евгений Потапов (Сумма Айти)Евгений Потапов (Сумма Айти)
Евгений Потапов (Сумма Айти)
 
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
Прокачиваем WebDriverAgent, или Как тестировать iOS-приложения после ядерного...
 
Что нового в nginx? / Максим Дунин (Nginx, Inc.)
Что нового в nginx? / Максим Дунин (Nginx, Inc.)Что нового в nginx? / Максим Дунин (Nginx, Inc.)
Что нового в nginx? / Максим Дунин (Nginx, Inc.)
 
Незаурядная Java как инструмент разработки высоконагруженного сервера
Незаурядная Java как инструмент разработки высоконагруженного сервераНезаурядная Java как инструмент разработки высоконагруженного сервера
Незаурядная Java как инструмент разработки высоконагруженного сервера
 
Asynchrony and coroutines
Asynchrony and coroutinesAsynchrony and coroutines
Asynchrony and coroutines
 
Smirnov twisted-python
Smirnov twisted-pythonSmirnov twisted-python
Smirnov twisted-python
 
Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...
Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...
Прокачиваем WebDriverAgent или как тестировать iOS-приложения после ядерного ...
 
JRebel
JRebelJRebel
JRebel
 
Распределенные системы в Одноклассниках
Распределенные системы в ОдноклассникахРаспределенные системы в Одноклассниках
Распределенные системы в Одноклассниках
 
Анатомия веб-сервиса (РИТ-2014)
Анатомия веб-сервиса (РИТ-2014)Анатомия веб-сервиса (РИТ-2014)
Анатомия веб-сервиса (РИТ-2014)
 
Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev FedorProgramming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor
 
New Android NDK & JNI
New Android NDK & JNINew Android NDK & JNI
New Android NDK & JNI
 
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
 
Управление секретами в кластере Kubernetes при помощи Hashicorp Vault / Серге...
Управление секретами в кластере Kubernetes при помощи Hashicorp Vault / Серге...Управление секретами в кластере Kubernetes при помощи Hashicorp Vault / Серге...
Управление секретами в кластере Kubernetes при помощи Hashicorp Vault / Серге...
 
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
Building the Enterprise infrastructure with PostgreSQL as the basis for stori...
 

Similar to Хватит писать инфраструктурный код

Система обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyСистема обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyRegn
 
Простой и кросс-платформенный WEB-сервер на .NET
Простой и кросс-платформенный WEB-сервер на .NETПростой и кросс-платформенный WEB-сервер на .NET
Простой и кросс-платформенный WEB-сервер на .NETMikhail Shcherbakov
 
IOP202 DevCon 2012 Apache Lucene in Windows Azure
IOP202 DevCon 2012 Apache Lucene in Windows AzureIOP202 DevCon 2012 Apache Lucene in Windows Azure
IOP202 DevCon 2012 Apache Lucene in Windows AzureVadim Novitskiy
 
.NET Fest 2018. Сергей Калинец. Azure веб разработка здорового человека
.NET Fest 2018. Сергей Калинец. Azure веб разработка здорового человека.NET Fest 2018. Сергей Калинец. Azure веб разработка здорового человека
.NET Fest 2018. Сергей Калинец. Azure веб разработка здорового человекаNETFest
 
Взломать сайт на ASP.NET
Взломать сайт на ASP.NETВзломать сайт на ASP.NET
Взломать сайт на ASP.NETPositive Hack Days
 
Обзор платформы B4
Обзор платформы B4Обзор платформы B4
Обзор платформы B4Bars Group
 
МАИ, Сети ЭВМ, Лекция №5
МАИ, Сети ЭВМ, Лекция №5МАИ, Сети ЭВМ, Лекция №5
МАИ, Сети ЭВМ, Лекция №5Dima Dzuba
 
Инструментируй это
Инструментируй этоИнструментируй это
Инструментируй этоRoman Dvornov
 
Dynamic Language Runtime
Dynamic Language RuntimeDynamic Language Runtime
Dynamic Language RuntimeSQALab
 
Evgeny Rybak Presentation
Evgeny Rybak PresentationEvgeny Rybak Presentation
Evgeny Rybak Presentationsef2009
 
The Old New ASP.NET
The Old New ASP.NETThe Old New ASP.NET
The Old New ASP.NETVitaly Baum
 
RESTful API: Best practices, versioning, design documentation
RESTful API: Best practices, versioning, design documentationRESTful API: Best practices, versioning, design documentation
RESTful API: Best practices, versioning, design documentationMikhail Shcherbakov
 
Как превратить приложение в платформу
Как превратить приложение в платформуКак превратить приложение в платформу
Как превратить приложение в платформуVadim Kruchkov
 
Семь тысяч Rps, один go
Семь тысяч Rps, один goСемь тысяч Rps, один go
Семь тысяч Rps, один goBadoo Development
 
Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!Vladimir Kochetkov
 
Node.JS: возможности для РНР-разработчика
Node.JS: возможности для РНР-разработчикаNode.JS: возможности для РНР-разработчика
Node.JS: возможности для РНР-разработчикаAlexei Smolyanov
 
Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин Sigma Software
 
Database (Lecture 14 – database)
Database (Lecture 14 – database)Database (Lecture 14 – database)
Database (Lecture 14 – database)Noveo
 
Паттерны быстрой разработки WPF MVVM бизнес-приложений
Паттерны быстрой разработки WPF MVVM бизнес-приложенийПаттерны быстрой разработки WPF MVVM бизнес-приложений
Паттерны быстрой разработки WPF MVVM бизнес-приложенийGoSharp
 

Similar to Хватит писать инфраструктурный код (20)

Система обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyСистема обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на Groovy
 
Простой и кросс-платформенный WEB-сервер на .NET
Простой и кросс-платформенный WEB-сервер на .NETПростой и кросс-платформенный WEB-сервер на .NET
Простой и кросс-платформенный WEB-сервер на .NET
 
IOP202 DevCon 2012 Apache Lucene in Windows Azure
IOP202 DevCon 2012 Apache Lucene in Windows AzureIOP202 DevCon 2012 Apache Lucene in Windows Azure
IOP202 DevCon 2012 Apache Lucene in Windows Azure
 
.NET Fest 2018. Сергей Калинец. Azure веб разработка здорового человека
.NET Fest 2018. Сергей Калинец. Azure веб разработка здорового человека.NET Fest 2018. Сергей Калинец. Azure веб разработка здорового человека
.NET Fest 2018. Сергей Калинец. Azure веб разработка здорового человека
 
Взломать сайт на ASP.NET
Взломать сайт на ASP.NETВзломать сайт на ASP.NET
Взломать сайт на ASP.NET
 
Обзор платформы B4
Обзор платформы B4Обзор платформы B4
Обзор платформы B4
 
МАИ, Сети ЭВМ, Лекция №5
МАИ, Сети ЭВМ, Лекция №5МАИ, Сети ЭВМ, Лекция №5
МАИ, Сети ЭВМ, Лекция №5
 
Viper architecture
Viper architectureViper architecture
Viper architecture
 
Инструментируй это
Инструментируй этоИнструментируй это
Инструментируй это
 
Dynamic Language Runtime
Dynamic Language RuntimeDynamic Language Runtime
Dynamic Language Runtime
 
Evgeny Rybak Presentation
Evgeny Rybak PresentationEvgeny Rybak Presentation
Evgeny Rybak Presentation
 
The Old New ASP.NET
The Old New ASP.NETThe Old New ASP.NET
The Old New ASP.NET
 
RESTful API: Best practices, versioning, design documentation
RESTful API: Best practices, versioning, design documentationRESTful API: Best practices, versioning, design documentation
RESTful API: Best practices, versioning, design documentation
 
Как превратить приложение в платформу
Как превратить приложение в платформуКак превратить приложение в платформу
Как превратить приложение в платформу
 
Семь тысяч Rps, один go
Семь тысяч Rps, один goСемь тысяч Rps, один go
Семь тысяч Rps, один go
 
Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!
 
Node.JS: возможности для РНР-разработчика
Node.JS: возможности для РНР-разработчикаNode.JS: возможности для РНР-разработчика
Node.JS: возможности для РНР-разработчика
 
Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин
 
Database (Lecture 14 – database)
Database (Lecture 14 – database)Database (Lecture 14 – database)
Database (Lecture 14 – database)
 
Паттерны быстрой разработки WPF MVVM бизнес-приложений
Паттерны быстрой разработки WPF MVVM бизнес-приложенийПаттерны быстрой разработки WPF MVVM бизнес-приложений
Паттерны быстрой разработки WPF MVVM бизнес-приложений
 

Хватит писать инфраструктурный код

  • 1. Хватит писать инфраструктурный код Вадим Мартынов, безработный программист
  • 2. Цели и желания ○ DRY ○ Тестируемость кода ○ Quick start ○ Минимизация кода приложения ○ Прозрачность aka простота использования ○ DI (применение IOC-контейнеров)
  • 3. Типовые инфраструктурные задачи ○ Доступ к хранилищу данных ○ Хостинг wcf-сервисов и клиентский вызов wcf ○ Клиентский вызов asp.net mvc web api ○ Хранение настроек
  • 4. Доступ к данным 1. Есть проект с Entity framework (>= 5.0.0.0) code first. 2. Вы любите IoC, но не любите бесконечные регистрации новых сущностей. 3. В качестве контейнера используется Unity (или есть возможность потратить 10 минут на допиливание исходников под свой контейнер). 4. Перспектива написания однотипного кода почему-то отпугивает вас.
  • 5. Доступ к данным при помощи Rikrop.Core.Data
  • 6. Доступ к данным: Rikrop.Core.Data Подготовка инфраструктуры: 1. Для проектов с Entity: PM> Install-Package Rikrop.Core.Data Для проекта с контекстом БД: PM> Install-Package Rikrop.Core.Data.Unity 2. container.RegisterRepositoryContext<MyDbContext>(); //container.RegisterRepositoryContext(s => new MyDbContext(s), "myConStr"); //container.RegisterRepositoryContext<MyDbContext>( new PerRequestLifetimeManager()); container.RegisterRepositories(typeof(Department).Assembly); 3. public class Department : Entity<Int32>, IRetrievableEntity<Department, Int32> {} public class Employee : DeactivatableEntity<Int32>, IRetrievableEntity<Employee,Int32> {}
  • 7. Доступ к данным: Rikrop.Core.Data Использование: var employeeRepository = container.Resolve<IRepository<Employee, int>>(); var employees = employeeRepository.Get(q => { q = q.Filter(e => e.EmploymentDate >= new DateTime(2014, 9, 1)) .Include(e => e.Department, e => e.Department.Chief) .OrderBy(e => e.Name); if (excludeFired) q = q.Filter(e => !e.Fired); });
  • 8. Доступ к данным: Rikrop.Core.Data Расширяемость: 1. public interface IPersonRepository : IDeactivatableRepository<Person, int> { Person RecursiveLoad(Person parentCategory); } 2. [Repository(typeof(IPersonRepository))] public class PersonRepository : DeactivatableRepository<Person, int>, IPersonRepository { public Person RecursiveLoad(Person parent) { Context.Entry(parent).Collection(d => d.Children).Load(); parent.Children.ForEach(x => RecursiveLoad(x)); return parent; } } 3. var personRepository = container.Resolve<IPersonRepository>(); var p = personRepository.RecursiveLoad(person);
  • 9. Доступ к данным: Rikrop.Core.Data Интерфейс: public interface IRepository<TEntity, in TId> : IRepository where TEntity : class, IRetrievableEntity<TEntity, TId>, IEntity<TId> { TEntity Get(TId id); IReadOnlyCollection<TEntity> Get(Action<RepositoryQuery<TEntity>> query); IReadOnlyCollection<TEntity> GetAll(); //IQueryable<TEntity> GetQueryable(); TEntity Save(TEntity entity); void Delete(TEntity entity); }
  • 10. WCF Возможно ли писать и использовать клиент-серверный код так же просто, как локальный?
  • 11. WCF. Ожидание и реальность
  • 12. WCF: ожидание и реальность Добавление нового wcf-сервиса в существующий хост Ожидание 1. Создать ServiceContract. 2. Реализовать контракт. 3. Вызвать новый сервис на клиенте. Реальность 1. Создать ServiceContract. 2. Реализовать контракт. 3. Добавить в хост wcf код, инициализирующий ServiceHost для нового сервиса. 4. Добавить конфигурацию сервиса на сервере и не клиенте. 5. Добавить ServiceReference. 6. Зарегистрировать вклиентском IoC- контейнере Proxy-класс нового сервиса. 7. Вызвать новый сервис на клиенте.
  • 13. WCF: ожидание и реальность Изменение настроек (адреса сервера, типа привязки) Ожидание 1. В серверной регистрации изменить строку с типом привязки или адресом. 2. В клиентской регистрации изменить строку с типом тип привязки или адресом. Реальность <endpoint address="http://localhost:8500/LE/Services/Emission/EmissionReferencesService" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IEmissionReferencesService" contract="EmissionReferencesServiceReference.IEmissionReferencesService" name="BasicHttpBinding_IEmissionReferencesService" /> <endpoint address="http://localhost:8500/LE/Services/Emission/EmissionService" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IEmissionService" contract="EmissionServiceReference.IEmissionService" name="BasicHttpBinding_IEmissionService" /> <endpoint address="http://localhost:8500/LE/Services/InjurySafety/InjurySafetyReferencesServ ice" behaviorConfiguration="InjurySafetyReferencesServiceBehavior" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IInjurySafetyReferencesService" contract="InjurySafetyReferencesServiceReference.IInjurySafetyReferencesService" name="BasicHttpBinding_IInjurySafetyReferencesService" /> <endpoint address="http://localhost:8500/LE/Services/InjurySafety/WorkplaceInjurySafetyCondi tionsService" behaviorConfiguration="HugeDataTransferServiceBehavior" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IWorkplaceInjurySafetyConditionsService" contract="WorkplaceInjurySafetyConditionsServiceReference.IWorkplaceInjurySafetyCo nditionsService" name="BasicHttpBinding_IWorkplaceInjurySafetyConditionsService" /> <endpoint address="http://localhost:8500/LE/Services/IndividualProtection/IndividualProtecti onReferencesService" behaviorConfiguration="IndividualProtectionReferencesServiceBehavior" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IIndividualProtectionReferencesService" contract="IndividualProtectionServiceReference.IIndividualProtectionReferencesServ ice" name="BasicHttpBinding_IIndividualProtectionReferencesService" />
  • 14. WCF: Быстро. Прозрачно. Гибко Подготовка инфраструктуры: 1. Install-Package Rikrop.Core.Wcf.Unity 2. Пишем ServiceContract и их реализации 3. На сервере и клиенте добавляем одну строку регистрации в IoC (конфиги править не надо) 4. Поднимаем хосты с двух строк: var assembly = Assembly.GetExecutingAssembly(); _serviceHostManager.StartServices(assembly); 5. На клиенте резолвим IServiceExecutor<TService>. Эта обёртка служит для вызова методов сервиса и скрывает работу с каналом. 6. Можно пользоваться var articles = await _serviceExecutor.Execute(s => s.GetArticles(theme)));
  • 15. WCF: Быстро. Прозрачно. Гибко Расширяемость: container .RegisterType<ISessionResolver<Session>, SessionResolver<Session>>() .RegisterServerWcf( o => o.RegisterServiceConnection(reg => reg.NetTcp(serviceIp, servicePort)) .RegisterServiceHostFactory(reg => reg.WithBehaviors() .AddErrorHandlersBehavior(eReg => eReg.AddBusinessErrorHandler().AddLoggingErrorHandler(NLogger.CreateEventLogTarget())) .AddDependencyInjectionBehavior() .AddCustomBehavior<ActionPerformanceTrackingBehavior>() .AddServiceAuthorizationBehavior(sReg => sReg.WithStandardAuthorizationManager() .WithStandardSessionHeaderInfo(“TimeTracker", "SessionId") .WithOperationContextSessionIdInitializer() .WithSessionAuthStrategy<Session>() .WithLoginMethod<ILoginService>(s => s.Login()) .WithOperationContextSessionIdResolver() .WithInMemorySessionRepository() .WithStandardSessionCopier())));
  • 16. WCF: Быстро. Прозрачно. Гибко http://habrahabr.ru/post/246961/ https://github.com/Vadimyan/Rikrop.WcfExample https://github.com/Vadimyan/Rikrop.WcfExample/tree/AuthorizationExample https://github.com/rikrop/Rikrop.Core.Wcf https://github.com/rikrop/Rikrop.Core.Wcf.Unity
  • 17. Asp.net mvc web api 2 До чего многословное название, надеюсь, пользоваться им легче, чем произносить
  • 18. Mvc web api. Вызов из клиента .net Ожидание var executor = container .Resolve<IServiceExecutor<IArticleController>>(); var articles = await executor .Execute(c => c.GetArticles(theme.Id)); var newArticleId = await executor .Execute(c => c.PostArticle(article)); await executor.Execute(c => c.Delete(newArticleId)); Реальность using (var client = new HttpClient()) { client.BaseAddress = new Uri("http://localhost:9000/"); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add (new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.GetAsync("api/articles/3"); if (response.IsSuccessStatusCode) { var article = await response.Content.ReadAsAsync<Article>(); } }
  • 19. Mvc web api. Сбываем мечту container .RegisterClientWebApi( o => o.RegisterServiceExecutor(reg=> reg.Standard() .WithErrorHandlers() .AddHttpStatusCodeToExceptionHandler()) .RegisterMultipartContainer() .RegisterConnection(reg => reg.Https(baseAddress) .WithBehaviors() .AddRouteResolverBehavior(x => x.AddReflectionResolver() .AddExternalResolver<RouteActionsMapper>()) .AddAuthorizationBehavior(x => x.WithBearerAuthStrategy() .WithInMemorySessionRepository())) );
  • 20. Mvc web api. Готовые решения: WebApiProxy 1. PM> Install-Package WebApiProxy.Csharp 2. Add configuration WebApiProxy.config: <proxy endpoint="http://myservice.net/api" /> 3. Можно пользоваться using (var client = new PeopleClient()) { var response = await client.GetAsync("Fanie"); var people = await response.Content.ReadAsAsync<Person[]>(); } 4. Документация:
  • 21. Что ещё: Собственные наработки • Предупреждение UI о выполнении асинхронной операции interface IBusyServiceExecutor : IServiceExecutor { bool IsBusy {get; } } class SingleCallBusyServiceExecutorWithPopup : BusyServiceExecutorBase • INPC • ILogger, ILoggerFactory и реализации ConsoleLogger/NLogger
  • 23. Что ещё 1. public interface IWindowPositionProvider { Rect Position { get; set; } bool IsMaximazed { get; set; } Task SaveSettings(); } 2. public class SettingsWindowPositionProvider : IWindowPositionProvider {} public class XmlWindowPositionProvider : IWindowPositionProvider {} 3. public interface IWindowPositionProviderFactory { Task<IWindowPositionProvider> Get(string key); }
  • 24. Что ещё 4. public interface ISettingsProvider { Task<TSettings> Get<TSettings>(); Task<TSettings> Get<TSettings>(string key); Task Save<TSettings>(TSettings settings); Task Save<TSettings>(TSettings settings, string key); } 5. Rikrop.Core.SettingsProvider.dll Rikrop.Core.SettingsProvider.AppConfig.dll Rikrop.Core.SettingsProvider.Database.EnityFramework.dll Rikrop.Core.SettingsProvider.Xml.dll 6. https://docs.nuget.org/create/hosting-your-own-nuget-feeds https://www.myget.org/ https://www.nuget.org/packages/upload
  • 25. Что ещё: AspNetBoilerplate • Documentation • Overall • NLayer Architecture • Module System • Startup Configuration • Dependency Injection • Logging • Nuget packages • Change logs • Domain layer • Entities • Repositories • Unit Of Work • Domain Events (EventBus) • Application layer • Application Services • Data Transfer Objects • Validating Data Transfer Objects • Presentation layer • Dynamic Web API Layer • Javascript API • Localization • Navigation • Handling exceptions • Embedded resource files
  • 26. • vadim@rikrop.ru • http://www.rikrop.ru • https://www.nuget.org/packages?q=rikrop • https://github.com/rikrop