在多租户 ASP .NET 应用程序中的隔离问题

13
我正在构建一个多租户ASP .NET应用程序。鉴于每个租户可以动态配置他们的应用程序(可能涉及将动态自定义程序集加载到内存中),我需要一种隔离每个租户的方法。
出于维护原因,我不想为每个租户创建新的Web应用程序。
我考虑使用AppDomainManager为每个应用程序创建一个AppDomain,但似乎这并不适用于ASP .NET应用程序。
是否有人对此有建议?
谢谢。
3个回答

5
我猜问题是:如果您不想创建Web应用程序,那么什么类型的隔离对您来说真正可接受?如果您真的希望在操作系统级别上保证程序集不会互相干扰,我会为每个程序集提供自己的Web应用程序。特别是当您允许用户加载第三方程序集时,这一点尤为重要,如果这些第三方程序集可以找到实例化非托管代码的方法,则更加必要。如果所有代码均为您的(托管)代码,则可以不创建单独的Web应用程序,但一旦将动态自定义程序集结合在一起,我认为这是唯一可行的方法。

我赞同这个观点,关键词是“自定义程序集”。 - Andreas Paulsson
好的,我肯定愿意考虑这个方案,但我有一些顾虑。一,所有应用程序都应该具有相同的根URL...这可能吗?二,创建和删除需要自动化...我应该使用WMI吗?我不知道我对此有何感觉...IIS支持多少个Web应用程序?在硬件云中,这是否可扩展,因为限制在于操作系统?三,我们希望这个解决方案与Azure兼容(但不是Azure特定),那么我该如何为Azure进行管理? - Jeff
另外,您会如何建议处理共享资源(页面)?使用从共享dll中提取页面的VirtualPathProvider? - Jeff

1

我在MVC2中编写了多租户Web应用程序。由于我选择了共享数据库、共享模式的方法,因此添加/删除帐户与添加/删除表中的行一样复杂。

这是一篇关于多租户数据库设计的非常好的MSDN文章:Multi-Tenant Data Architecture

在MVC中,我所要做的就是正确设置路由,使路径的第一部分是帐户名:

  • www.yourdomain.com/Account1/...
  • www.yourdomain.com/Account2/...
  • www.yourdomain.com/Account3/...

而且我还有一个自定义的MvcHandler来查找每个请求的帐户:

public class AccountMvcHandler : MvcHandler
{
    public AccountModel Account { get; set; }

    public AccountMvcHandler(RequestContext requestContext)
        : base(requestContext)
    {
    }

    protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
    {
        string accountName = this.RequestContext.RouteData.GetRequiredString("account");
        Account = ServiceFactory.GetService<IAccountService>().GetAccount(accountName);

        // URL doesn't contain valid account name - redirect to login page with Account Name textbox
        if (Account == null)
            httpContext.Response.Redirect(FormsAuthentication.LoginUrl);

        return base.BeginProcessRequest(httpContext, callback, state);
    }
}

正如Andreas Paulsson所说的那样,关键词是“自定义程序集”。为什么需要“自定义程序集”来进行配置?您是否使用CodeEmit?用户会上传它们吗?我更倾向于考虑使用Windows Workflow Foundation来进行任何客户特定的业务逻辑定制。

我已经设置了特定于租户的MVC路由,它们运行良好。自定义程序集的目的是让租户能够使用自定义页面和代码后台来自定义他们的“实例”。为此目的隔离任何自定义代码是关键。 - Jeff
进一步澄清,是的,用户将上传自定义程序集,这些程序集将在应用程序域中编译和运行。问题在于这些程序集需要某种形式的隔离,以便不能访问其他租户的数据。我已经有了防止自定义程序集进行数据库调用的代码,但我担心静态上下文,例如应用程序状态或静态属性/方法/字段。 - Jeff
我考虑为这些自定义程序集动态创建应用程序域,但我更喜欢集成的方式,因为 asp.net 已经为我管理了应用程序域。此外,我不确定如何将我的自定义应用程序域加入 asp.net 请求生命周期(能够发出呈现的 aspx 页面)。 - Jeff
@JeffN825 - 在我看来,允许用户上传任何代码都是一个潜在的麻烦事。根据自定义客户端的数量,您可能希望为他们提供一个新的网站 - 这应该可以通过简单的msbuild脚本实现... - Jakub Konecki
我真的不想养成为每个新客户都需要定制部署的习惯。这确实是一个麻烦的问题,但绝对是要求的一部分。我一直在研究使用DLR来托管代码,但我不确定是否有成熟的实现来支持它。 - Jeff

1

当您创建不同的网站时,您的URL根路径肯定会改变。我在想为什么不在主应用程序内创建不同的应用程序,并根据需要将它们放入不同的应用程序池中?

一... 这样,根URL将保持不变。 二... 创建VDir或应用程序实例。哪一个需要是动态的? 三... 我没有专业知识。

如果我必须分享页面[基于托管在不同VDir中的应用程序],我会为所有共享页面创建一个新的VDir。并使用一些自定义代码来显示与应用程序相关的数据。


我该如何动态创建应用程序呢?这是问题所在。 - Jeff
如果您使用的是IIS 7,您可以委派IIS虚拟目录的配置给终端用户,以便他们可以配置自己的应用程序。 - Rahul Soni
你可以使用SharePoint或DotNetNuke。如果我理解你的问题正确,你可以使用SharePoint创建站点定义,并让任何人将其用作自己网站的模板。 - Rahul Soni
每个SharePoint网站是否在单独的AppDomain中运行?如果是的话,那可能是一个非常可行的解决方案。 - Jeff
好的,我想是这样的[虽然不是100%确定]!好处是,如果您创建了一个包含所有所需功能的站点定义,那么其他人可以轻松地在其上工作。您只需要说一些像...创建新的网站集合并选择您的站点定义。此时,您分配一个网站集合管理员就可以了。它会自行处理隔离所有数据,并且使用起来非常容易。 - Rahul Soni
我查了一下,似乎不能保证站点之间的AppDomain隔离,所以不幸的是,这并没有解决防止租户特定代码执行不应该做的事情的问题。 - Jeff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接