Asp.net core 如何直接从ConfigureServices方法注入HttpContextAccessor

Asp.net core 如何直接从ConfigureServices方法注入HttpContextAccessor,asp.net-core,dependency-injection,Asp.net Core,Dependency Injection,我的目标是根据我将要处理的环境设置用户名字符串,该字符串必须是: 开发和登台环境的任意字符串 生产中的HttpContext.User.Identity.Name。 这是因为我必须能够模拟不同类型的用户,我通过使用此用户名字符串作为参数在自定义的UserIdentity实现上调用FindByIdAsync方法来实现这一点,如下所示: public class HomeController : Controller { UserManager<AppUser> userMana

我的目标是根据我将要处理的环境设置用户名字符串,该字符串必须是:

开发和登台环境的任意字符串 生产中的HttpContext.User.Identity.Name。 这是因为我必须能够模拟不同类型的用户,我通过使用此用户名字符串作为参数在自定义的UserIdentity实现上调用FindByIdAsync方法来实现这一点,如下所示:

public class HomeController : Controller
{
    UserManager<AppUser> userManager;
    AppUser connectedUser;

    public HomeController(UserManager<AppUser> usrMgr, IContextUser ctxUser)
    {
        connectedUser = usrMgr.FindByNameAsync(ctxUser.ContextUserId).Result;
    }
}
而生产环境配置文件没有此密钥

我创建了一个简单的界面

public interface IContextUser
{
    public string ContextUserId { get; }
}
及其实施:

public class ContextUser : IContextUser
{
    string contextUser;
    IHttpContextAccessor contextAccessor;

    public ContextUser(IHttpContextAccessor ctxAccessor, string ctxUser = null)
    {
        contextUser = ctxUser;
        contextAccessor = ctxAccessor;
    }

    public string ContextUserId => contextUser ?? contextAccessor.HttpContext.User.Identity.Name;
}
现在,我只想在Startup类中配置ConfigureServices方法:

但它需要一个IHttpContextAccessor对象,该对象在应用程序的这个阶段似乎不可用。如何解决此问题?

HttpContextAccessor在封面下使用静态AsyncLocal属性,这意味着任何HttpContextAccessor实现都将访问相同的数据。这意味着您可以简单地执行以下操作:

services.AddSingletonc=>newcontexternewhttpcontextaccessor,ctxUser; //别忘了叫这个;否则,HttpContext属性将被删除 //生产时为空。 services.AddHttpContextAccessor; 如果您发现这一点过于含蓄,或者HttpContextAccessor实现不会在将来中断,您还可以执行以下操作:

var访问器=新的HttpContextAccessor; services.addSingleton访问器; services.AddSingletonc=>新上下文Accessor,ctxUser; 或者,您可以从ServiceCollection类中取出已注册的实例:

services.AddHttpContextAccessor; var accessor=IHttpContextAccessorservices.Last s=>s.ServiceType==TypeOfHittpContextAccessor.ImplementationInstance; services.AddSingletonc=>新上下文Accessor,ctxUser; 然而,我发现一个更令人愉快的解决方案,特别是从设计的角度来看,就是拆分ContextUser类;它目前似乎实施了两种不同的解决方案。您可以拆分这些:

公共密封类HttpContextUser:IContextser { 专用只读IHttpContextAccessor访问器; 公共HttpContextSerieHttpContextAccessor访问器=> this.accessor=accessor??抛出新参数NullExceptionAccessor; 公共字符串contextSerID=>this.accessor.HttpContext.User.Identity.Name; } 公共密封类FixedContextUser:IContextUser { public FixedContextSerString用户ID=> this.contextSerid=userId??抛出新的ArgumentNullExceptionuserId; 公共字符串上下文ID{get;} } 现在,根据您运行的环境,您可以注册其中一个:

公共无效配置服务服务服务收集服务 { services.AddHttpContextAccessor; 如果这是.Configuration.IsProduction { services.AddSingleton; } 其他的 { 字符串ctxUser=Configuration[数据:ConnectedUser]; services.addSingleTonew FixedContextUserctxUser; } } HttpContextAccessor在封面下使用静态AsyncLocal属性,这意味着任何HttpContextAccessor实现都将访问相同的数据。这意味着您可以简单地执行以下操作:

services.AddSingletonc=>newcontexternewhttpcontextaccessor,ctxUser; //别忘了叫这个;否则,HttpContext属性将被删除 //生产时为空。 services.AddHttpContextAccessor; 如果您发现这一点过于含蓄,或者HttpContextAccessor实现不会在将来中断,您还可以执行以下操作:

var访问器=新的HttpContextAccessor; services.addSingleton访问器; services.AddSingletonc=>新上下文Accessor,ctxUser; 或者,您可以从ServiceCollection类中取出已注册的实例:

services.AddHttpContextAccessor; var accessor=IHttpContextAccessorservices.Last s=>s.ServiceType==TypeOfHittpContextAccessor.ImplementationInstance; services.AddSingletonc=>新上下文Accessor,ctxUser; 然而,我发现一个更令人愉快的解决方案,特别是从设计的角度来看,就是拆分ContextUser类;它目前似乎实施了两种不同的解决方案。您可以拆分这些:

公共密封类HttpContextUser:IContextser { 专用只读IHttpContextAccessor访问器; 公共HttpContextSerieHttpContextAccessor访问器=> this.accessor=accessor??抛出新参数NullExceptionAccessor; 公共字符串contextSerID=>this.accessor.HttpContext.User.Identity.Name; } 公共密封类FixedContextUser:IContextUser { public FixedContextSerString用户ID=> this.contextSerid=userId??抛出新的ArgumentNullExceptionuserId; 公共字符串上下文ID{get;} } 现在,根据您运行的环境,您可以注册其中一个:

公共无效配置服务服务服务收集服务 { services.AddHttpContextAccessor; 如果这是.Configuration.IsProduction { services.AddSingleton; } 其他的 { 字符串ctxUser=Configuration[数据:ConnectedUser]; services.addSingleTonew FixedContextUserctxUser; } }
我非常喜欢您分割ContextUser类的替代解决方案,我就是这么做的。谢谢。我非常喜欢你的拆分ContextUser类的替代解决方案,我就是这么做的。谢谢
public class ContextUser : IContextUser
{
    string contextUser;
    IHttpContextAccessor contextAccessor;

    public ContextUser(IHttpContextAccessor ctxAccessor, string ctxUser = null)
    {
        contextUser = ctxUser;
        contextAccessor = ctxAccessor;
    }

    public string ContextUserId => contextUser ?? contextAccessor.HttpContext.User.Identity.Name;
}
public void ConfigureServices(IServiceCollection services)
{
    // --- add other services --- //

    string ctxUser = Configuration["Data:ConnectedUser"];
    services.AddSingleton(service => new ContextUser( ??? , ctxUser ));

}