处理MVC上的多租户

时间:2012-04-17 14:29:11

标签: asp.net-mvc-3 multi-tenant

我想问一下你对我处理MultiTenancy的方式的看法。我使用MVC3(切换到MVC4)和EF作为我的后端。我使用的是单个应用程序,共享架构MultiTenancy。下面是代码:

public abstract class Service<T> where T : Entity
{
    private Repository<T> _repo;
    public Service()
    {
        _repo = new Repository<T>();
    }

    public bool Authenticate(int id)
    {
        //var companyInfo = _authorizationRepository.GetApiKey(apiKey);
        int tenantId = 0; // replaced by companyInfo using repository
        var entity = _repo.GetQuery(tenantId).Where(e => e.Id == id).First();

        if (tenantId != entity.TenantId)
            throw new ArgumentException();

        return true;
    }
}

public class EmployeeService : Service<Employee>
{
    private EmployeeRepository employeeRepository;
    public EmployeeService()
    {
        employeeRepository = new EmployeeRepository();
    }

    public Employee GetEmployeeById(int employeeId)
    {
        this.Authenticate(employeeId);
        return employeeRepository.GetById(employeeId);
    }
}

public class Entity
{
    public int Id { get; set; }
    public int TenantId { get; set; }
}

当然DI也会在那里,但为了简单起见,我在这里删除了它们(暂时)。我在服务层上使用了Generics(感觉很脏)因为我在比较TenantId和将在类上传递的正确实体时遇到了麻烦。我正在考虑使用FilterAttributes重新编码,但我不知道如何。你们如何处理你的多租户?从长远来看,设计是否有一些重要的缺陷?如果你有一些使用FilterAttributes的样本会有很大的帮助。

谢谢!

1 个答案:

答案 0 :(得分:2)

我们正在构建相当大的多租户网络应用程序。嗯,它看起来并不那么简单,但一旦你建立了你的架构,它就是直截了当的。我们正在深入开发,但您可以查看nanocms.codeplex.com中的开源部分(我们几天没有上传数据库喷射器)

由于这是一个非常广泛的问题,我将尝试总结一些问题和解决方案。

首先,您需要为每个请求识别租户。我们有一个全局操作过滤器,用于解析url并将其与数据库中的数据进行比较。当然,您必须缓存所有数据,以便不会调用数据库。您不能在cookie或会话中保存任何内容,因为用户当时可以访问多个租户。我建议你将这些数据放在HttpRequest Items中,这样你只需要在请求中执行一次,但仍然可以使用该数据。

对于身份验证用户必须是唯一的。您必须考虑是否要为每个租户提供一些用户不同的权限。如果是这样,您必须编写验证码甚至属性,以便检查他在当前租户中的角色。在用户进行身份验证的应用中,我们创建会话对象。在对象中,我们有静态方法来检查租户中的权限。

我建议您保持强类型的HttpRequest项目。我们有:

public static int TenantID {
    get { return System.Web.HttpContext.Current.Items.Contains("TenantID") ? Convert.ToInt32(System.Web.HttpContext.Current.Items["TenantID"]) : -1; }
    set {
        if (!System.Web.HttpContext.Current.Items.Contains("TenantID"))
            System.Web.HttpContext.Current.Items.Add("TenantID", value);
        System.Web.HttpContext.Current.Items["TenantID"] = value;
    }
}