ASP.NET插件架构:参考其他模块
目前,我们正在将 ASP Intranet 迁移到 .NET,并开始在一个 ASP.NET 网站中开发此 Intranet。然而,这引发了有关 Visual Studio 的一些问题(性能、编译时间……)。
因为我们的内网基本上都是模块存在的,所以我们想在Visual Studio中将我们的项目分成子项目(每个模块都是一个子项目)。 这也会引发一些问题,因为模块之间存在相互引用。 模块 X 使用模块 Y,反之亦然...(循环依赖)。
开发这样一个 Intranet 的最佳方式是什么?
我会举一个例子,因为它很难解释。
我们有一个模块来维护我们的员工。每个员工都有不同的文件(合同、员工创建的文件……)。
我们内联网中的所有文档均由文档模块维护。
employee-module需要引用document-module。
如果将来我需要在文档模块中引用员工模块怎么办?
解决这个问题的最佳方法是什么?
We're currently migrating our ASP Intranet to .NET and we started to develop this Intranet in one ASP.NET website. This, however, raised some problems regarding Visual Studio (performance, compile-time, ...).
Because our Intranet basically exists of modules, we want to seperate our project in subprojects in Visual Studio (each module is a subproject).
This raises also some problems because the modules have references to each other.
Module X uses Module Y and vice versa... (circular dependencies).
What's the best way to develop such an Intranet?
I'll will give an example because it's difficult to explain.
We have a module to maintain our employees. Each employee has different documents (a contract, documents created by the employee, ...).
All documents inside our Intranet our maintained by a document module.
The employee-module needs to reference the document-module.
What if in the future I need to reference the employee-module in the document-module?
What's the best way to solve this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在我看来,你有两个问题。
首先,您需要将系统的面向业务的功能分解为有凝聚力的部分;在面向对象设计方面,您应该使用一些原则来指导您的思考:
密切相关,以至于“如果一个需要改变,那么所有这些都可能需要改变”。
不要试图让组件做太多事情。
我认为您还需要更仔细地查看您的依赖结构 - 一旦您开始获得循环引用,这可能表明您没有正确地分解各种“事物”。也许您需要更多地了解问题领域?这是一个常见的问题——嗯,与其说是一个问题,不如说是设计复杂系统的一部分。
一旦你解决了这个问题,第二部分就会变得容易得多:系统架构和设计。
幸运的是,已经有很多关于插件的现有材料,尝试按标签搜索,例如:
编辑:
。这有两个部分,您可能想考虑使用两者:
通用层/ POCO
POCO 代表“普通旧 CLR 对象”,其思想是 POCO 是一种简单的数据结构,您可以使用它在层之间交换信息 - 或者在您的情况下在需要的模块之间交换信息保持松散耦合。 POCO 不包含任何业务逻辑。像对待 String 或 DateTime 类型一样对待它们。
因此,Asset 和 Employee 类不是相互引用,而是引用 POCO。
我们的想法是在一个通用程序集中定义它们,以便您的应用程序/模块的其余部分可以引用。定义这些的程序集需要避免不需要的依赖项——这应该很容易。
接口
这几乎是相同的,但不是指具体对象(如 POCO),而是指接口。这些接口将以与上述 POCO 类似的方式定义(公共程序集,无依赖性)。
然后,您可以使用工厂在运行时加载具体对象。这基本上就是依赖倒置。
因此,Asset 和 Employee 类不是相互引用,而是引用接口,并且具体实现在运行时实例化。
本文可能对上述两个选项都有帮助:依赖倒置简介
编辑:
这取决于逻辑所在,以及您想要如何构建事物。
如果您有一个业务逻辑 (BL) 层 - 主要是一个综合域模型 (DM)(资产和员工都是其中的成员),那么资产和成员很可能会互相了解,并且当您进行调用时要填充资产,您可能还会获得适当的员工数据。在这种情况下,BL / DM 要求提供数据 - 不是孤立的资产和成员类别。
在这种情况下,您的“模块”将是构建在上述 BL / DM 之上的另一层。
我的变体是,在 GetAsset() 中您只能获取资产数据,之后的某个时候您可以单独获取员工数据。无论您将事物耦合得多么松散,都必须在某个点定义资产和员工之间的连接,即使它只是在数据中。
这表明某种寄存器模式,即定义“连接”的地方,并且每当您处理“可分配”类型时,您都知道需要检查寄存器是否有任何可能的分配。
It sounds to me like you have two problems.
First you need to break the business orientated functionality of the system down into cohesive parts; in terms of Object Orientated design there's a few principles which you should be using to guide your thinking:
The idea is that things which are closely related, to the extent that 'if one needs to be changed, they all are likely to need to be changed'.
Don't try to have a component do to much.
I think you also need to look at you dependency structure more closely - as soon as you start getting circular references it's probably a sign that you haven't broken the various "things" apart correctly. Maybe you need to understand the problem domain more? It's a common problem - well, not so much a problem as simply a part of designing complex systems.
Once you get this sorted out it will make the second part much easier: system architecture and design.
Luckily there's already a lot of existing material on plugins, try searching by tag, e.g:
Edit:
There two parts to this, and you might want to look at using both:
Common Layer / POCO's
POCO stands for "Plain Old CLR Objects", the idea is that POCO's are a simple data structures that you can use for exchanging information between layers - or in your case between modules that need to remain loosely Coupled. POCO's don't contain any business logic. Treat them like you'd treat the String or DateTime types.
So rather than referencing each other, the Asset and Employee classes reference the POCO's.
The idea is to define these in a common assembly that the rest of your application / modules can reference. The assembly which defines these needs to be devoid of unwanted dependencies - which should be easy enough.
Interfaces
This is pretty much the same, but instead of referring to a concrete object (like a POCO) you refer to an interface. These interfaces would be defined in a similar fashion to the POCO's described above (common assembly, no dependencies).
You'd then use a Factory to go and load up the concrete object at runtime. This is basically Dependency Inversion.
So rather than referencing each other, the Asset and Employee classes reference the interfaces, and concrete implementations are instantiated at runtime.
This article might be of assistance for both of the options above: An Introduction to Dependency Inversion
Edit:
This depends on where the logic sits, and how you want to architect things.
If you have a Business Logic (BL) Layer - which is mainly a comprehensive Domain Model (DM) (of which both Asset and Employee were members), then it's likely Assets and Members would know about each other, and when you did a call to populate the Asset you'd probably get the appropriate Employee data as well. In this case the BL / DM is asking for the data - not isolated Asset and Member classes.
In this case your "modules" would be another layer that was built on top of the BL / DM described above.
I variation on this is that inside GetAsset() you only get asset data, and atsome point after that you get the employee data separately. No matter how loosely you couple things there is going to have to be some point at which you define the connection between Asset and Employee, even if it's just in data.
This suggests some sort of Register Pattern, a place where "connections" are defined, and anytime you deal with a type which is 'IAssignable' you know you need to check the register for any possible assignments.
我会考虑为您的插件创建接口,这样您就可以添加新模块,并且只要它们遵循接口规范,您的项目就可以在不明确了解它们的情况下调用它们。
我们用它来为我们的应用程序创建插件。每个插件都封装在实现特定接口的用户控件中,然后我们可以随时添加新模块,因为它们是用户控件,所以我们可以将控件的路径存储在数据库中,并使用加载控件来加载它们,然后我们使用界面来操作它们,加载它们的页面不需要知道它们的作用。
I would look into creating interfaces for your plug-ins that way you will be able to add new modules, and as long as they follow the interface specifications your projects will be able to call them without explicitly knowing anything about them.
We use this to create plug-ins for our application. Each plugin in encapsulated in user control that implements a specific interface, then we add new modules whenever we want, and because they are user controls we can store the path to the control in the database, and use load control to load them, and we use the interface to manipulate them, the page that loads them doesn't need to know anything about what they do.