将 IHttpContextAcessor 注入控制器操作中的绑定模型
Injecting IHttpContextAcessor into a Binding Model inside an Controller Action
我有一个控制器操作方法:
public void Register([FromBody]RegisterTenantCommand message)
{
...
}
我有 class RegisterTenantCommand 和 constructor:
public class RegisterTenantCommand
{
public RegisterTenantCommand(IHttpContextAccessor httpContextAccessor)
: base(httpContextAccessor) { }
}
但是当我启动我的应用程序并执行此操作时,我有 httpContextAccessor = null。
我该如何解决?
您似乎将命令与来自 UI 框架的命令混淆了(例如 ICommand
接口的 WPF+MVVM 实现)。
当前的实现也有点违反 SRP 原则,class 应该只负责一件事。您基本上是在处理输入(将其绑定到用户值)并执行它以及处理其中的执行逻辑。
Command/Handler 或 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 关系,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 这样的第 3 方 IoC 自动注册或使用内置 IoC 手动注册(这里我将使用内置):
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);
}
当然你可以进一步抽象它只注入一个接口class,它将解析和处理所有命令,然后调用它generalCommandHandler.Handle(command)
,它的实现将解析和处理它。
默认情况下未注册 IHttpContextAccessor 服务(不再)
IHttpContextAccessor can be used to access the HttpContext for the
current thread. However, maintaining this state has non-trivial
performance costs so it has been removed from the default set of
services.
Developers that depend on it can add it back as needed:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
See aspnet/Hosting#793 for discussion.
我有一个控制器操作方法:
public void Register([FromBody]RegisterTenantCommand message)
{
...
}
我有 class RegisterTenantCommand 和 constructor:
public class RegisterTenantCommand
{
public RegisterTenantCommand(IHttpContextAccessor httpContextAccessor)
: base(httpContextAccessor) { }
}
但是当我启动我的应用程序并执行此操作时,我有 httpContextAccessor = null。
我该如何解决?
您似乎将命令与来自 UI 框架的命令混淆了(例如 ICommand
接口的 WPF+MVVM 实现)。
当前的实现也有点违反 SRP 原则,class 应该只负责一件事。您基本上是在处理输入(将其绑定到用户值)并执行它以及处理其中的执行逻辑。
Command/Handler 或 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 关系,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 这样的第 3 方 IoC 自动注册或使用内置 IoC 手动注册(这里我将使用内置):
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);
}
当然你可以进一步抽象它只注入一个接口class,它将解析和处理所有命令,然后调用它generalCommandHandler.Handle(command)
,它的实现将解析和处理它。
默认情况下未注册 IHttpContextAccessor 服务(不再)
IHttpContextAccessor can be used to access the HttpContext for the current thread. However, maintaining this state has non-trivial performance costs so it has been removed from the default set of services.
Developers that depend on it can add it back as needed:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
See aspnet/Hosting#793 for discussion.