ASP. net core 3.1, добавлена ​​поддержка внедрения зависимостей для действий контроллера с автоматически связанными параметрами [FromBody] - PullRequest
0 голосов
/ 06 апреля 2020

Я знаю, как внедрить в действия контроллера и контроллер напрямую, добавив сервис в IServiceprovider, а затем фреймворк просто обрабатывает его для меня, а в случае действий контроллера я мог бы добавить [Microsoft.AspNetCore.Mvc.FromServices], и он бы внедрил служба по указанному c действию.

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

Я хотел бы знать, возможно ли иметь что-то близкое к следующему:

[HttpPost]
public async Task<ActionResult> PostThings([FromBody]ParameterClassWithInjection parameter) {
  parameter.DoStuff();
...}

public class ParameterClassWithInjection{
  public readonly MyService _myService;
  public ParameterClassWithInjection(IMyService service){ _myService = service;}

  public void DoStuff(){ _myService.DoStuff(); }
}

Я нашел только кое-что о пользовательском связывателе модели в документах. https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-3.1#custom -model-binder-sample

Здесь показано, как можно создать пользовательское связующее и сделать так, чтобы пользовательский поставщик предоставил инъекцию. Кажется, мне просто нужно реализовать много стандартного кода из автоматического связывания c (который в каждом случае работает для меня абсолютно нормально), чтобы получить некоторую инъекцию зависимостей.

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

1 Ответ

0 голосов
/ 06 апреля 2020

Shotcut

Если тип контента JSON и вы используете Newtonsoft. Json, вы можете десериализовать вашу модель с внедрением зависимостей с помощью специального обработчика контрактов.

Привязка модели

В противном случае, если вам требуется поддержка других типов контента и т. Д. c, вам необходимо go сложным способом.

Для уточнения c модель или только модели FromBody:

Используйте подшивку модели и выполните внедрение свойства. См. мой ответ пару недель a go.

Для универсальных c моделей или моделей из других источников:

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

Например, :

public class DependencyInjectionModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        // Get MVC options.
        var mvcOptions = context.Services.GetRequiredService<IOptions<MvcOptions>>();

        // Find model binder provider for the current context.
        IModelBinder binder = null;
        foreach (var modelBinderProvider in mvcOptions.Value.ModelBinderProviders)
        {
            if (modelBinderProvider == this)
            {
                continue;
            }

            binder = modelBinderProvider.GetBinder(context);
            if (binder != null)
            {
                break;
            }
        }

        return binder == null
            ? null
            : new DependencyInjectionModelBinder(binder);
    }
}

// Model binder decorator.
public class DependencyInjectionModelBinder : IModelBinder
{
    private readonly IModelBinder _innerBinder;

    public DependencyInjectionModelBinder(IModelBinder innerBinder)
    {
        _innerBinder = innerBinder;
    }

    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        await _innerBinder.BindModelAsync(bindingContext);

        if (bindingContext.Result.IsModelSet)
        {
            var serviceProvider = bindingContext.HttpContext.RequestServices;

            // Do DI stuff.
        }
    }
}

// Register your model binder provider
services.AddControllers(opt =>
{
    opt.ModelBinderProviders.Insert(
        0, new DependencyInjectionModelBinderProvider());
});

Это работает для внедрения свойства.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...