从一个常见的模板应用程序“继承”ASP.NET MVC网站? (多租户)

时间:2009-09-30 02:28:14

标签: asp.net-mvc architecture inheritance dry multi-tenant

我们正在构建大约10个ASP.NET MVC站点,这些站点具有一组通用功能(以及相应的URL,路由,控制器,操作和视图)。这些站点还将共享一组域对象(例如用户,公司)和这些对象上的基本属性(例如,名称,地址等)。

但每个站点也将高度定制并从基础扩展。例如,我们针对大型上市公司的网站将在公司域对象上具有“子公司”和“股票代码”字段,而我们的初创公司网站将具有“风险公司”和“资金”属性。虽然我们试图尽可能保持HTML的一致性(为额外的域对象属性建模额外的表单字段等),但外观也会有很大差异。我们也会谨慎地覆盖图像,因此我们可以在网站上重复使用相同的按钮图形。

无论如何,我们正在努力弄清楚如何最好地考虑事物和构建事物,以便我们可以尽可能多地重用代码和尽可能多的测试,而不会限制我们添加每个应用程序属性的自由,并改变应用程序之间的UI。

我熟悉如何处理有限的自定义多租户,就像您在StackOverflow / SuperUser / ServerFault(或MSDN / TechNet)中找到的那样,UI有点不同,数据模型更多 - 或者更少相同。但是当模型和UI非常不同(但是从共同基础继承)时,我不太清楚如何继续。

我不太担心操作问题,因为我们可能会在单独的appdomain中运行每个站点并将它们托管在不同的数据库中。我更担心的是降低长期代码维护成本,提高灵活性(例如,在不破坏衍生应用程序的情况下轻松添加新功能到基础),以及在构建第2版时实现短期开发/测试成本节省,第3,第4等网站。

我正在寻找高级指导和建议,但也有关于如何使用现代ASP.NET MVC实践使指导真实的具体建议。

我意识到这是一个非常普遍的问题,但对于初学者而言,我正在寻找高级指导以及如何在ASP.NET MVC中应用该指导的具体提示 - 技巧,包括:

  • 建议在Visual Studio项目中拆分基础/派生的位置
  • 避免分叉的源控制提示
  • 数据库架构提示(FWIW,我们的数据库都很小 - 每个表10K行以下,所以开发/测试成本比DB perf更多问题)
  • 有关重新使用控制器/视图等的提示。对应于“基础”模型属性,尤其是重新使用UI,例如“新客户”表单,它们将混合使用基本属性和派生属性。

对于如何构建像这样的多租户应用程序,任何人都有很好的建议吗?

4 个答案:

答案 0 :(得分:11)

以下是我们的工作,目前大约有8个网站效果很好。

  • 为您的Controllers,ViewModels,HttpApplication,路由等定义核心MVC项目。这将编译成DLL并破坏您网站的大部分内容。

  • 为您的网站创建一组基本的默认视图,脚本,图片等。这些服务器将作为您各个站点的默认服务器。

  • 每个客户端,在编译到另一个dll的项目中创建您需要的任何自定义控制器,路由等。

  • 同样根据客户,重新创建您想要使用的任何视图,脚本和图像。

要使上述步骤协同工作,您需要编写一些胶水。第一块胶水是自定义视图引擎。您需要自定义标准视图引擎,以首先在特定于客户端的文件夹中查找视图,然后查找默认文件夹。这使您可以轻松覆盖每个客户端的默认布局。

使一切正常运行的第二种方法是让您的核心应用程序从客户端特定程序集加载路由,控制器等。为此,我使用Managed Extensibility Framework(MEF)来公开单个Register方法。在我的客户端汇编代码上调用此方法会记录路由和任何其他特定于客户端的需求。

以下是我的网站文件夹结构的一般视图,首先检查SiteContent的视图:

  - AppContent
  - AppContent/Static
  - AppContent/Static/Images
  - AppContent/Static/Scripts
  - AppContent/Static/Styles
  - AppContent/Views
  - AppContent/Views/Shared

  - SiteContent
  - SiteContent/Static
  - SiteContent/Static/Images
  - SiteContent/Static/Scripts
  - SiteContent/Static/Styles
  - SiteContent/Views
  - SiteContent/Views/Shared

  - web.config
  - Global.asax

我有一些帮助,我可以使用SiteImage和AppImage在我的视图中使用。另外,我让每个客户端站点都使用某些特定的名称作为其母版页,我从未在AppContent默认值中定义。

我意识到这是一个粗略的概述,但它现在对我们来说运作良好。

答案 1 :(得分:2)

我参与了类似的“套件”项目,目前专注于允许客户在线申请产品,但对收集哪些信息的要求非常相似,其中唯一的区别在于产品特定的产品。信息或略有不同的立法要求。

我们尝试做的一件事是创建可重复使用的页面(模型,视图和控制器组合),因此任何应用程序都可以使用该页面来捕获信息,但重定向到下一页可能会有所不同,具体取决于正在申请什么类型的产品。为了实现这一点,我们使用模板方法模式形式的抽象基础控制器,它基本上包含所有必需的控制器逻辑(包括带有应用的动作过滤器的动作方法),然后使用抽象方法来执行特定的操作,例如重定向到这个过程的下一页。这意味着特定应用程序页面流使用的控制器的具体实现可能只包含一个方法,该方法返回与流中下一页对应的RedirectToActionResult。 还有很多其他的东西可以处理倒退和那些导航的东西,但是在动作过滤器的帮助下,你可以设置它,你不必担心它一旦你起床和工作。

还有一些基本模型对象,它们包含通用功能,无论是验证逻辑还是状态持久性逻辑。

在应用程序进程中捕获的数据作为xml序列化模型对象保存在数据库中,然后可以在应用程序完成后将其拉出并反序列化,并以任何格式向后端操作人员用于处理的任何系统进行吐出应用

这意味着我们有一个项目结构,它包含一个基本的dll,它包含顶级抽象类,接口和实用程序类以及html助手,动作过滤器等​​。然后我们有mvc项目,其中包含具体的基本控制器,模型等以及视图和主页的实现。

最困难的是分享观点,我认为我们还没有正确地对其进行分类。虽然MVC 2.0包含区域,但我认为这不会成为一个问题,但我还没有很好的发挥它。 (参见Scott Gu关于2.0的帖子: http://weblogs.asp.net/scottgu/archive/2009/07/31/asp-net-mvc-v2-preview-1-released.aspx) 我有一个看起来像POCed的东西是使用一个基础MVC项目来包含公共视图,然后扩展默认视图引擎以在查找要渲染的视图时在Web服务器上搜索该项目(这很容易做到) )。区域虽然是一个更好的解决方案。

至于源代码控制,我们正在使用svn,我认为你关心分支是合理的。它不是我们必须处理的东西,但我们可能会使用git,因为它似乎使分支和合并的过程更加痛苦。

不确定这对你有多大帮助,但我肯定会建议记住抽象控制器和模型,还要看看如何使用html助手和部分视图来分组相似的功能。

答案 2 :(得分:1)

答案 3 :(得分:1)

执行此操作的一种方法是在源控制系统中使用分支。

主分支用于常用功能。然后,您有一个用于自定义的分支,可以将更改合并到自定义或返回主分支。