AOP для C# dotnet core 2.0, доступ к значениям параметров метода перед запуском тела метода
Это мой метод, я пытаюсь проверить componentToSave
(или получить доступ к значениям параметра метода) и вызвать исключение до того, как тело метода будет запущено.
public Component SaveComponent(Component componentToSave) {
...
}
Я пытался использовать PostSharp, но он не бесплатный, а также были и другие библиотеки, использующие AutoFac в качестве IoC, но в своей текущей установке я использую встроенное внедрение зависимостей ядра dotnet.
Я старался
NConcern
и это зависит отCNeptune
а такжеCNeptune
сам опирается на.exe
файл для связывания после компиляции, и в настоящее время я использую Linux как для разработки, так и для производства, поэтому я не могу использовать его, даже пытался протестировать его на Windows, но не смог заставить его работать с ядром dotnet.Я попробовал этот подход (т.е.
ActionFilter
а такжеServiceFilter
) но у меня это работает только если[ServiceFilter(typeof(LoggingActionFilter))]
над контроллером, а не какой-либо другой метод (т.е.SaveComponent
метод).Я пытался с помощью
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. Ниже приведены инструкции о том, как добиться желаемого поведения.
- Установить пакеты.
Install-Package Decor
Install-Package Decor.Extensions.Microsoft.DependencyInjection
- Создайте декоратор, содержащий логику проверки.
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();
}
}
- добавлять
[Decorate(typeof(ComponentValidator))]
атрибут метода (ов), который вы хотите проверить.
[Decorate(typeof(ComponentValidator))]
public virtual Component SaveComponent(Component componentToSave) {
...
}
- Зарегистрируйте Decor.NET, декоратор проверки и декорированный класс, используя методы расширения, предоставляемые
Decor.Extensions.Microsoft.DependencyInjection
.
services.AddDecor()
.AddTransient<ComponentValidator>()
.AddScoped<SomeService>().Decorated();
Обратите внимание, что декорированный метод должен быть переопределяемым (помечен как virtual
или реализовано из интерфейса). Это необходимо для динамического прокси, чтобы переопределить реализацию метода.