C# 使服务层可以访问对象,而无需在MVC4应用程序中作为参数传递
我正在构建一个多租户MVC应用程序,其中有一个应用程序池和一个数据库。我有一个租户表,我的每个模型都有一个已标识的租户 每个租户都有一个字符串“Url”,用于标识用于访问该租户数据的完整Url 我可以从我的BaseController通过以下(粗略近似值)访问此项: 现在,我需要将租户传递到服务层以执行业务逻辑。我可以这样做的一种方法是跨所有服务遍历每个方法(~200个方法),并添加一个租户参数。我必须触摸每个对服务层的调用,以及每个服务层方法。这将是可行的,但它很乏味,并且会混淆代码 例如,我以前的一个方法:C# 使服务层可以访问对象,而无需在MVC4应用程序中作为参数传递,c#,asp.net,asp.net-mvc,asp.net-mvc-4,multi-tenant,C#,Asp.net,Asp.net Mvc,Asp.net Mvc 4,Multi Tenant,我正在构建一个多租户MVC应用程序,其中有一个应用程序池和一个数据库。我有一个租户表,我的每个模型都有一个已标识的租户 每个租户都有一个字符串“Url”,用于标识用于访问该租户数据的完整Url 我可以从我的BaseController通过以下(粗略近似值)访问此项: 现在,我需要将租户传递到服务层以执行业务逻辑。我可以这样做的一种方法是跨所有服务遍历每个方法(~200个方法),并添加一个租户参数。我必须触摸每个对服务层的调用,以及每个服务层方法。这将是可行的,但它很乏味,并且会混淆代码 例如,我
public void DeleteUserById(int userId)
{
using (var db = CreateContext())
{
var user = db.Users.FirstOrDefault(u => u.UserId.Equals(userId));
InternalDeleteUser(db, user);
}
}
之后(如果我通过租户):
我试图实现的目标(通过从我的BaseController设置租户,向上一层):
是否有任何方法可以使用我的BaseService(所有其他服务继承自此)或其他模式从控制器定义租户,并让服务方法拾取租户,而无需将其作为参数传递给每个租户?这样,我只需要触摸基本控制器(甚至可能是global.asax),其他什么都不需要
简单地说:我如何通过从MVC控制器定义对象而不直接将其传递给服务,从而使所有服务都可以访问该对象?我也有同样的“问题”,因为我正在构建一个多租户应用程序。然而,我很简单地解决了这个问题,IMO:每个存储库/服务都定义了一个TenantId属性,在使用该服务时必须设置该属性。TenantId是一个值对象,如果为null,它将抛出 现在,关键是任何repos/服务都可以在请求之外使用,例如在后台线程或应用程序中。我使用的是消息驱动的方法,因此任何必需的信息(如租户id)都是消息的一部分,因此可供服务的使用者(消息处理程序)使用。另一个好处是可测试性
我建议不要将您的服务与特定于请求的对象(如HttpContext、Session或Cache)耦合。我想您所说的基本服务(请参阅)是有道理的。该基类将依赖于在同一服务层中定义的接口(例如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.
}
}
希望这有帮助。您是否执行某种用户身份验证?我会发现将租户与当前用户关联是很自然的。有关如何将自定义字段添加到当前标识/主体对象的说明,请参阅。然后您可以从服务层代码访问TenantId,如下所示:
((MyCustomPrincipal)HttpContext.Current.User)。TenantId
@EiríkurFannarTorfason我已经设置了自定义成员身份,并且用户当前与租户配对,但是并非所有查询都涉及用户,因此我认为这种方法不起作用。嗯,始终存在会话
对象。@EiríkurFannarTorfason我现在正在玩会话-'Session.Add(“租户”,“测试”);'从我的Global.asax.cs——虽然我不知道如何在不通过HttpContext(yikes)的情况下从我的服务层访问它。想法?HttpContext.Current.Session[“租户”]
应该可以。谢谢迈克。我还在BaseService上实现了TenantId属性。您如何从(比如)您的管制员处获得租户?由于租户应该由URL确定,您会在BaseController中提取它吗?我在httpmodule中提取租户id,然后将其缓存在HttpContext.Items中。然后是一个扩展方法,使它更容易访问。真棒-看起来我还有更多的学习要做:)。谢谢你的帮助
public void DeleteUserById(int userId)
{
using (var db = CreateContext())
{
var user = _tenant.Users.FirstOrDefault(u => u.UserId.Equals(userId));
InternalDeleteUser(db, user);
}
}
abstract class BaseService
{
protected IContext Context {get; private set;}
public BaseService(IContext context)
{
Context = context;
}
}
public interface IContext
{
Tenant GetTenant();
}
public IWebContext : IContext
{
public Tenant GetTenant()
{
//your code to return create the tenant based on the url.
}
}