简体   繁体   English

在Autofac和WebAPI 2 Owin中的服务解析期间获取User.Identity

[英]Getting the User.Identity during service Resolution in Autofac and WebAPI 2 Owin

What I', trying to do is have a UserContext instantiated (single instance per user ideally). 我要做的是实例化一个UserContext (理想情况下每个用户一个实例)。 The UserContext depends on the current logged-in user. UserContext取决于当前登录的用户。

MyUser is created by calling GlobalContext.User(username) 通过调用GlobalContext.User(username)创建MyUser

The following snippet is called from my Startup.Configuration(IAppBuilder app) : 从我的Startup.Configuration(IAppBuilder app)调用以下代码段:

private static IContainer RegisterServices()
{
    var builder = new ContainerBuilder();
    builder.RegisterApiControllers(System.Reflection.Assembly.GetAssembly(typeof(MyWeb.API.Startup)));
    builder.RegisterType<GlobalContext>().As<IGlobalContext>().SingleInstance();
    builder.Register(c => c.Resolve<IGlobalContext>().User(
        HttpContext.Current.User.Identity.Name)
        ).As<MyUser>();
    builder.RegisterType<UserContext>().As<IUserContext>().InstancePerLifetimeScope();
    return builder.Build();
}

Everything seems to work fine when ran in IIS Express. 在IIS Express中运行时,一切似乎工作正常。 When I run this in an integration test using the Owin WebApp.Start<Startup>(url: BaseAddress) HttpContext.Current is null. 当我使用Owin WebApp.Start<Startup>(url: BaseAddress)在集成测试中运行此代码时, WebApp.Start<Startup>(url: BaseAddress) HttpContext.Current为null。 This is expected from all the reading that I've done so far, but what's the alternative? 到目前为止,我已经完成了所有阅读,这是可以预期的,但是还有什么选择呢?

I think I need to access the owinContext or the autofac lifetime scope to get the current user during resolution, but how do I do that? 我认为我需要访问owinContext或autofac生存期范围才能在解析期间获取当前用户,但是我该怎么做?

Is there a better way to do this? 有一个更好的方法吗? or am I missing something trivial? 还是我缺少一些琐碎的东西?

All help is appreciated. 感谢所有帮助。

EDITED TO ADD INFO: In case it helps I'm including my Configuration() method here: 编辑以添加信息:如果有帮助,请在此处包括我的Configuration()方法:

using System.Web;
using System.Web.Http;
using Autofac;
using Autofac.Integration.WebApi;
using Owin;
using System.Reflection;

namespace SomeNameSpace
{

 public partial class Startup
    {

    public void Configuration(IAppBuilder app)
    {
        var configuration = new HttpConfiguration{ IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always };

        WebApiConfig.Register(configuration);
        BreezeConfig.Register(configuration);
        CorsConfig.Register(configuration);

        // Autofac IoC
        var container = RegisterServices();
        app.UseAutofacMiddleware(container);

        app.UseWindowsAuthentication();

        var urt = new UserRolesTranformer(new GlobalContext());
        app.UseClaimsTranformation(urt.Transformation);

        app.UseAutofacWebApi(configuration);
        configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);

        //app.Use(typeof(TestMiddleware));
        app.UseAutofacWebApi(configuration);
        app.UseWebApi(configuration);
    }
}

Ultimate Goal: create a test that simulates multiple concurrent users logging in and ensuring that each user get's their own UserContext instance. 最终目标:创建一个测试,以模拟多个并发用户登录并确保每个用户都拥有自己的UserContext实例。

In the case of a Unit Test, you shouldn't really need access to the HttpContext or the OwinContext. 在单元测试的情况下,您实际上不需要访问HttpContext或OwinContext。 As I imagine you have already discovered, a Unit Test has no concept of a HttpContext. 就像您已经发现的那样,单元测试没有HttpContext的概念。

I am assuming that your IGlobalContext has a method User which takes a Username and returns you a User, perhaps from your database based on the Username passed in from the Current Context? 我假设您的IGlobalContext有一个User方法,该方法采用一个Username并向您返回一个User,也许是基于从当前上下文传入的Username从数据库中返回的?

What you should do is have different Autofac registrations for your website and for your unit test so that you can have different dependencies in each environment. 您应该做的是为您的网站和单元测试使用不同的Autofac注册,以便在每个环境中都可以具有不同的依赖关系。 Then in your Unit Tests Autofac registration you could register either a completely different dependency to be resolved in your Unit Test, or you could pass into your User method, a mocked username that you know exists. 然后,在单元测试Autofac注册中,您可以注册一个完全不同的依赖关系,以在单元测试中解决,或者可以将您知道的模拟用户名传递给User方法。

So you would keep this as your Autofac Registrations in your Website. 因此,您将其保留为您网站上的Autofac注册。

private static IContainer RegisterServices()
{
    var builder = new ContainerBuilder();
    builder.RegisterApiControllers(System.Reflection.Assembly.GetAssembly(typeof(MyWeb.API.Startup)));
    builder.RegisterType<GlobalContext>().As<IGlobalContext>().SingleInstance();
    builder.Register(c => c.Resolve<IGlobalContext>().User(
        HttpContext.Current.User.Identity.Name)
        ).As<MyUser>();
    builder.RegisterType<UserContext>().As<IUserContext>().InstancePerLifetimeScope();
    return builder.Build();
}

Then in your Unit Test, when you register your Autofac registrations with something like this.. 然后在您的单元测试中,当您使用以下内容注册Autofac注册时。

private static IContainer RegisterServices()
{
    var builder = new ContainerBuilder();
    builder.RegisterApiControllers(System.Reflection.Assembly.GetAssembly(typeof(MyWeb.API.Startup)));
    builder.RegisterType<GlobalContext>().As<IGlobalContext>().SingleInstance();
    builder.Register(c => c.Resolve<IGlobalContext>().User(
        "MyTestUser")
        ).As<MyUser>();
    builder.RegisterType<UserContext>().As<IUserContext>().InstancePerLifetimeScope();
    return builder.Build();
}

This way you know in your Unit Test, exactly what User you are passing in and what User you should be getting back. 这样,您就可以在单元测试中确切知道要传递的用户和应该返回的用户。

Or by using your own entirely mocked user like this ... 或者使用您自己的完全嘲笑的用户,像这样...

public class TestUser : MyUser
{
    //Known Test Scenario Properties and Methods as required
}

private static IContainer RegisterServices()
{
    var builder = new ContainerBuilder();
    builder.RegisterApiControllers(System.Reflection.Assembly.GetAssembly(typeof(MyWeb.API.Startup)));
    builder.RegisterType<GlobalContext>().As<IGlobalContext>().SingleInstance();
    builder.RegisterType<TestUser>().As<MyUser>();
    builder.RegisterType<UserContext>().As<IUserContext>().InstancePerLifetimeScope();
    return builder.Build();
}

I hope this helps? 我希望这有帮助?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM