Реализуйте сквозной валидатор для очень разных методов, используя C#

У меня есть небольшая структура с архитектурой клиент / сервер. Я использую эти инструменты на своем бизнес-уровне:

DI = SimpleInjector

DynamicProxy для перехвата = Castle.Core

Теперь мне нужно проверить некоторые проверки! например, посмотрите на этот метод:

public void DeleteFakeItem (Guid userId, Guid fakeItemId)
{
    userAccountService.IsAuthorized(userId, FeatureIndex.DeleteFakeItem);

    if (fakeItemId == Guid.EmptyGuid || userId == Guid.EmptyGuid) 
        throw new ArgumentNullException("parameters are not correct!");

    if (!repo.IsFakeItemIsDeletable(fakeItemId))
        throw new Exception("you can not delete this item!");

    var fakeItem = repo.GetFakeItem(fakeItemId);

    if (fakeItem == null)
        throw new Exception("this fakeItem dose not exists!");

    repo.DeleteActivityCenter(fakeItem);
}

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

Как я могу реализовать функцию сквозной резки для проверки моих параметров?

я думаю, что могу сделать это с помощью перехватчика и атрибутов, например, атрибута, такого как [Validate(ValidateEnum.NotNull)] для каждого параметра.

какой правильный путь?

и второй вопрос для моих сущностей: могу ли я получить беглые правила проверки API для проверки сущностей на их основе с использованием отражения с перехватчиком?

например, я хочу получить правила, если есть IsRequired() Правило, подтвердите как не нуль.

я не хочу использовать шаблон декоратора, потому что это заставляет меня много рефакторинга;

2 ответа

Решение

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

У меня есть перехватчик, который перехватывает все методы. и это работает для меня. но кто-нибудь может дать мне некоторую информацию о спектакле? это правильный способ сделать проверку? перехватчик:

public class ValidatorInterceptor : IInterceptor
{

    private readonly IServiceFactory factory;

    public ValidatorInterceptor(IServiceFactory _factory)
    {
        factory = _factory;
    }

    public void Intercept(IInvocation invocation)
    {
        var methodParameterSet = invocation.InvocationTarget.GetType().GetMethod(invocation.Method.Name).GetParameters().ToList();
        for (var index = 0; index < methodParameterSet.Count; index++)
        {
            var parameter = methodParameterSet[index];
            var paramType = parameter.ParameterType;
            var customAttributes = new List<object>();
            var factoryMethod = factory.GetType().GetMethod("GetService");
            var baseValidatorType = typeof(IValidator<>);
            var validatorType = baseValidatorType.MakeGenericType(paramType);
            factoryMethod = factoryMethod.MakeGenericMethod(validatorType);
            var validator = factoryMethod.Invoke(factory, null);

            customAttributes.AddRange(parameter.GetCustomAttributes(true).Where(item => item.GetType().Name.StartsWith("Validate")));
            foreach (var attr in customAttributes)
            {
                dynamic attribute = attr;
                var method = validator.GetType().GetMethod("Validate");
                method = method.MakeGenericMethod(paramType);
                object[] parameterSet = {invocation.Arguments[index], attribute.Rule, attribute.IsNullCheck};
                method.Invoke(validator, parameterSet);
            }
        }

        invocation.Proceed();
    }
}

и реализация IValidator для объекта UserAccount выглядит следующим образом:

public class ValidateUserAccount<T> : IValidator<T> where T : UserAccount
{
    public void Validate<T>(T entity, object obj1 = null, object obj2 = null) where T : class
    {
        var item = (UserAccount) Convert.ChangeType(entity, typeof(UserAccount));

        if (item == null)
            throw new ArgumentNullException("user account cant be null");
    }

}

и для проверки строки:

public class ValidateString : IValidator<string>
{
    public void Validate<T>(T entity, object rukeObj = null, object nullChekcObj = null) where T : class
    {
        var item = (string) Convert.ChangeType(entity, typeof(string));
        var rule = (Regex)Convert.ChangeType(rukeObj, typeof(Regex));
        var reqItem = Convert.ChangeType(nullChekcObj, typeof(bool));
        var isRequire = reqItem != null && (bool) reqItem;

        if (isRequire && string.IsNullOrEmpty(item))
            throw new ArgumentException("value can not be null!");

        if (!rule.Match(item).Success)
            throw new ArgumentException("[" + item + "] is not a valid input!");

    }
}

Мое решение проблемы заключается в следующем ( вы можете найти его здесь):

  1. Интерфейс и класс реализации для того, чтобы иметь возможность изменять логику проверки - возможно, есть ошибки или изменения в логике проверки.
  2. Сделать большинство методов недействительными и генерировать исключения с помощью глобального обработчика исключений.
  3. Разделяйте реализацию и интерфейс в разных сборках. Этим я получаю выигрыш в производительности для юнит-тестов. У меня есть отдельные сборки для службы обмена сообщениями, служб кэширования, служб персистентности, потому что их реализации огромны и имеют много зависимостей, которые замедляют выполнение модульного теста до полного забвения. Когда ваши юнит-тесты ссылаются только на интерфейсные сборки, тесты компилируются и работают намного быстрее. Эта точка очень сильно влияет на огромные и долгоживущие проекты. - это влияет на качество кодовой базы!
Другие вопросы по тегам