在Controller Action中的绑定模型中注入ihttpcontextaccessor

本文关键字:模型 注入 ihttpcontextaccessor 绑定 Controller Action | 更新日期: 2023-09-27 18:15:33

我有一个控制器动作方法:

public void Register([FromBody]RegisterTenantCommand message)
{
    ...
}

我有类RegisterTenantCommand构造器:

public class RegisterTenantCommand
{
    public RegisterTenantCommand(IHttpContextAccessor httpContextAccessor)
        : base(httpContextAccessor) { }
}

但是当我启动我的应用程序并执行此操作时,我有httpContextAccessor = null

如何解决这个问题?

在Controller Action中的绑定模型中注入ihttpcontextaccessor

似乎您将命令与UI框架的命令混淆(如WPF+MVVM实现的ICommand接口)。

当前的实现也违反了SRP原则,即一个类应该只负责一件事。你基本上是处理输入(将其绑定到用户值)并执行它,以及处理其中的执行逻辑。

命令/处理器或CQRS模式中的命令仅仅是消息,它们只包含数据(这些数据可能被序列化,也可能不被序列化,并通过消息总线发送给其他后台进程处理)。

// ICommand is a marker interface, not to be confused with ICommand from WPF
public class RegisterTenantCommand : ICommand
{
    public string TenantId { get; set; }
    public string Name { get; set; }
}

命令处理程序由一个标记接口和它的实现组成(1:1关系,一个命令对应一个处理程序)。

public interface ICommandHandler<T> where T : ICommand
{
    void Handle(T command);
}
public class RegisterTenantCommandHandler : ICommandHandler<RegisterTenantCommand>
{
    private readonly IHttpContext context;
    // You should really abstract this into a service/facade which hides
    // away the dependency on HttpContext
    public RegisterTenantCommandHandler(IHttpContextAccessor contextAccessor)
    {
        this.context = contextAccesspor.HttpContext;
    }
    public void Handle(RegisterTenantCommand command)
    {
        // Handle your command here
    }
}

在使用Autofac等第三方IoC时自动注册,或者使用内置IoC手动注册(这里我将使用内置IoC):

services.AddTransient<ICommandHandler<RegisterTenantCommand>, RegisterTenantCommandHandler>();

你可以在action、controller或任何其他service中注入它:

public class TenantController 
{
    public TenantController(ICommandHandler<RegisterTenantCommand> registerTenantHandler)
    {
        ...
    }
}

或动作

public Task<IActionResult> RegisterTenant(
    [FromBody]RegisterTenantCommand command,
    [FromService]ICommandHandler<RegisterTenantCommand> registerTenantHandler
)
{
    registerTenantHandler.Handle(command);
}

当然,你可以进一步抽象它,只注入一个接口类来解析和处理所有的命令,然后叫它generalCommandHandler.Handle(command),它的实现将解析和处理它

IHttpContextAccessor服务默认不注册

IHttpContextAccessor可以用来访问当前线程。然而,维护这种状态具有重要的意义性能成本,因此它已从默认设置中删除服务。

依赖它的开发人员可以根据需要添加它:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

请参阅aspnet/Hosting#793进行讨论。