如何将Owin上下文传递给注入Api控制器的Repo

时间:2014-12-31 15:44:05

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

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

看起来像这样

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

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

我正在努力解决的问题 - 我如何将'OwinContex'传递给回购。

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

如果我尝试在Startup.cs

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

我得到一个空引用,说HttpContext.Current为NULL

这里的主要思想是将当前经过身份验证的用户传递给repo,因为Repo托管逻辑以查询数据库,具体取决于用户。 (如果用户是Admin,则返回此数据,如果用户是guest虚拟机,则返回此数据)

重点是 - 这是一个自我主持人!

4 个答案:

答案 0 :(得分:25)

让我们放下为什么你有这个设计并专注于这个问题:注入IOwinContext

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

Unity不支持开箱即用注入HttpRequestMessage,但您可以使用自定义DelegatingHandler将当前HttpRequestMessage存储在容器中,如下所述:{{3} }

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

CurrentRequestCurrentRequestHandler可以在Inject WebAPI UrlHelper into service using Autofac的答案中使用:

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方法:Andrew Davey

答案 1 :(得分:2)

在自托管应用程序中,您没有HttpContext。你还需要另一种方法来改变状态。一个选项是使用自我实现的HttpContext,如:

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

答案 2 :(得分:1)

我认为问题是在调用Startup时HttpContext不存在,所以你可能需要的是改为使用Func,如下所示:

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

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

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

答案 3 :(得分:0)

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

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