在 NancyContext 中找不到 OwinContext

Can't find OwinContext in NancyContext

我有一个使用 Nancy 的自托管 Owin 应用程序。在其中一个 NancyModules 中,我需要获取 IOwinContext.

的实例

这个问题涉及主题,但没有解决方案:Get current owin context in self host mode

它说对于 Nancy,您必须使用 NancyContext 获取 Items 字典并查找与键 "OWIN_REQUEST_ENVIRONMENT" 对应的值。

我可以访问 NancyContext,我可以看到 Items 字典,它包含一个名为 "OWIN_REQUEST_ENVIRONMENT" 的键。 (我也可以调用 NancyContext.GetOwinEnvironment() 扩展,它给出相同的结果 但是,当我获得该密钥时,它不包含实际的 IOwinContext。

里面包含了很多关于欧文信息的keys(部分keys是owin.RequestPath,owin.RequestMethodowin.CallCancelled 等),但不是实际的上下文对象。而且它实际上只是一个具有各种键的字典,所以我也不能将它转换为 IOwinContext。

如何从 NancyContext 获取 IOwinContext 对象?


public class MyStartup
{
    public void Start()
    {
        var options = new StartOptions()
        options.Urls.Add(new Uri("http://*:8084"));
        options.AppStartup(this.GetType().AssemblyQualifiedName;
        var host = WebApp.Start(options, Configuration);
    }

    public void Configuration(IAppBuilder app)
    {
        app.UseNancy();
    }
}

public class MyModule : NancyModule
{
    Get["/", true] = async(x, ct) =>
    {
        var owinEnvironment = Context.GetOwinEnvironment();
        // Now what?
    }
}

实际上,问题 you mentioned 有一些您可能错过的提示。

For Nancy, you have to use NancyContext to get to the Items dictionary and look for the value corresponding to the key "OWIN_REQUEST_ENVIRONMENT". For SignalR, Environment property of IRequest gives you access to OWIN environment. Once you have the OWIN environment, you can create a new OwinContext using the environment.

因此,一旦您调用 var owinEnvironment = Context.GetOwinEnvironment() 并获得字典,您就可以创建 OwinContext(它只是这些字典值的包装器)

它有一个构造函数 OwinContext(IDictionary<String, Object>),我想这就是您所需要的。

此外,您可以从 HttpContext:

得到 OwinContext
// get owin context
var owinContext = HttpContext.Current.GetOwinContext();
// get user manager
var userManager = owinContext.GetUserManager<YourUserManager>();

我最终通过创建新的 Owin 中间件解决了这个问题。在中间件中,您可以访问当前的 Owin 上下文,这使您可以访问 Owin 环境。

当您有权访问 Owin 环境时,只需将 Owin 上下文添加到环境中即可。当上下文在环境中时,您可以在 NancyModule 中检索它。

像这样检索它之后,我还可以访问上下文中的 GetUserManager() 方法,这样我就可以获得我的 AspNetIdentity 管理器(正如我在对另一个答案的评论中提到的)。请记住,中间件必须在 Nancy 之前添加到 Owin 管道。

启动

public class Startup
{
    public void Start()
    {
        var options = new StartOptions()
        options.Urls.Add(new Uri("http://*:8084"));
        options.AppStartup(this.GetType().AssemblyQualifiedName;
        var host = WebApp.Start(options, Configuration);
    }

    public void Configuration(IAppBuilder app)
    {
        app.Use(typeof(OwinContextMiddleware));
        app.UseNancy();
    }
}

中间件

public class OwinContextMiddleware : OwinMiddleware
{
    public OwinContextMiddleware(OwinMiddleware next)
        : base(next)
    {
    }

    public async override Task Invoke(IOwinContext context)
    {
        context.Environment.Add("Context", context);
        await Next.Invoke(context);
    }
}

NancyModule

public class MyModule : NancyModule
{
    public MyModule()
    {
        Get["/", true] = async(x, ct) =>
        {
            IDictionary<string, object> environment = Context.GetOwinEnvironment();
            IOwinContext context = (IOwinContext)environment["Context"]; // The same "Context" as added in the Middleware
        }
    }

警告

上面列出的中间件未经测试,因为我拥有的中间件更复杂,而且我没有时间创建工作示例。我找到了关于如何创建 Owin 中间件的简单概述 on this page

var owinContext = new OwinContext(Context.GetOwinEnvironment());

示例:

public class SecurityApi : NancyModule
{
    public SecurityApi()
    {
        Post["api/admin/register", true] = async (_, ct) =>
        {
            var body = this.Bind<RegisterUserBody>();

            var owinContext = new OwinContext(Context.GetOwinEnvironment());
            var userManager = owinContext.GetUserManager<ApplicationUserManager>();

            var user = new User {Id = Guid.NewGuid().ToString(), UserName = body.UserName, Email = body.Email};

            var result = await userManager.CreateAsync(user, body.Password);

            if (!result.Succeeded)
            {
                return this.BadRequest(string.Join(Environment.NewLine, result.Errors));
            }

            return HttpStatusCode.OK;
        };

    }
}