通过 .NET 反射在运行时动态加载程序集





4.00/5 (1投票)
展示了 .NET 如何通过延迟绑定和反射的强大功能,根据实际需要,在运行时加载程序集的能力。
目标
本文旨在展示 .NET 如何通过延迟绑定和反射的强大功能,根据实际需要,在运行时加载程序集的能力。
引言
在典型的 N 层应用程序中,我们有
- 表示层 – 构成应用程序的用户界面
- 应用程序层 – 处理业务逻辑
- 数据访问层 – 与数据库交互
通常,这三层是完全独立的,通过程序集引用进行调用。表示层可以与业务层完全分离,并且完全不知道其功能和数据类型。它只关心业务层提供的数据。此外,业务层可以服务于一个以上的表示层(Web、Windows 等),前提是它们知道如何调用它。
当存在一个以上的表示层调用多个业务层时,情况就会变得有趣。处理这种情况的优化方法是什么?
让我们通过一个例子来理解这个问题。
考虑一家养老金公司 IT 基础设施 – ABC Pension。ABC Pension 为其 100 多家客户的员工计算养老金福利。每位客户根据其需求有不同的养老金计算规则。ABC Pension 必须通过单一 IT 基础设施为所有客户提供养老金信息。
让我们考虑它有两种用户界面表示层
- 基于 Java 的网站 – 用户可以通过其凭据登录并查看其账户
- 桌面应用程序 – 由电话代表使用,当客户拨打公司免费帮助热线电话时,他们会接听。这可以是 VC++、VB.NET 或 C# 或任何其他语言。桌面应用程序向电话代表显示的信息比网站更多。
ABC Pension 公司的每位客户都由一个客户代码标识。当一个人通过其 SSN 和安全密码登录数据库时,系统会获取其客户 ID。表示层与业务层之间的通信通过 XML 进行。
有一个独立的开发团队,他们在养老金领域受过高度培训,负责管理应用程序层中的实际养老金计算逻辑。每个客户都有一个单独的代码库来实施其自身的业务逻辑。
例如 – 客户 A 为其员工有一个单独的代码库;客户 B 为其员工有一套独立的 कोड库。当来自公司 A 的员工登录到网站时,表示层必须调用业务逻辑 A 套库。同样,当来自公司 B 的员工登录到网站层时,表示层必须调用业务逻辑 B 套库。
如何实现这一点?
解决方案
处理此问题的最优化方法通过随附的示例代码进行了描述。为了简单起见,我们将使用三个客户和三种业务逻辑——BusinessLogic-1、BusinessLogic-2、BusinessLogic-3。
理想的实现方式是创建一个“业务逻辑管理器”,它将根据传递给它的客户 ID 来决定调用哪个业务逻辑。
在此项目中,Dynamic Assembly Loader 控制台应用程序执行此任务。为简单起见,这是一个控制台应用程序,并且业务逻辑的选择是通过控制台的用户输入来完成的。在实际场景中,这可以是一个 WCF 服务或任何其他项目类型。
第一部分是创建 BusinessLogicLibrary
——抽象。它包含
- 抽象类 –
AbstractBusinessLogic
namespace BusinessLogicLibrary { public abstract class AbstractBusinessLogic: IBusinessLogic { virtual public string GetBusinesslogic() { throw new NotImplementedException(); } } }
- 接口 –
IbusinessLogic
namespace BusinessLogicLibrary { public interface IBusinessLogic { string GetBusinesslogic(); } }
注意 – 抽象类中的方法被声明为虚方法,以便可以被实现实际业务逻辑的方法覆盖。
现在,让我们构建三个业务逻辑代码库。在这里,我使用了简单的类库,它们返回一个 String
来标识它们被调用的来源。例如 – 如果调用了 Business Logic 1,它将返回“Calculated Busines Logic 1”。在实际应用中,这可以是一个 XML 文档,返回客户 1 的养老金计划值。
Business Logic - 1 的代码
namespace BusinessLogic_1
{
public class BusinessLogic_1: AbstractBusinessLogic
{
public override string GetBusinesslogic()
{
return "Calculated Business Logic 1";
}
}
}
Business Logic - 2 的代码
namespace BusinessLogic_2
{
public class BusinessLogic_2:AbstractBusinessLogic
{
public override string GetBusinesslogic()
{
return "Calculated Business Logic 2";
}
}
}
Business Logic - 3 的代码
namespace BusinessLogic_3
{
public class BusinessLogic_3:AbstractBusinessLogic
{
public override string GetBusinesslogic()
{
return "Calculated Business Logic 3";
}
}
}
请注意,Business Logic 类库继承自 AbstractBusinessLogic
抽象类并覆盖了 GetBusinessLogic()
方法。
现在来到了主要部分 – Dynamic Assembly Loader。这是我们的业务逻辑管理器,它根据输入决定在内存中加载哪个业务逻辑 DLL。
首先,添加对以下项的程序集引用
System.Configuration
和BusinessLogicLibrary
- BusinessLogic-1
- BusinessLogic-2
- BusinessLogic-3
在 app.config 文件中添加以下内容
<configuration>
<appSettings>
<add key="BusinessLogic1" value="BusinessLogic_1.BusinessLogic_1,BusinessLogic-1"/>
<add key="BusinessLogic2" value="BusinessLogic_2.BusinessLogic_2,BusinessLogic-2"/>
<add key="BusinessLogic3" value="BusinessLogic_3.BusinessLogic_3,BusinessLogic-3"/>
</appSettings>
</configuration>
请注意,appsettings
的值应该是完全限定的程序集名称 – 命名空间.类,程序集名称。
声明一个 IbusinessLogic
接口的实例。请记住,Business Logic 类实现了 IbusinessLogicInterface
。
IBusinessLogic businessLogic = null;
询问用户输入
Console.WriteLine("Press ....");
Console.WriteLine("1 --- For Business Logic 1");
Console.WriteLine("2 --- For Business Logic 2");
Console.WriteLine("3 --- For Business Logic 3");
Console.WriteLine("Enter your choice");
string choice = Console.ReadLine();
string strbusinessLogicType=null;
然后,根据用户的选择,从 App.Config 文件中获取要加载的程序集的完全限定名称
switch (choice)
{
case "1":
strbusinessLogicType = ConfigurationManager.AppSettings.Get("BusinessLogic1");
businessLogic = ProcessLogic(strbusinessLogicType);
break;
case "2":
trbusinessLogicType = ConfigurationManager.AppSettings.Get("BusinessLogic2");
businessLogic = ProcessLogic(strbusinessLogicType);
break;
case "3":
strbusinessLogicType = ConfigurationManager.AppSettings.Get("BusinessLogic3");
businessLogic = ProcessLogic(strbusinessLogicType);
break;
default:
break;
}
最后,在 static
方法 ProcessLogic()
中加载 DLL
static IBusinessLogic ProcessLogic(string logicName)
{
try
{
Type businessLogicType = Type.GetType(logicName);
IBusinessLogic logic= (IBusinessLogic)
Activator.CreateInstance(businessLogicType) ;
if (logic == null)
{
//return null;
throw new Exception("Business Logic Not Loaded");
}
else
return logic;
}
catch (Exception ex)
{
Console.WriteLine("An exception has occurred");
Console.WriteLine(ex.Message.ToString());
return null;
}
}
从 app.config 文件中的名称获取程序集的类型,然后通过创建实例来动态加载程序集。返回创建的实例。
最后,打印结果
Console.WriteLine(businessLogic.GetBusinesslogic());
Console.ReadLine();
历史
- 2010 年 9 月 6 日:初始版本