65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (1投票)

2010年9月8日

CPOL

4分钟阅读

viewsIcon

41092

downloadIcon

490

展示了 .NET 如何通过延迟绑定和反射的强大功能,根据实际需要,在运行时加载程序集的能力。

目标

本文旨在展示 .NET 如何通过延迟绑定和反射的强大功能,根据实际需要,在运行时加载程序集的能力。

引言

在典型的 N 层应用程序中,我们有

  1. 表示层 – 构成应用程序的用户界面
  2. 应用程序层 – 处理业务逻辑
  3. 数据访问层 – 与数据库交互

通常,这三层是完全独立的,通过程序集引用进行调用。表示层可以与业务层完全分离,并且完全不知道其功能和数据类型。它只关心业务层提供的数据。此外,业务层可以服务于一个以上的表示层(Web、Windows 等),前提是它们知道如何调用它。

当存在一个以上的表示层调用多个业务层时,情况就会变得有趣。处理这种情况的优化方法是什么?

让我们通过一个例子来理解这个问题。

考虑一家养老金公司 IT 基础设施 – ABC Pension。ABC Pension 为其 100 多家客户的员工计算养老金福利。每位客户根据其需求有不同的养老金计算规则。ABC Pension 必须通过单一 IT 基础设施为所有客户提供养老金信息。

让我们考虑它有两种用户界面表示层

  1. 基于 Java 的网站 – 用户可以通过其凭据登录并查看其账户
  2. 桌面应用程序 – 由电话代表使用,当客户拨打公司免费帮助热线电话时,他们会接听。这可以是 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 ——抽象。它包含

  1. 抽象类 – AbstractBusinessLogic
    namespace BusinessLogicLibrary
    {
        public abstract class AbstractBusinessLogic: IBusinessLogic
        {
            virtual public string GetBusinesslogic()
            {
                throw new NotImplementedException();
            }        
        }
    }
  2. 接口 – 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。

首先,添加对以下项的程序集引用

  1. System.Configuration
  2. BusinessLogicLibrary
  3. BusinessLogic-1
  4. BusinessLogic-2
  5. 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 日:初始版本
© . All rights reserved.