如何通过依赖注入传递Web API请求?

Mic*_*tum 10 .net c# asp.net async-await asp.net-web-api

我有一个Web API应用程序,其中控制器通过依赖注入(Unity)将服务/存储库等注入其中.让我们假设我IStuffService需要IPrincipal当前请求(或它周围的包装).

Web API的问题似乎是当前Request/User 的唯一可靠来源是Request实例上的属性ApiController.任何静态的(无论是HttpContext.Current,CallContext.Get/SetDataThread.Get/SetData)不能保证是相同的线程上,由于网络API的同步性质.

如何可靠地确保特定于请求的上下文通过依赖项传递,更重要的是,操作在整个操作过程中保持正确IPrincipal

两种选择:

  1. 每个需要的方法IPrincipal都将它作为方法的参数 - 这是最可靠的方法,但它也要求我在每个方法签名中都有这个东西
  2. 将IPrincipal注入服务的ctor,使用Unity中的DependencyOverride在每个请求上激活对象图的新内容: container.Resolve(opType, new DependencyOverride(typeof(IPrincipal), principal))

选项2意味着我的方法签名是干净的,但这也意味着我需要确保所有依赖项都使用TransientLifetimeManager,而不是Singleton甚至是Per-Thread.

有没有比我没有看到更好的解决方案?

Kha*_* TO -1

如何可靠地确保特定于请求的上下文通过依赖项传递,更重要的是,操作在整个操作过程中始终保留正确的 IPrincipal?

我认为你不应该这样做。您的服务比您的 Api 控制器低一层。你的服务不应该依赖于任何与更高层相关的类,否则你的服务无法被重用,例如:当你需要在现有服务之上构建一个win forms应用程序时。

IPrincipal不适合注入到我们的服务中,因为它与 Web 应用程序相关。当我们将此信息传递到较低层(服务)时,我们应该传递中性类或只是一个userId,以将我们的服务与使用它的应用程序解耦。

您应该为用户和任何与请求相关的内容定义自己的类,以在我们的服务层中使用,因为它与域相关。这样,您的服务层就与应用程序层(Web、Win 表单、控制台……)无关了:

public class AppPrincipal : IAppPrincipal
{
   public int UserId { get; set; }
   public string Role { get; set; }
   //other properties
   public AppPrincipal() {

   }
   public AppPrincipal(int userId, string role):this() {
       UserId  = userId;
       Role = role;
   }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以IAppPrincipal在 Web 应用程序中注册为每个请求范围,并使用您的IPrincipal. 在任何调用之前,它将初始化IAppPrincipal整个对象图await/async。Unity 的示例代码:

public void RegisterTypes(IUnityContainer container)
{
    container.RegisterType<IAppPrincipal>(
                new PerRequestLifetimeManager(),
                new InjectionFactory(c => CreateAppPrincipal()));
}
public IAppPrincipal CreateAppPrincipal()
{
    var principal = new AppPrincipal();
    principal.UserId = //Retrieve userId from your IPrincipal (HttpContext.Current.User)
    principal.Role = //Retrieve role from your IPrincipal (HttpContext.Current.User)
    return principal;
}
Run Code Online (Sandbox Code Playgroud)

这里的关键是我们已经将服务层与网络分离。如果您需要重用服务层来构建 Windows 窗体或控制台应用程序,您可以注册IAppPrincipal为单例并以不同的方式填充它。

我们不需要处理与平台相关的问题,例如async/await


归档时间:

查看次数:

2218 次

最近记录:

7 年,11 月 前