如何在ASP.NET 5中动态创建和注入服务

本文关键字:创建 动态 注入 服务 ASP NET | 更新日期: 2023-09-27 18:22:18

vnext的DI容器的经典功能不足以为我提供正确的功能。假设我有一个DataService,它从这样的数据库中获取数据:

public class DataService : IDataService, IDisposable {
  public List<MyObject> GetMyObjects() 
  {
    // do something to fetch the data...
    return myObjects;
  }
}

然后,我可以在Startup.cs:中的配置阶段将此服务注册到DI容器中

public void ConfigureServices(IServiceCollection services) 
{
  services.AddScoped(typeof(IDataService), typeof(DataService));
}

这确保了服务的正确生命周期(每个请求范围一个),但是,当发出不同的请求时,我需要服务访问不同的数据库。为了简单起见,假设以下场景适用:

  • 当向我的Web API发出请求时,DataService将访问当前登录的用户,其中包含一个名为Database的声明,其中包含要使用哪个数据库的信息
  • 则CCD_ 4被实例化为具有正确的数据库连接

为了让第二步开始工作,我为DataService创建了一个构造函数,如下所示:

public DataService(IHttpContextAccessor accessor) 
{
   // get the information from HttpContext
   var currentUser = accessor.HttpContext.User;
   var databaseClaim = currentUser.Claims.SingleOrDefault(c => c.Type.Equals("Database"));
   if (databaseClaim != null) 
   {
      var databaseId = databaseClaim.Value;
      // and use this information to create the correct database connection
      this.database = new Database(databaseId);
   }
}

通过使用当前登录的用户及其声明,我可以确保我自己的身份验证中间件负责提供必要的信息,以防止攻击者试图访问错误的数据库。

当然,添加IDisposable实现是清理任何数据库连接所必需的(并使用作用域生命周期正确调用)。

然后我可以将DataService注入像这样的控制器中

public MyController : Controller 
{
   private IDataService dataService;
   public MyController(IDataService dataService) 
   {
     this.dataService = dataService;
   }
}

到目前为止一切都很好。我现在的问题是:

  1. 除了使用DataService的构造函数之外,还有其他方法可以创建实例吗?也许在不同的地方访问IServiceCollection提供的对象,而不是在只运行一次的配置阶段?也许使用我自己的OWIN中间件
  2. 这种方法真的安全吗?同时发出的两个请求是否会意外地得到另一个请求的DataService,从而给出错误的数据

如何在ASP.NET 5中动态创建和注入服务

您所拥有的一切都很好。

除了使用DataService的构造函数之外,还有其他方法可以创建实例吗?也许在不同的地方访问IServiceCollection提供的对象,而不是在只运行一次的配置阶段?也许使用我自己的OWIN中间件?

不是。您可以使用代理注册,但这是相同的问题。

这种方法真的安全吗?

同时发出的两个请求是否会意外地得到用于另一个请求的DataService,从而给出错误的数据?

没有。IHttpContextAcessor使用AsyncLocal(http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html)以提供对"当前"http上下文的访问。