вторник, 20 августа 2013 г.

Фреймворк: Rikrop.Core.Framework.dll

К оглавлению

Rikrop.Core.Framework.dll

Эта библиотека содержит множество наиболее обобщенных инструментов, которые находят применение из проекта в проект. Рассмотрим чуть подробнее каждое пространство имен.

 namespace Rikrop.Core.Framework

Сюда мы поместили те классы и инструменты, которые являются инфраструктурными.

public static class CollectionExtentions

Поскольку коллекции в .NET развивались вместе с самим фреймворком, не каждый из контейнеров получил удобный интерфейс манипуляции данными. Здесь мы собрали методы расширения, которые решают эту проблему. Мы вставляем, добавляем, перебираем, ищем и осуществляем слияние.

public static class CryptoHelper

К счастью, в .NET есть классы для работы алгоритмами шифрования, цифровой подписи и хеширования. К сожалению, их интерфейс довольно громоздкий. Для себя мы сделали маленький класс с единственным методом:

public static string GetShaHash(string str) { ... }

public class DateRange

Класс представляет собой тип данных для хранения диапозонов дат, при этом диапозон может быть открытым. Экземпляры умеют сравнивать себя с другими, округлять до целых дней и сериализоваться.

public interface ITodayNowProvider + public class TodayNowProvider + public interface IDateTimeProvider + public class DateTimeProvider : IDateTimeProvider

Мы често работаем с временем и столкнулись с проблемой покрытия кода, связанного с определением времени относительно текущего. А еще очень часто оказалось важным иметь доступ к таким данным как "текущий месяц", "прошлая неделя". Реализация  DateTimeProvider и чудесный класс DateRange дали возможность с лёгкостью манипулировать типов данных DateTime. Вот простой пример mock для тестирования функционала, использующего провайдер даты-времени.
var today = new DateTime(2013, 05, 2);
var dateTimeProvider = Mock.Create<IDateTimeProvider>();
Mock.Arrange(() => dateTimeProvider.Today).Returns(today);

А вот вкратце и без излишних комментариев и интерфейс IDateTimeProvider
public interface IDateTimeProvider
{
    DateTime Now { get; }
    DateTime UtcNow { get; }
    DateTime Today { get; }

    DateRange GetLogicalDateRange(DateTime dateFrom, DateTime dateTo, int dayStartHour);
    DateRange GetFactDateRange(DateTime logicDateFrom, DateTime logicDateTo, int dayStartHour);
    DateRange MaxRange();
    DateRange GetMonthAgo(int monthCount = -1);
    DateRange GetCurrentMonth();
    DateRange GetToday();
    DateRange GetYesterday();
    DateRange GetCurrentWeek();
    DateRange GetLastWeek();
    DateRange GetTwoWeeksAgo();
    DateRange GetLastMonth();
}

public static class ExpressionHelper

Мы активно работаем над строгой типизацией и статической проверкой в коде, поэтому активно используем работу с деревьями выражений (Expressions). В этом классе собраны важные, хоть и редкоприменимые методы для разбора и получения информации из деревьев выражений.

public static class SerializerExtention

В .NET нет такого удобного инструмента как generic-serializer. У нас он есть.

public interface ITimer + public class SimpleTimer : ITimer + public class RepeatableExecutor

Мы решили абстрагироваться от множества реализаций таймеров, которые есть в .NET и переносимо между платформами решить наиболее частую задачу, в которой применяются таймера - повторяемый запуск определенного события.

namespace Rikrop.Core.Framework.ActiveDirectory

Интеграция приложений с AD является важной темой. В .NET на данный момент существует несколько подходов к работе с сущностями домена, однако для типовых задач часто хватает ограниченного набора функций. Основным классом здесь является ADManager.
public interface IADManager
{
    IEnumerable<ADUserEntity> GetUsersInGroup(string groupName, bool recursive);
    IEnumerable<ADUserEntity> GetAllUsers();
    IEnumerable<ADUserEntity> GetUsersWithNameAndLastName();
    IEnumerable<ADGroupEntity> GetUserGroups(string userIdentity);
    IEnumerable<ADGroupEntity> GetAllGroups();
    bool ValidateAuthorization();
}
Стоит отметить, что это лишь базовый набор функций, каждое приложение ставит свои требования и единого интерфейса для интеграции с различной структурой AD заказчиков достичь очень проблематично, но мы всегда строим свои системы максимально настраиваемыми и универсальными.

namespace Rikrop.Core.Framework.Exceptions

Для обработки исключений мы используем механизм, схожий с Exception Handling Application Block из Enterprise library. Вместе с этим, мы постарались упростить механизм обработки исключений.
public interface IExceptionHandler
{
    bool Handle(Exception exception);
}
У нас нет готовых обработчиков, пока двух одинаковых решений по обработке исключений в наших проектах не встретилось. Но фреймворк поддерживается в максимально актуальном состоянии и как только типовое решение появится - мы сразу добавим его. В Enterprise library логирование может быть организовано через подсистему обработки ошибок, но у нас мухи отделены от перехвата исключений.

namespace Rikrop.Core.Framework.Logging

Поскольку логирование событий необходимо практически в каждом приложении, мы вынесли инфраструктуру для логирования в общую сборку.
public interface ILoggerFactory
{
    ILogger CreateForSource(string logSource);
}

public interface ILogger
{
    void Log<TRecord>(TRecord record) where TRecord : ILogRecord;
}

public interface ILogRecord
{
    LogRecordLevel LogLevel { get; }
    string Message { get; }
    LogRecordDataValue[] DataValues { get; }
    bool HasDataValues { get; }
}
Мы не стали реализовывать в базовой библиотеке конкретные логгеры, вместо этого можно подключить библиотеки Rikrop.Core.Logging.dll и Rikrop.Core.Logging.NLog.dll. По необходимости всегда можно написать свой логгер, но пока необходимости в этом не возникало.

namespace Rikrop.Core.Framework.Services

Взаимодействие с уровнем сервисов занимает очень важное место в нашем фреймворке. Если рассматривать клиентскую сторону взаимодействия, то мы приняли концепцию работы с сервисами через Executor'ы, которые могут обладать некоторыми дополнительными свойствами в зависимости от контекста. Например, для работы в ViewModel на время запуска метода сервиса может исполняться триггер для извещения интерфейса о том, что приложение занято. Точкой входа является интерфейс
public interface IServiceExecutor<out TService>
{
    Task Execute(Func<TService, Task> action);
    Task<TResult> Execute<TResult>(Func<TService, Task<TResult>> func);
}

Комментариев нет:

Отправить комментарий