“继承”来自通用模板应用程序的 ASP.NET MVC 站点? (多租户)

发布于 2024-08-06 08:28:56 字数 1105 浏览 7 评论 0 原文

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

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

无论如何,我们正在尝试找出如何最好地分解和构建事物,以便我们可以重用尽可能多的代码和尽可能多的测试,而不限制我们添加每个应用程序属性和改变应用程序之间的 UI 的自由。

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

我不太担心操作问题,因为我们可能会在单独的应用程序域中运行每个站点并将它们托管在单独的数据库上。我更担心的是减少长期代码维护成本,提高敏捷性(例如,在不破坏派生应用程序的情况下轻松向基础添加新功能),以及在构建第二个应用程序时实现短期开发/测试成本节省。第三、第四等站点。

我不仅在寻找高级指导和建议,而且也在寻找有关如何使用现代 ASP.NET MVC 实践使该指导成为现实的具体建议。

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

  • 建议跨 Visual Studio 项目拆分基/
  • 派生源控制提示,以避免分叉
  • 数据库模式提示(FWIW,我们的数据库都很小 - 每个表不到 10K 行,因此开发/测试成本比数据库性能更重要)
  • 有关 re 的提示-使用控制器/视图/等。对应于“基本”模型属性,尤其是对诸如“新客户”表单之类的内容重新使用 UI,这些表单将具有基本属性和派生属性的混合。

有人对如何构建这样的多租户应用程序有好的建议吗?

We're building about 10 ASP.NET MVC sites which have a common set of features (and corresponding URLs, Routes, Controllers, Actions, and Views). The sites will also all share a base set of domain objects (e.g. users, companies) and base attributes on those objects (e.g. name, address, etc.).

But each site will also be highly customized and extended from the base. For example, our site for large, public companies will have "Subsidiary" and "Stock Symbol" fields on the Company domain object, while our site for startups will have a "Venture Firm" and and "Funding" attributes. Look and feel will also vary considerably, although we're trying to keep HTML as consistent as possible (modulo extra form fields for extra domain object attributes, etc.). We'll also be overriding images sparingly, so we can, for example, re-use the same button graphics across sites.

Anyway, we're trying to figure out how best to factor and architect things so that we can reuse as much code and as many tests as possible without limiting our freedom to add per-app attributes and vary the UI between apps.

I'm familiar with how to handle limited-customization multi-tenancy like you find in StackOverflow/SuperUser/ServerFault (or MSDN/TechNet for that matter), where the UI is a little different and the data model is more-or-less identical. But when the models and UI are very different (but inherit from a common base), I'm less sure how to proceed.

I'm less worried about operational issues, since we'll probably be running each site in a separate appdomain and hosting them on separate databases. I'm more worried about reducing long-term code maintenance costs, increasing agility (e.g. easy to add new features to the base without breaking derived apps), and realizing short-term dev-/test-cost savings as we build our 2nd, 3rd, 4th, etc. site.

I'm looking both for high-level guidance and suggestions, but also concrete suggestions for how to make that guidance real using modern ASP.NET MVC practices.

I realize this is a very general question, but for starters I'm looking for both high-level guidance as well as concrete tips-n-tricks for how to apply that guidance with ASP.NET MVC, including things like:

  • recommendations where to split base/derived across Visual Studio projects
  • source control tips to avoid forking
  • database schema tips (FWIW, our databases are all small-- under 10K rows per table, so dev/test cost is more of an issue than DB perf)
  • tips about re-using Controllers/Views/etc. corresponding to the "base" model attributes, especially re-using UI for things like "new customer" forms which will have a mix of base and derived attributes.

Anyone have good advice for how to architect a multi-tenant app like this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我很OK 2024-08-13 08:28:56

这就是我们所做的,目前它对大约 8 个站点效果很好。

  • 为您的控制器、ViewModel、HttpApplication、路由等定义一个核心 MVC 项目。这将编译为 DLL 并危及您网站的大部分内容。

  • 为您的网站创建一组基本的默认视图、脚本、图像等。这些将作为您各个站点的默认设置。

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

    每个客户端,创建您在编译为另一个 dll 的项目中需要的任何

  • 此外,针对每个客户端,重新创建您想要使用的任何视图、脚本、图像。

    另外,

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

