如何使用在 Core 中使用支持依赖项注入 ASP.NET 自定义模型绑定程序

本文关键字:NET ASP 注入 自定义 模型 程序 绑定 依赖 Core 何使用 支持 | 更新日期: 2023-09-27 18:36:20

我正在尝试在 MVC 中使用自定义模型绑定器,我想从我的 IoC 容器中解析该绑定器。 我遇到的问题是,在添加 MVC 服务时无法访问我的容器,因为我的容器尚未构建(我需要在构建容器之前添加 MVC)。 感觉像鸡/蛋的问题,我确定我错过了一个简单的解决方案。

例:

services.AddMvc().AddMvcOptions(options =>
{
     options.ModelBinders.Add(serviceProvider.Resolve<CustomModelBinder>());
});

我的自定义模型绑定器如下所示:

public class CustomModelBinder : IModelBinder
{
    private IServiceProvider serviceProvider;
    public CustomModelBinder(IServiceProvider serviceProvider)
    {
        this.serviceProvider = serviceProvider;
    }
    public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
    {
        var model = serviceProvider.GetService(bindingContext.ModelType);
        bindingContext.Model = model;
        var binder = new GenericModelBinder();
        return binder.BindModelAsync(bindingContext);
    }
}

如何使用在 Core 中使用支持依赖项注入 ASP.NET 自定义模型绑定程序

根据这里的帖子:https://github.com/aspnet/Mvc/issues/4167

要直接回答您的问题,请使用:

bindingContext.OperationBindingContext.ActionContext.HttpContext.RequestServices

附带说明一下,您还可以选择使用[FromServices]为您解决它。

对于 ASP.NET Core 2.2,这应该适用于DI:

public class CustomModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        // dependency injection
        var model = bindingContext.HttpContext.RequestServices.GetService(bindingContext.ModelType);
        // other changes...
        bindingContext.Result = ModelBindingResult.Success(model);
        return Task.CompletedTask;
    }
}
您可以使用

IConfigureOptions来配置具有依赖关系注入的选项,而不是使用在模型绑定器中检索所需服务的服务定位器模式。这允许您延迟选项的配置,直到构建了依赖项注入容器。

下面是一个依赖于ICustomService的模型绑定器:

class CustomModelBinder : IModelBinder
{
    private readonly ICustomService customService;
    public CustomModelBinder(ICustomService customService) => this.customService = customService;
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        // Use customService during model binding.
    }
}

您需要此模型绑定程序的提供程序:

class CustomModelBinderProvider : IModelBinderProvider
{
    private readonly ICustomService customService;
    public CustomModelBinderProvider(ICustomService customService) => this.customService = customService;
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        // Return CustomModelBinder or null depending on context.
        return new CustomModelBinder(customService);
    }
}

通常,您将使用如下代码在Startup中添加模型绑定提供程序:

services.AddMvc().AddMvcOptions(options =>
{
    options.ModelBinderProviders.Add(new CustomModelBinderProvider(customService));
});

但是,正如您所指出的,这是不可能的。在配置系统时,您无法解析customService。此问题的一般解决方案是将IConfigureOptions与上述代码一起使用来配置选项,但具有能够使用依赖项注入的额外好处:

class CustomModelBinderConfigureMvcOptions : IConfigureOptions<MvcOptions>
{
    private readonly ICustomService customService;
    public CustomModelBinderConfigureMvcOptions(ICustomService customService) => this.customService = customService;
    public void Configure(MvcOptions options)
        => options.ModelBinderProviders.Add(new CustomModelBinderProvider(customService));
}

此类必须添加到容器中Startup

services.AddSingleton<IConfigureOptions<MvcOptions>, CustomModelBinderConfigureMvcOptions>();

现在,您可以使用具有依赖项的模型绑定程序。