使用 .NET Enterprise Library 创建自定义应用程序块





5.00/5 (1投票)
本白皮书旨在帮助开发人员使用 .NET Enterprise Library 创建自定义应用程序块。
目录
- 引言
- 必备组件
- .NET Enterprise Library 2.0 命名空间
- 技术设计规范
- 创建自定义应用程序块
- Page_Load
- 构建 Web.config 文件
- 为类库 DLL 生成公钥令牌
- 参考
- 结论
引言
我曾从事 spring.NET 框架的工作,并且长期以来一直深入研究 .NET Enterprise Library。每次使用这些框架时,我都会感受到它们之间强烈的相似性。随着时间的推移,微软几乎涵盖了 spring.net 框架通常为开发人员提供的 .NET Framework 中的所有内容。我只能说,微软紧跟最新技术,并希望与时俱进。正是 spring.NET 给了主页的概念和演变,同样,我们也有自定义应用程序块,它体现了依赖注入和面向切面编程的思想。在这里,我将不描述 spring .NET 和 .NET Enterprise Library 的相似之处或区别。我的目的是帮助开发人员使用 .NET Enterprise Library 实现和开发自定义应用程序块。网上可能有各种文章,但我希望在本课程的这一部分展示我的发现。我们都知道依赖注入设计模式,它已不再是新话题。简而言之,依赖注入通过对象的构造函数隔离对象的实现,并在运行时调用和创建对象,从而允许以最简单、最松耦合的方式灵活操作。它是控制反转模式的一种形式,其中工厂对象负责对象创建、链接和加载,进而形成运行时对象创建和调用的实例化。
我在这里将展示如何使用 .NET Enterprise Library 创建自定义应用程序块,它能够很好地演示依赖注入的概念。所有类和命名空间都将在配置文件中配置,从而在运行时链接和加载。这是一种需求调用方法。
自定义应用程序块
这种方法最好的地方在于,我们可以在同一个环境中测试和开发同一个项目集下的模块。更广泛地说,我们可以配置自定义应用程序块,以便测试人员可以在同一台机器上测试应用程序,而开发人员则可以在同一台机器上修复或开发。
例如:我有一个 fileUploaderModule
包,为了让我的团队的生活更轻松,我会怎么做?我会创建两个包,一个包是 fileUploaderModule_test
,另一个包是 fileUploaderModule_Dev
,并在配置文件中配置它们,这将帮助测试人员和开发人员在同一工作包上并行工作。这样我就能节省应用程序额外的测试服务器。这种方法将帮助我在同一台机器上为两个角色进行测试和开发。
拥有这种设计设计的另一个用途是利用组织中跨项目/应用程序的基于能力的资产,从而提高生产力,因为它可以在开发级别上作为全局功能需求使用。
例如,我有一个被组织中 10 个应用程序使用的登录机制。在这种情况下,我将开发一个登录自定义应用程序块,该应用程序块将由 10 个跨应用程序使用,使该块成为一个独立的实体并充当服务提供商。
在考虑了上述措施后,我们得出结论,在设计方面我们将获得以下优势。
- 松耦合架构
- 可作为库跨项目重用
- 易于测试,因为它是自定义打包设计
- 易于维护
- 易于部署,因为自定义打包可在配置文件中配置
问题陈述:我需要通过文件传输系统端口将文件上传到服务器。因此,这里的挑战在于,服务器详细信息必须是可配置的,因为该服务器将来可能会更改。此外,此包应开发成可供不同应用程序使用,并具有易于插入的功能。
必备组件
- .NET Framework 2.0
- Enterprise Library 2.0
.NET Enterprise Library 2.0 命名空间
- Microsoft.Practices.EnterpriseLibrary.Common.dll
- Microsoft.Practices.ObjectBuilder.dll
技术设计规范
在这里,我将演示默认设置配置块和特定设置配置块部分。它的工作方式类似于默认构造函数和参数化构造函数。如果我们不提供提供程序名称,则它会选择默认设置,否则它会根据提供程序名称选择设置。为了更直观和易于理解,请参阅顺序图和红色文本。
图 1.0 顺序图:默认设置
<dbConfiguration defaultDBProvider="DefaultFilePath">
<dbProviders>
<add name="DefaultFilePath"
type="Project.Practice.DB.DBProvider,Project.Practice.DB" userID="admin"
password="admin" server="militaryZoneArea" database="xyz"/>
</dbConfiguration>

