我的任务是为公司重写一个相当大的Web应用程序。此应用程序为我们目前拥有的3个客户提供某些财务/风险分析。
这个应用程序的一个大问题是每个客户端都不同,并且数据略有不同。他们都登录到同一个网站,但之后他们的经验会略有不同。他们的数据库模式不尽相同,偶尔他们的观点必须不同以表示不同的数据,他们的用户管理是一个复杂的噩梦。当用户登录我们的站点时,我们需要从正确的数据库中提取数据(每个客户端都有自己的数据)。
假设我们的客户是3家硬件公司:
Hackman的硬件可能有不同的分析需求,或在我们的报告中请求某些特殊列。同样,Lowes Hardware可能希望对其页面的安全访问权限略有不同,然后根据其用户对其他公司进行安全访问。
从功能上讲,Web应用程序对他们来说是相同的。它具有相同的选项卡,并且在尝试呈现的信息方面具有相同的目标。但是它们之间存在细微差别,我在封装时遇到了麻烦,而且它使代码变得混乱。
问题:处理需要针对我们获得的每个新客户端进行修改的基本应用程序的最佳做法是什么?我们可以使用哪种架构/设计模式来增加新客户端,尽管他们需要进行自定义,同时仍然尽可能多地重新使用?如何在不需要每个客户端黑客的情况下保持我们的代码库清洁?
我们正在使用ASP.NET MVC进行重写,但我不确定这个问题的相关性。
答案 0 :(得分:4)
创建一个母版页,其中包含每个客户端相同的所有信息。然后,添加每个客户端唯一的视图和/或控制器。
查看以下链接。它解释了如何创建“应用程序控制器”,这是一个可以由其他控制器继承的抽象类,这样您只需编写一次代码就可以将所需的母版页数据推送到视图中。
将数据传递到查看母版页:
http://www.asp.net/learn/MVC/tutorial-13-cs.aspx
另外,请看下面的链接,它解释了如何在ASP.NET MVC中实现部分视图和子控件:
ASP.NET MVC中的部分请求
http://blog.codeville.net/2008/10/14/partial-requests-in-aspnet-mvc/
答案 1 :(得分:4)
我将不得不反对描述从公共基本控制器等派生的一些方法,因为单独的子类化不会很好。您将为每个客户端添加派生类,如果您拥有的不仅仅是少数几个客户端,它将成为维护的噩梦。此外,虽然MasterPage将以某种身份使用,但如果您的客户希望输入其网站的外观和感觉,那么很多东西,如颜色,样式等,都需要数据驱动。 / p>
门户网站的想法非常好,但是如果你有很多自定义域逻辑会因客户端而异,那么它也会很快成为一个问题。如果只是为一些客户隐藏一些页面的问题,那么门户网站的想法并不是一个糟糕的建议。请记住,如果您正在使用预生产环境,那么门户网站(如DotNetNuke)很难从一个环境部署到另一个环境,除非您非常熟悉其架构。此外,像DotNetNuke这样的网站不是用MVC编写的,因此应用任何测试驱动的开发实践将比从头开始更具挑战性。
如果你已经没有很好的背景知识,我会首先开始阅读设计模式,特别是策略和抽象工厂模式。这将允许您查看项目的设计,着眼于支持依赖继承。尝试开发一些域类,这些类将公开属性,这些属性是您将向客户公开的内容的模板。这些属性的类型将使用封装从客户端到客户端的不同类的类。一旦构建了几个类并对其进行测试,就可以生成支持它所需的数据库模式。我怀疑你最终将得到一个客户表,包含实体及其相关值类型的可能值的表,以及将客户与这些实体相关联的表。
希望这有帮助。
答案 2 :(得分:2)
您期望有多少潜在客户?如果答案是每年2个新答案,那么您的解决方案将与每年200个新客户的答案不同。
首先,它听起来像需要一个主配置数据库(或文件)。您的应用程序可以使用此配置信息来确定可自定义的所有内容。之后,构建用于添加客户端的UI非常简单。
如果我这样做(我对你的项目知之甚少)...... 我首先要创建一个“基础”客户端模型。所有新的客户端模型都将从这个基础派生,它将包含我所有的标准逻辑。对于现有客户来说,将它们装入可能会很痛苦,但通过一系列包装函数和配置类,可以完成它。
答案 3 :(得分:1)
您需要一个“门户网站”。
有很多关于如何在ASP.NET中构建Web门户的信息可能会为您提供有关如何使用MVC的一些想法。特别是DropThings portal和它的配套书Building a Web 2.0 Portal with ASP.NET 3.5。您可以将其大部分或全部想法调整为ASP.NET MVC。
答案 4 :(得分:1)
查看“多租户”应用程序。 这里multi tenant on so
答案 5 :(得分:0)
最终,您需要一种方法来描述应用程序可以理解的元数据中的架构。有很多不同的方法可以做,你必须自己选择,但作为一个例子(不一定是最好的选择 - 或一个好的选择):
使用XML来描述每个商店的架构。创建一个基于XML生成数据库模式的工具。对报告进行编码以查看XML以确定要显示的列。继续恶心。
另一个选择是保持应用程序的核心相同,但创建不同的关键部分的不同实现。使用IoC容器库为每个商店加载适当的实现。
答案 6 :(得分:0)
数据级别的自定义始终具有挑战性。首先分析一下客户与下一个客户的不同之处。然后寻找创建封装变体的单一数据设计的方法。这可能很棘手,但我们非常值得付出努力。如果您可以尝试考虑如何创建设计以满足未来客户的需求(是的,这可能涉及水晶球)。
从架构的角度来看,考虑在数据访问层使用anstract工厂模式。在不知道要求的细节或从一个客户到另一个客户的变化程度的情况下,我不确定这是多么适用,但我过去使用这种模式成功地解释了格式和结构的相当大的变化。需要传递到公共处理/表示层的数据源。这将允许您创建直接插入系统前端的数据层组件。
自定义表示层可以更加直接,并且可以通过MVC,母版页和主题的用户轻松处理。我认为这里发布的其他一些评论/答案涉及定制过程的那些方面。
答案 7 :(得分:0)
使用硬煮C#代码和一些脚本语言(如IronPython)来解决您的问题可能是一个好主意。很难创建足够全面的配置文件来描述客户端之间发生的细微差别,并且您不能在配置文件中使用任何类型的逻辑(除非您自己开发另一种半生不熟的编程语言)。
我会尝试为C#中的所有安装编写类似的内容,并在Python中安装所有不同的内容。我将进一步使用您的源代码管理工具来管理C#框架和Python配置的组合。这应该为您提供可重用代码与每个客户端的特定业务逻辑要求之间明确定义的边界。此外,由于脚本语言未编译,您将能够在现场调整配置。这样做被广泛认为是不好的做法,但是当您将Python代码视为应用程序的美化配置时,它可能并不那么糟糕。由于自定义在Python中被攻击,因为特定客户已经成熟为可重用的概念,我会将它们重新编写为C#,将它们添加到框架中并删除自定义。
请注意,我在这里使用C#和IronPython作为示例 - 您可以使用两种语言的任意组合。但我确实认为两者之间的语法应该有很大的不同,以保持边界清晰。