使服务层可以访问对象,而不在MVC4应用程序中作为参数传递

我正在构建一个多租户MVC应用程序,其中有一个应用程序池和单个数据库。 我有一个租户表,我的每个模型都有一个TenantId标识。

每个租户都有一个字符串“Url”,用于标识用于访问该租户数据的完整URL。

我可以通过以下(粗略近似)从我的BaseController访问它:

HttpRequest request = HttpContext.Current.Request; Uri requestUrl = request.Url; _tenant = _tenantService.GetTenantByUrl(requestUrl); 

现在,我需要将租户传递到服务层以执行业务逻辑。 我可以这样做的一种方法是跨所有服务(约200种方法)查看每个方法并添加一个Tenant参数。 我必须触及每个服务层的调用 ,以及每个服务层方法 。 这样可以工作,但这很繁琐并且使代码混乱。

例如,我以前的一种方法:

  public void DeleteUserById(int userId) { using (var db = CreateContext()) { var user = db.Users.FirstOrDefault(u => u.UserId.Equals(userId)); InternalDeleteUser(db, user); } } 

之后(如果我通过租客):

  public void DeleteUserById(Tenant tenant, int userId) { using (var db = CreateContext()) { var user = tenant.Users.FirstOrDefault(u => u.UserId.Equals(userId)); InternalDeleteUser(db, user); } } 

我想要实现的目标(通过从我的BaseController设置租户,一层):

  public void DeleteUserById(int userId) { using (var db = CreateContext()) { var user = _tenant.Users.FirstOrDefault(u => u.UserId.Equals(userId)); InternalDeleteUser(db, user); } } 

有什么方法可以使用我的BaseService(所有其他服务inheritance自此)或其他模式来从Controller定义租户,并让服务方法捡起它,而不将其作为参数传递给每个? 这样我只需要触摸基本控制器(或者甚至可能是global.asax),而不需要其他任何东西。

简单地说: 如何通过从MVC控制器定义一个对象来访问所有服务,而不将其直接传递给服务?

我想你所说的有关基本服务(参见Layer Supertype )的说法是有道理的。 该基类将依赖于在同一服务层中定义的接口(例如IUserSession,IContext或其他),并且该接口将具有将返回您的租户的方法或属性。

此接口的实现将驻留在您的Web应用程序中,它将执行您所描述的操作,从HttpContext获取数据。

如果您有后台进程,控制台应用程序或任何不在Web上下文中运行的应用程序,您将拥有一个不同的实现,它将根据您需要的任何其他条件创建租户。

总而言之,您将在服务层中拥有:

 abstract class BaseService { protected IContext Context {get; private set;} public BaseService(IContext context) { Context = context; } } public interface IContext { Tenant GetTenant(); } 

然后在您的Web层中,您将拥有:

 public IWebContext : IContext { public Tenant GetTenant() { //your code to return create the tenant based on the url. } } 

希望这可以帮助。

我有同样的“问题”,因为我正在构建一个多租户应用程序。 但是,我解决了这个问题很简单,IMO:每个存储库/服务都定义了一个TenantId属性,必须在使用该服务时进行设置。 TenantId是一个值对象,如果为null则抛出它。

现在,重点是任何repos / services都可以在请求之外使用,例如在后台线程或应用程序中。 我正在使用消息驱动的方法,因此任何所需的信息(如租户ID)都是消息的一部分,因此可供服务的使用者(消息处理程序)使用。 另一个好处是可测试性。

我建议不要将您的服务耦合到特定于请求的对象,如HttpContext,Session或Cache。