Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使服务层可以访问对象,而无需在MVC4应用程序中作为参数传递_C#_Asp.net_Asp.net Mvc_Asp.net Mvc 4_Multi Tenant - Fatal编程技术网

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

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个方法),并添加一个租户参数。我必须触摸每个对服务层的调用,以及每个服务层方法。这将是可行的,但它很乏味,并且会混淆代码 例如,我

我正在构建一个多租户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.
    }
}