我们有一些迷你应用程序(单个Web表单查找工具)需要在更大的站点和应用程序(以下称为“Monolith”)的上下文中运行
我们不希望在每个开发人员的计算机上安装Monolith,因此我们希望一些开发人员能够在他们自己的孤立沙箱项目(以下简称“Sandbox”)中开发这些小应用程序。我们的想法是,我们将(1)生成的DLL和(2)Web表单(aspx)文件从Sandbox移动到单片Web应用程序,然后运行它。
这一切都很好,除了这些小应用程序中的一些需要使用Monolith中存在的控件。如果没有Monolith背后的所有基础设施,这个控制将无法运行。
所以,我们有创建模拟控件的好主意。我们使用与Monolith中的控件相同的命名空间,类名和属性来删除控件。我们将其编译成DLL,然后放入Sandbox。我们可以针对它进行开发,它只是吐出Lorem Ipsum类型的数据,这很酷。
对控件的唯一引用是:
<Namespace:MyControl runat="server"/>
在Sandbox中,这会调用模拟对象。在Monolith中,这会调用实际控件。我们认为,由于与控件的唯一连接是上面的标签,它应该在两侧都有效。在运行时,它只会调用不同的东西,具体取决于它的运行位置。
因此我们将aspx文件和应用程序的DLL(不是模拟对象DLL)移动到Monolith中......并且它没有运行。
似乎我们没有依赖Visual Studio中出现的“mypage.aspx.designer.cs”文件。这会被编译到DLL中,并且它一直有一个引用回到我们的模拟对象DLL。因此,当它在Monolith中运行时,它会抱怨它无法加载模拟对象DLL。
因此,我们的目标是拥有如上所述的控制标记,并根据环境调用不同的东西。在这两种情况下,它都会执行相同的命名空间和类,但该命名空间和类在两个环境之间将是不同的。在Monolith中,它将是我们的实际控制。在Sandbox中,它将是我们的模拟对象。
基本上,我们希望在运行时评估此标记,而不是编译时。我们希望DLL没有任何引用回到模拟对象的DLL。
可能?针对核心问题的其他解决方案?
解决方案
最后,这很简单。
我使用针对我的模拟对象DLL编译的控件来处理我的应用程序。当我准备好最后一次编译时,我删除了对模拟对象DLL的引用,并添加了对Monolith DLL的引用。然后我编译并使用该DLL。
生成的DLL不知道它一直没有针对Monolith DLL开发。
答案 0 :(得分:2)
这看起来像松散耦合的工作!软件设计中最有用但最少遵循的原则之一是依赖性反转;类不应直接依赖于其他具体类,而应依赖于抽象基类或接口等抽象。
你对模拟对象有很好的直觉,但如果我理解的话,你就错误地实现了它。你基本上用另一个(模拟控件)替换了对一个具体类(Monolithic控件)的依赖。模拟可以具有相同的名称,甚至与Monolith具有相同的名称空间,但它驻留在与Monolith控件不同的程序集中,因为它被编译为引用该程序集,但在生产中找不到。环境。
我首先要为您的控件创建一个接口,该接口定义控件的使用者可用的功能(方法,属性等)。让Monolith的控件和模拟控件都实现这个接口,并声明将控件用作接口类型而不是Monolith或mock。将此接口放在一个相对轻量级的DLL中,与模拟对象,Sandbox和现有的Monolith DLL分开,您可以将它们放在开发人员的机器上,与模拟对象的DLL一起,也存在于Monolith代码库中。现在,需要您控制的类只需要接口;您不再需要直接引用Monolith或任何模拟DLL。
现在,在实例化依赖于此控件的对象时,您需要某种方式为新的依赖对象提供实现接口的具体类,可以是mock或Monolith,而不是创建新接口的依赖类。这称为依赖注入,是依赖倒置的自然延伸;指定一个接口很棒,但是如果您的依赖类必须知道如何创建实现该接口的对象的新实例,那么您还没有获得任何东西。创建具体类的逻辑必须位于依赖类之外。
因此,定义一个知道如何将控件挂钩到依赖于它的类的第三个类。首选方法是引入一个IoC框架,它可以作为任何对象的大型工厂,这些对象既可以是依赖项,也可以具有依赖项。您将两个控件中的一个注册为特定环境的接口实现(开发框的模拟,Monolith在生产中的控制);注册信息特定于每个环境(通常位于app.config中)。然后,您要求容器为您提供实现该接口的类的实例,而不是新建一个控件类的实例,然后弹出一个新的模拟或Monolith控件。或者,将控件和所有依赖类放在IoC容器中,并询问依赖类,容器将完全“保湿”返回,并引用其控件。所有这一切都发生在没有任何依赖于控件的类必须知道它来自哪里,或者甚至不知道它是什么。
但是,IoC框架可能很难集成到现有设计中。一个类似的工作是创建一个Factory类,它使用反射来动态实例化两个控件中的任何一个,并在app.config文件中放置一个AppSetting,它将告诉工厂在这个环境中使用哪个程序集和类型。然后,无论你通常在哪里修改一个控件,都要调用Factory。答案 1 :(得分:0)
我没有为您提供超级快速修复(可能是其他人会),但您可能对像Unity这样的IoC容器感兴趣。