如何将 Owin 上下文传递给注入到 API 控制器中的存储库

本文关键字:控制器 API 存储 注入 Owin 上下文 | 更新日期: 2023-09-27 18:35:43

我有一个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是空的

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

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

如何将 Owin 上下文传递给注入到 API 控制器中的存储库

让我们抛开你为什么有这个设计,专注于这个问题: 注入IOwinContext

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

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

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

CurrentRequestCurrentRequestHandler可以从安德鲁·戴维的回答中使用,因为它是:

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 方法,如下所述: ASP.NET Web API 2 中的依赖项注入

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

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

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

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

然后将"启动"中的代码更改为以下内容:

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

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

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