Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将IHttpContextAcessor注入控制器动作内的绑定模型_C#_Asp.net Core_.net Core - Fatal编程技术网

C# 将IHttpContextAcessor注入控制器动作内的绑定模型

C# 将IHttpContextAcessor注入控制器动作内的绑定模型,c#,asp.net-core,.net-core,C#,Asp.net Core,.net Core,我有一个控制器动作方法: public void Register([FromBody]RegisterTenantCommand message) { ... } 我有类RegisterTenantCommand和构造函数: 但当我启动应用程序并执行此操作时,我有httpContextAccessor=null 如何解决这个问题?您似乎把命令与UI框架中的命令混淆了(比如ICommand接口的WPF+MVVM实现) 当前的实现也有点违反了SRP原则,在SRP原则中,类应该只负责一件事

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

public void Register([FromBody]RegisterTenantCommand message)
{
    ...
}
我有类RegisterTenantCommand和构造函数:

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


如何解决这个问题?

您似乎把命令与UI框架中的命令混淆了(比如
ICommand
接口的WPF+MVVM实现)

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

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

命令处理程序由标记接口及其实现(1:1关系,1个处理程序对应1个命令)组成

公共接口ICommandHandler,其中T:ICommand
{
无效句柄(T命令);
}
公共类注册器TenantCommandHandler:ICommandHandler
{
私有只读IHttpContext上下文;
//您应该将其抽象为一个隐藏
//消除对HttpContext的依赖
公共注册表TenantCommandHandler(IHttpContextAccessor contextAccessor)
{
this.context=contextAccesspor.HttpContext;
}
公共无效句柄(RegisterTenantCommand命令)
{
//在这里处理你的命令
}
}
使用第三方IoC(如Autofac)时自动注册或使用内置IoC手动注册后(此处我将使用内置IoC):

services.AddTransient();
您可以在action、controller或任何其他服务中注入它:

public class TenantController 
{
    public TenantController(ICommandHandler<RegisterTenantCommand> registerTenantHandler)
    {
        ...
    }
}
公共类租户控制器
{
公用租户控制器(ICommandHandler注册器管理员)
{
...
}
}
或行动

public Task<IActionResult> RegisterTenant(
    [FromBody]RegisterTenantCommand command,
    [FromService]ICommandHandler<RegisterTenantCommand> registerTenantHandler
)
{
    registerTenantHandler.Handle(command);
}
公共任务注册表项(
[FromBody]RegisterTenantCommand命令,
[FromService]ICommandHandler注册表项调用器
)
{
寄存器tenanthandler.Handle(命令);
}

当然,您可以将其进一步抽象为只注入一个接口类,该类将解析和处理所有命令,然后调用它
generalCommandHandler.handle(command)
,它的实现将解析和处理它。

默认情况下IHttpContextAccessor服务不再注册。

IHttpContextAccessor可用于访问 当前线程。然而,保持这种状态有着不平凡的意义 性能成本,因此已将其从默认的 服务

依赖它的开发人员可以根据需要重新添加它:
services.AddSingleton()

请参阅以进行讨论


为什么您甚至需要依赖于命令?如果您想使用命令/处理程序模式,那么命令是一条纯消息,没有依赖项,您需要解析处理消息的命令处理程序。我使用CQRS模式,我想从我的多租户应用程序中的url获取db名称。是的,但在CQRS中,命令只是消息,它们没有逻辑。为什么?在我的实现中,我添加了Execute方法,该方法使用db上下文中的实体进行操作。将依赖项注入模型类总是很困难的,您需要将消息与其他内容紧密耦合。在您的案例中,您将其与基础架构耦合(IHttpContextAccessor
非常特定于ASP.NET核心,并且在您的实现中,它会泄漏到您的域/业务逻辑中),这是什么意思?“//您应该将其抽象为一个服务/外观,它隐藏了对HttpContext的依赖性”。什么服务?HttpContext与ASP.NET核心框架紧密耦合。让我们假设数据库的注册和创建是一个非常耗时的操作,那么您可能不希望在ASP.NET内核中运行该操作,尤其是在请求期间。相反,您希望有一个后台任务(即Azure Web作业)来完成它。在Azure Web作业中没有HttpContext,因此您必须从头开始创建处理程序并复制逻辑。根据您在上下文中所做的工作,单元测试可能非常困难(例如,许多依赖项需要模拟),如果参数对命令的执行至关重要,那么是的。或者如果它仅在请求期间可用,并且之后无法查询。如果您可以在以后查询它(即存储在数据库中的客户电子邮件),并且可以使用命令中提供的数据进行查询,则只需将您的服务或DbContext注入处理程序中即可获取数据。我需要根据请求中的信息创建DataContext。因此,我将HttpContext注入CommandHandler,并根据来自客户端的请求信息创建DatabaseContext。这是最好的方法吗?是什么样的数据/参数?数据库/表名?一些标题?json有效负载/模型?安全令牌?
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
    }
}
services.AddTransient<ICommandHandler<RegisterTenantCommand>, RegisterTenantCommandHandler>();
public class TenantController 
{
    public TenantController(ICommandHandler<RegisterTenantCommand> registerTenantHandler)
    {
        ...
    }
}
public Task<IActionResult> RegisterTenant(
    [FromBody]RegisterTenantCommand command,
    [FromService]ICommandHandler<RegisterTenantCommand> registerTenantHandler
)
{
    registerTenantHandler.Handle(command);
}