让一切正常工作的第二种方法是让核心应用程序从客户端特定程序集加载路由、控制器等。为此,我使用托管扩展性框架 (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 默认值中定义这些名称。

我意识到这是一个粗略的概述,但它现在对我们来说已经足够好了。

Here's what we do, and it works pretty well for about 8 sites currently.

  • Define a core MVC project for your Controllers, ViewModels, HttpApplication, routes, etc. This will compile into a DLL and compromise the bulk of your site.

  • Create a basic set of default views, scripts, images, etc. for your site. These will server as defaults for your individual sites.

  • Per client, create any custom controllers, routes, etc that you'll need in a project that compiles to another dll.

  • Also per client, recreate any views, scripts, images that you'll want to use.

To make the above steps work together you'll need to write a little glue. The first piece of glue is a custom view engine. You'll want to customize the standard view engine to first look for views in your client-specific folder, and then the default folder. This lets you easily override the default layout per client.

The second method of getting everything working is to have your core application load the routes, controllers, etc from your client specific assembly. To do this I use the Managed Extensibility Framework (MEF) to expose a single Register method. Calling this method on my client assembly code registers the routes and any other client-specific needs.

Here's a general view of what my site folder structure looks like, with SiteContent being checked for views first:

  - 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

I have helpers that I can use like SiteImage and AppImage for use in my views. Also, I make each of my client sites use certain specific names for their master pages, that I don't ever define in my AppContent defaults.

I realize this is a rough overview, but it is working well enough for us right now.

如日中天 2024-08-13 08:28:56

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

我们尝试做的一件事是创建本身可重用的页面(模型、视图和控制器组合),因此任何应用程序都可以使用该页面捕获信息,但重定向到下一页,该页面可能会有所不同,具体取决于应用程序的类型产品正在申请中。为了实现这一目标,我们使用模板方法模式形式的抽象基本控制器,该控制器基本上包含所有必需的控制器逻辑(包括带有应用的操作过滤器的操作方法),然后使用抽象方法来执行特定的操作,例如重定向到过程中的下一页。这意味着特定应用程序页面流使用的控制器的具体实现可能只包含一个返回与流中下一页相对应的 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)
我进行 POC 的一件事看起来会起作用,那就是使用基本 MVC 项目来包含常见视图,然后扩展默认视图引擎以在寻找要渲染的视图时在 Web 服务器上搜索该项目(这很容易做到) )。不过,区域是一个更好的解决方案。

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

不确定这是否对您有很大帮助,但我绝对建议您记住抽象控制器和模型,并了解如何使用 html 帮助器和部分视图来对类似的功能进行分组。

I'm involved in a similar type of "suite" of projects currently which is focused on allowing customers to apply for products online but have very similar requirements for what information to collect, where the only differences are around product specific pieces of information or slightly different legislative requirements.

One thing that we have tried to do is create pages (model, view and controller combinations) that are reusable in themselves, so any application can use the page to capture information but redirect to the next page which may be different depending on what type of product is being applied for. To achieve this we are using abstract base controllers in the form of the template method pattern that contain basically all the required controller logic (including action methods with their applied action filters) but then use abstract methods to do the specific stuff such as redirecting to the next page in the process. This means that the concrete implementation of the controller used by specific application page flows may contain only one method which returns a RedirectToActionResult corresponding to the next page in the flow.
There is also quite a bit of other stuff that handles going backwards and those kinds of navigational things, but with the help of action filters you can get it set up that you don't have to worry about it once you get it up and working.

There are also base model objects which contains common functionality, be it validation logic or state persistence logic.

The data captured during the application process is persisted in database as xml serialized model objects which can then be pulled out and de-serialised once the application is completed and spat out in whatever format to whatever system the backend operations staff use to process applications.

The implications of this is that we have a project structure that consists of a base dll that contains top level abstract classes, interfaces and utility classes as well as html helpers, action filters etc. Then we have mvc projects which contain the concrete implementations of the base controllers, models etc as well as the views and masterpages.

The hardest thing is sharing views and I don't think we have properly got this sorted yet. Although with MVC 2.0 containing Areas I think this will become less of an issue but I haven't had a good play with it yet. (see Scott Gu's post on 2.0: http://weblogs.asp.net/scottgu/archive/2009/07/31/asp-net-mvc-v2-preview-1-released.aspx)
One thing I have POCed that looks like it will work is using a base MVC project to contain common views and then extending the default view engine to search that project on the web server when looking for a view to render (which is quite easy to do). Areas though is a far nicer solution.

As for source control, we are using svn and I think you are reasonable in being concerned about branches. It is not something that we have had to deal with yet, but we are probably going to go with git as it seems to make the process of branching and merging much less painful.

Not sure whether this helps you much but I would definitely recommend keep in mind abstract controllers and models, and also look at how you can use html helpers and and partial views to group similar pieces of functionality.

浴红衣 2024-08-13 08:28:56

实现此目的的一种方法是在源代码控制系统中使用分支。

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

One way to do this is to use branching in a source control system.

The main branch is for the common functionality. You then have a branch for customization and can merge changes out to the customization or back to the main branch.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文