This presentation will teach you to never repeat yourself and organize your code correctly for reuse.
It also illustrates advantages of the use of third-party libraries.
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. Перспектива написания однотипного кода почему-то отпугивает вас.
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
Возможно ли писать и использовать клиент-серверный код так же просто, как
локальный?
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)));
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);
}