【问题标题】:How to pass Owin context to a Repo being injected into Api controller如何将 Owin 上下文传递给被注入 Api 控制器的 Repo
【发布时间】:2015-02-27 16:02:32
【问题描述】:

我有一个 MVC WebApi owin(软托管)项目,它使用 Unity 解决控制器依赖关系

看起来像这样

public class PacientaiController : ODataController
    {
        private readonly IEntityRepo<Ent.Pacientas> repo;

        public PacientaiController(IEntityRepo<Ent.Pacientas> repo)
        {
            this.repo = repo;
        }

我要解决的问题是如何将“OwinContex”传递给 Repo。

public class PacientasEntityRepo:IEntityRepo<Pacientas>,IDisposable
    {
        public PacientasEntityRepo(IOwinContext ctx)
        {
        .........

如果我尝试像这样在Startup.cs 中注册它

Container.RegisterType<IOwinContext>(new InjectionFactory(o => HttpContext.Current.GetOwinContext()));

我得到一个空引用,说HttpContext.Current 是空的

这里的主要思想是将当前经过身份验证的用户传递给存储库,因为存储库托管了用于查询数据库的逻辑,具体取决于用户。 (假设用户是管理员,则返回此数据,如果用户是访客 - 返回此数据)

关键是 - 这是一个自我主机!

【问题讨论】:

  • 忽略我的回答,我没有阅读 self-hosted 部分
  • 我不能是唯一一个读到这篇文章并认为有异味的人,特别是关于需要访问 OWIN 上下文的 Repo?是的,它可能需要根据当前用户做出一些决定,但肯定会获取该信息并仅公开 IPrincipal 或类似于 repo 的内容会更有意义吗?
  • 是的,它可能会。无论如何它不会影响问题,因为我仍然需要访问 OwinContext 或 RequestContext,取出当前主体,并将其交给 IoC 以注入正在构建的依赖项。不管是 IOwinContext 还是 IPrinciple 还是 IUserRole。它仍然存在于“RequestsContext”中。问题是关于这种或类似情况下的沟通原则。

标签: c# unity-container asp.net-web-api2 owin


【解决方案1】:

让我们抛开为什么会有这种设计并专注于问题:注入IOwinContext

您也可以使用GetOwinContext 方法从HttpRequestMessage 实例中获取它,但是您还需要以某种方式获取HttpRequestMessage

Unity 不支持开箱即用的HttpRequestMessage 注入,但您可以使用自定义DelegatingHandler 将当前HttpRequestMessage 存储在容器中,如下所述:Inject WebAPI UrlHelper into service using Autofac

链接的问题是关于 Autofac 但您可以将其转移到 Unity 中工作:

CurrentRequestCurrentRequestHandler 可以直接从Andrew Davey 的回答中使用:

public class CurrentRequest
{
    public HttpRequestMessage Value { get; set; }
}

public class CurrentRequestHandler : DelegatingHandler
{
    protected async override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        var scope = request.GetDependencyScope();
        var currentRequest = (CurrentRequest)scope.GetService(typeof(CurrentRequest));
        currentRequest.Value = request;
        return await base.SendAsync(request, cancellationToken);
    }
}

那么你只需要将DelegatingHandler注册到:

httpConfiguration.MessageHandlers.Insert(0, new CurrentRequestHandler());

并在容器中注册CurrentRequestIOwinContext

container.RegisterType<CurrentRequest>(
            new HierarchicalLifetimeManager());

container.RegisterType<IOwinContext>(
    new HierarchicalLifetimeManager(),
    new InjectionFactory(c => c.Resolve<CurrentRequest>().Value.GetOwinContext()));

httpConfiguration.DependencyResolver = new UnityHierarchicalDependencyResolver(container);

除了自定义委托处理程序之外,还有其他地方可以连接到 Web.API 以捕获HttpRequestMessage,例如,您可以创建自己的IHttpControllerActivator 并使用ExecuteAsync 方法,如下所述:Dependency Injection in ASP.NET Web API 2

【讨论】:

  • 感谢您发布这个干净的解决方案。
【解决方案2】:

在自托管应用程序中,您没有 HttpContext。您需要另一种方式来移动状态。一种选择是使用自行实现的 HttpContext,例如:

https://github.com/danielcrenna/graveyard/tree/master/httpcontext-shim

【讨论】:

  • 我知道没有HttpContext。因此问题。但是 - 每个请求和每个控制器、动作等中都存在“OwinContext”。问题是在构建依赖项时得到它!
  • 您可以使用构造函数注入来传递上下文。将 owincontext 作为构造函数参数注入到您的逻辑层中。
【解决方案3】:

我认为问题在于调用 Startup 时 HttpContext 不存在,所以您可能需要的是有一个 Func 代替,如下所示:

public class PacientasEntityRepo:IEntityRepo<Pacientas>,IDisposable
{
    public PacientasEntityRepo(Func<IOwinContext> ctx)
    {
    .........

然后将 Startup 中的代码更改为:

Container.RegisterType<IOwinContext>(new InjectionFactory(() => HttpContext.Current.GetOwinContext()));

【讨论】:

  • 在自托管应用程序中,您没有HttpContext,因为您甚至没有引用System.Web,所以HttpContext.Current.GetOwinContext() 无法编译!仅当 Web.Api 托管在 IIS 中但 OP 明确要求自托管方案时,您的答案才可用。
  • 好吧,OP 说 HttpContext 是空的,所以我猜他有对 System.Web 的引用,所以我在问这个问题
  • 是的,也许 OP 具​​有 HttpContext 类型,但它肯定会在自托管模式下始终为 Null,如peerJcl 已删除的答案中所述away 提出了一个与你非常相似的解决方案。
【解决方案4】:

在我的 Asp.Net Mvc (AutoFac) 项目(非核心)中,我使用了以下注册并且成功

builder.RegisterType<OwinContext>().AsImplementedInterfaces().InstancePerRequest();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多