图 2.0 顺序图:自定义设置
<add name="CustomFilePath"
type="Project.Practice.DB.DBProvider,Project.Practice.DB" userID="admin"
password="admin" server="militaryZoneArea" database="xyz"/>
</dbProviders>

创建自定义应用程序块
让我们深入研究代码以获得更多理解。我们创建 DBAssembler
,它实现了 IAssembler
。这是我们使用可配置的 DBdata
设置详细信息创建 DbProvider
对象的终结点。在完整的往返过程中,会创建 DBProvider
对象并调用 UploadFile()
方法。
设计配置提供程序
DBAssembler.cs
public class DBAssembler : IAssembler <IDBProvider, DBData>
{
public IDBProvider Assemble
(Microsoft.Practices.ObjectBuilder.IBuilderContext context,
DBData dbData, IConfigurationSource configurationSource,
ConfigurationReflectionCache reflectionCache)
{
return new DBProvider(dbData.UserId, dbData.Password,
dbData.Server, dbData.Database);
}
}
DBData.cs
此类是所有配置设置的容器对象。
[Assembler(typeof(DBAssembler))]
public class DBData : NameTypeConfigurationElement
{
private const string userIdProperty = "userID";
private const string passwordProperty = "password";
private const string serverProperty = "server";
private const string databaseProperty = "database";
public DBData()
: base("DBData", typeof(IDBProvider))
{
}
public DBData(string name, Type type)
: base(name, type)
{
}
[ConfigurationProperty(userIdProperty, IsRequired = true)]
public string UserId
{
get { return (string)this[userIdProperty]; }
set { this[userIdProperty] = value; }
}
[ConfigurationProperty(passwordProperty, IsRequired = true)]
public string Password
{
get { return (string)this[passwordProperty]; }
set { this[passwordProperty] = value; }
}
[ConfigurationProperty(serverProperty, IsRequired = true)]
public string Server
{
get { return (string)this[serverProperty]; }
set { this[serverProperty] = value; }
}
[ConfigurationProperty(databaseProperty, IsRequired = false)]
public string Database
{
get { return (string)this[databaseProperty]; }
set { this[databaseProperty] = value; }
}
}
DBDataRetriever.cs
编写 DBretriever
是为了能够根据调用链接和加载默认配置节。
internal class DBDataRetriever : IConfigurationNameMapper
{
public string MapName(string name, IConfigurationSource configurationSource)
{
return string.IsNullOrEmpty(name) == false ?
name : ((DBSettings)configurationSource.GetSection(DBSettings.SectionName)).
DefaultDBProvider;
}
}
DBSettings.cs
public class DBSettings : SerializableConfigurationSection
{
public const string SectionName = "dbConfiguration";
private const string DBProvidersProviderProperty = "dbProviders";
private const string DefaultDBProviderProperty = "defaultDBProvider";
public DBSettings() { }
[ConfigurationProperty(DBProvidersProviderProperty, IsRequired = true)]
public NameTypeConfigurationElementCollection <DBData> DBProviders
{
get { return (NameTypeConfigurationElementCollection
<DBData>)base[DBProvidersProviderProperty]; }
}
[ConfigurationProperty(DefaultDBProviderProperty, IsRequired = true)]
public string DefaultDBProvider
{
get { return (string)base[DefaultDBProviderProperty]; }
}
}
设计工厂和提供程序类
DBFactory.cs
DBFactory
是创建 DBProviderFactory
的类,之后当调用默认设置时,它会发挥重要作用,并调用 CreateDefault()
来继续承担责任,或者调用 Create()
来处理自定义设置调用。有关详细信息,请参阅顺序图。
public static class DBFactory
{
public static IDBProvider CreateProvider()
{
try
{
DBProviderFactory factory =
new DBProviderFactory(ConfigurationSourceFactory.Create());
return factory.CreateDefault();
}
catch (ConfigurationErrorsException configurationException)
{
throw;
}
}
public static IDBProvider CreateProvider( string name )
{
try
{
DBProviderFactory factory =
new DBProviderFactory( ConfigurationSourceFactory.Create() );
return factory.Create( name );
}
catch( ConfigurationErrorsException configurationException )
{
throw;
}
}
}
DBCustomFactory.cs
通过查看顺序图可以最好地解释和理解这一点。基本上,当未调用默认设置时,会调用 DBCustomfactory
。DBCustomFactory
获取所有配置并将它们设置在 DBData
中,然后将 DBData
返回给 DBassembler
。
public class DBCustomFactory : AssemblerBasedCustomFactory <IDBProvider, DBData>
{
protected override DBData GetConfiguration
(string name, IConfigurationSource configurationSource)
{
DBSettings settings =
(DBSettings)configurationSource.GetSection(DBSettings.SectionName);
return settings.DBProviders.Get(name);
}
}
DBProvider.cs
DBProvider
实现了 IDBProvider
并设置在config文件中配置的值。在构造函数中设置值的责任由 DBsetting
类承担。
[ConfigurationElementType(typeof(DBData))]
public class DBProvider : IDBProvider
{
protected string m_UserId = string.Empty;
protected string m_Password = string.Empty;
protected string m_Server = string.Empty;
protected string m_DirectoryPath = string.Empty;
private bool m_Disposed = false;
public DBProvider() { }
public DBProvider
(string userId, string password, string server, string directoryPath)
{
m_UserId = userId;
m_Password = password;
m_Server = server;
m_DirectoryPath = directoryPath;
}
#region IFTPProvider Interface
bool IDBProvider.UploadFile(string filePath)
{
//The functionality is not given here..
//Intension here is one can make use of these configurable credential
//Connect to FTP and transfer file.
//OpenFTP(m_Server,m_UserId,m_Password,m_DirectoryPath,
//filePath,domain,port)
return true;
}
}
DBProviderFactory.cs
public class DBProviderFactory : NameTypeFactoryBase <IDBProvider>
{
protected DBProviderFactory()
: base()
{
}
public DBProviderFactory(IConfigurationSource configurationSource)
: base(configurationSource)
{ }
}
IDBProvider.cs
IDBProvider
基本上存储了自定义属性的集合,我们在其中声明了默认和自定义设置类。它还公开了可供客户端接口使用的方法列表。
[ConfigurationNameMapper(typeof(DBDataRetriever))]
[CustomFactory(typeof(DBCustomFactory))]
public interface IDBProvider : IDisposable
{
bool UploadFile(string filePath );
}
Page_Load
这是调用运行时对象实例的入口点,在此,工厂对象负责对象创建。因此,DBFactory.CreateProvider()
用于默认设置,而 DBFactory.CreateProvider("CustomFilePath"))
用于自定义设置。
protected void Page_Load(object sender, EventArgs e)
{
using (IDBProvider dbProvider = DBFactory.CreateProvider())
{
Response.Write(dbProvider.UploadFile("abc"));
}
using (IDBProvider dbProvider = DBFactory.CreateProvider("CustomFilePath"))
{
Response.Write(dbProvider.UploadFile("xyz"));
}
}
构建 Web.config 文件
如果您查看配置设置,我们有默认配置“DefaultFilePath
”。如果我们不指定自定义文件路径,它将使用默认设置。这种配置设置在测试特定模块时非常有用。由于开发服务器的安全原因,我们无法访问与实际生产服务器类似的功能;在这种情况下,我们可以根据本地机器配置我们的设置,从而帮助我们测试模块并模拟实际环境。
<configSections>
<section name="dbConfiguration"
type="Project.Practice.DB.Configuration.DBSettings,Project.Practice.DB,
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=e6353c372c56789" allowDefinition="Everywhere"
allowExeDefinition="MachineToApplication" restartOnExternalChanges="true"/>
</configSections>
<!-- DB Configuration -->
<dbConfiguration defaultDBProvider="DefaultFilePath">
<dbProviders>
<add name="DefaultFilePath"
type="Project.Practice.DB.DBProvider,Project.Practice.DB" userID="admin"
password="admin" server="militaryZoneArea" database="xyz"/>
<add name="CustomFilePath"
type="Project.Practice.DB.DBProvider,Project.Practice.DB" userID="admin"
password="admin" server="militaryZoneArea" database="xyz"/>
</dbProviders>
</dbConfiguration>
为类库 DLL 生成公钥令牌
可以使用以下步骤为上述配置创建公钥。转到 Visual Studio 命令提示符并运行以下命令:
D:\SampleCustomBlock\bin\Debug>sn -T Project.Practice.DB.dll
Microsoft (R) .NET Framework 强签名工具 版本 2.0.50727.42 版权所有 (C) Microsoft Corporation。保留所有权利。
公钥令牌为 exxx78fd9i34545。确保您已为给定的 DLL 创建了强密钥。如果不需要公钥,则可以指定 public key=null
。
参考
- http://www.castleproject.org/
- http://www.springframework.net/examples.html
- https://martinfowler.com.cn/articles/injection.html
结论
如果您在运行演示代码时遇到问题,请给我留言。我会尽力帮助您。欢迎对本文提出任何建议或更新。