AOP для C# dotnet core 2.0, доступ к значениям параметров метода перед запуском тела метода

Это мой метод, я пытаюсь проверить componentToSave (или получить доступ к значениям параметра метода) и вызвать исключение до того, как тело метода будет запущено.

public Component SaveComponent(Component componentToSave) {
    ...
}
  1. Я пытался использовать PostSharp, но он не бесплатный, а также были и другие библиотеки, использующие AutoFac в качестве IoC, но в своей текущей установке я использую встроенное внедрение зависимостей ядра dotnet.

  2. Я старался NConcern и это зависит от CNeptune а также CNeptune сам опирается на .exe файл для связывания после компиляции, и в настоящее время я использую Linux как для разработки, так и для производства, поэтому я не могу использовать его, даже пытался протестировать его на Windows, но не смог заставить его работать с ядром dotnet.

  3. Я попробовал этот подход (т.е. ActionFilter а также ServiceFilter) но у меня это работает только если [ServiceFilter(typeof(LoggingActionFilter))] над контроллером, а не какой-либо другой метод (т.е. SaveComponent метод).

  4. Я пытался с помощью RealProxy но, по-видимому, это не поддерживается в ядре dotnet.

Я просто потерян, может быть, я слишком усложняю проблему, но должен быть способ. Любая помощь будет принята с благодарностью.

1 ответ

Посмотрите на CQS, декораторы и SimpleInjector. Если вы продвигаете методы к классам, вы можете иметь класс, посвященный одной вещи (SOLID). Затем вы можете добавить сквозные задачи для декораторов, которые будут иметь тот же интерфейс, что и реализация, но они будут существенным образом связывать вызовы. Если валидационный декоратор завершится неудачно, ваша основная логика никогда не будет вызвана. Вы даже можете добавить всю обработку исключений здесь и любую логику логирования или повторения или кеширование.

редактировать

Извините, раньше был на мобильном телефоне!:)

Для примера я буду использовать ваш метод здесь. Обычно с CQS у вас будет общий интерфейс для всех ваших запросов (только для чтения) и команд (изменение состояния). Таким образом, вся ваша логика в конечном итоге проходит через IQueryHandler или ICommandHandler, так что вы можете добавить сквозные проблемы ко всей вашей логике одновременно. Однако я приведу пример, специфичный для вашего вопроса.

public interface ISaveComponent
{
    Component SaveComponent(Component componentToSave);
}

public class SaveComponent : ISaveComponent
{
    public Component SaveComponent(Component componentToSave)
    {
        // Do your work here
    }
}

public class SaveComponentValidation : ISaveComponent
{
    private readonly ISaveComponent _saveComponent;

    public SaveComponentValidation(ISaveComponent saveCompnent)
    {
        _saveComponent = saveCompnent;
    }

    public Component SaveComponent(Component componentToSave)
    {
        // Do Validation here
        return _saveComponent.SaveComponent(componentToSave);
    }
}

Если вы позволите SimpleInjector (IoC/DI) обрабатывать декорации для вас, то вам просто нужно зарегистрировать их в одной строке кода следующим образом:

 container.RegisterDecorator(typeof(ISaveComponent), typeof(SaveComponentValidation));

В противном случае вам придется вручную создать их следующим образом:

public class Program
{
    public static void Main()
    {
        ISaveComponent handler = new SaveComponentValidation(new SaveComponent());
        handler.SaveComponent(new Component());
    }
}

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

Одна реализация динамического прокси, которая поддерживается в.NET Core, предоставляется Castle.Core пакет.

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

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


  1. Установить пакеты.

Install-Package Decor

Install-Package Decor.Extensions.Microsoft.DependencyInjection

  1. Создайте декоратор, содержащий логику проверки.
public class ComponentValidator : IDecorator
{    
    public async Task OnInvoke(Call call)
    {
        var componentToSave = (Component)call.Arguments[0];

        if (/* Your validation logic */)
            throw new Exception("Something's not right.");

        await call.Next();
    }
}
  1. добавлять [Decorate(typeof(ComponentValidator))] атрибут метода (ов), который вы хотите проверить.
[Decorate(typeof(ComponentValidator))]
public virtual Component SaveComponent(Component componentToSave) {
    ...
}
  1. Зарегистрируйте Decor.NET, декоратор проверки и декорированный класс, используя методы расширения, предоставляемые Decor.Extensions.Microsoft.DependencyInjection.
services.AddDecor()
    .AddTransient<ComponentValidator>()
    .AddScoped<SomeService>().Decorated();

Обратите внимание, что декорированный метод должен быть переопределяемым (помечен как virtual или реализовано из интерфейса). Это необходимо для динамического прокси, чтобы переопределить реализацию метода.

Другие вопросы по тегам