现在很多项目都须要为将来的扩展考虑,当然数据库也是一个很重我要的方面,扩展自己的Provider,这就需要反射技术,虽然会对性能有所影响,但是性价比还是很高的哦,从PetShop和CommunityServer都可以看到反射技术啦,也可以说反射是最基本的啦,呵呵!他的老家是在System.Reflection,当我们要开工时首先就是要把他抓出来.
现在很多项目都须要为将来的扩展考虑,当然数据库也是一个很重我要的方面,扩展自己的Provider,这就需要反射技术,虽然会对性能有所影响,但是性价比还是很高的哦,从PetShop和CommunityServer都可以看到反射技术啦,也可以说反射是最基本的啦,呵呵!他的老家是在System.Reflection,当我们要开工时首先就是要把他抓出来.
要实现这一功能我们当然要知道Provider的程序集,和工作的类名了,在多层架够中才能让逻辑和数据进行沟通,这样也方便团队开发的协条款发展,我们通过PetShop和CommunityServer两个例子来说明一下.
我们先看看PetShop的反射技术,在配制文件中发现如下配制:
<!-- Pet Shop DAL configuration settings -->
<add key="WebDAL" value="PetShop.SQLServerDAL"/>
<add key="OrdersDAL" value="PetShop.SQLServerDAL"/>
<add key="ProfileDAL" value="PetShop.SQLProfileDAL"/>
其实只从配制文件中得到程序集名称,一般程序集就是类所在命名空间,也就是编译后显示的DLL名称,那PetShop是怎样工作的,下面我们来看一下DataAccess类,这也可说成一个工厂,呵呵,我们来看一下代码:
1
using System.Reflection;
2
using System.Configuration;
3
4
namespace PetShop.DALFactory
{
5
6
/**//// <summary>
7
/// This class is implemented following the Abstract Factory pattern to create the DAL implementation
8
/// specified from the configuration file
9
/// </summary>
10
public sealed class DataAccess
{
11
12
// Look up the DAL implementation we should be using
13
private static readonly string path = ConfigurationManager.AppSettings["WebDAL"];
14
private static readonly string orderPath = ConfigurationManager.AppSettings["OrdersDAL"];
15
16
private DataAccess()
{ }
17
18
public static PetShop.IDAL.ICategory CreateCategory()
{
19
string className = path + ".Category";
20
return (PetShop.IDAL.ICategory)Assembly.Load(path).CreateInstance(className);
21
}
22
23
public static PetShop.IDAL.IInventory CreateInventory()
{
24
string className = path + ".Inventory";
25
return (PetShop.IDAL.IInventory)Assembly.Load(path).CreateInstance(className);
26
}
27
28
public static PetShop.IDAL.IItem CreateItem()
{
29
string className = path + ".Item";
30
return (PetShop.IDAL.IItem)Assembly.Load(path).CreateInstance(className);
31
}
32
33
public static PetShop.IDAL.IOrder CreateOrder()
{
34
string className = orderPath + ".Order";
35
return (PetShop.IDAL.IOrder)Assembly.Load(orderPath).CreateInstance(className);
36
}
37
38
public static PetShop.IDAL.IProduct CreateProduct()
{
39
string className = path + ".Product";
40
return (PetShop.IDAL.IProduct)Assembly.Load(path).CreateInstance(className);
41
}
42
43
}
44
}
其中(PetShop.IDAL.IProduct)Assembly.Load(path).CreateInstance(className);就是将类进行反射,首先要载入程序集,然后再创进类实例,通过静态方法就可以直接调用接口的方法等,从而实现了继承接口的类的反射,同时也方便表现层的数据传输.
下面我们来看一下CommunityServer是怎么实现的,CS是一个大象极别的项目,所以他有很自己扩展Provider,那怎么样才能让他们工作呢?其实原理和上述的反射方法差不多,只不过CS用的是Object.GetTyp()而达到这项功能.当我第一次看到时,还一直为怎样传输ConnectionString&DataOwner而不解,后来打开源数据看了一下各个方法的注解后才理解.
CS从自定的配制文件中读取Provider节点并缓存,这在CSConfiguration类中可以发现,在DataProviders类中就实现反射,通过能构造函数的反射查找最匹配的构造函数对类进行实例化,当然当他们遇到有ConnectionString&DataOwner两参数的构造函数时,就对其进行实例化,从而达到对他们值的传输.

DataProviders
1
//------------------------------------------------------------------------------
2
// <copyright company="Telligent Systems">
3
// Copyright (c) Telligent Systems Corporation. All rights reserved.
4
// </copyright>
5
//------------------------------------------------------------------------------
6
7
using System;
8
using System.Configuration;
9
using System.IO;
10
using System.Reflection;
11
using System.Web;
12
using CommunityServer.Configuration;
13
14
namespace CommunityServer.Components
15

{
16
/**//// <summary>
17
/// DataProviders is responible for loading and managing the various CS DataProviders
18
/// </summary>
19
public sealed class DataProviders
20
{
21
/**//// <summary>
22
/// This class can not be instantiated
23
/// </summary>
24
private DataProviders()
25
{
26
}
27
28
private static void GetDataStoreParameters(Provider dataProvider, out string connectionString, out string databaseOwner)
29
{
30
databaseOwner = dataProvider.Attributes["databaseOwner"];
31
if(databaseOwner == null || databaseOwner.Trim().Length == 0)
32
databaseOwner = ConfigurationSettings.AppSettings[dataProvider.Attributes["databaseOwnerStringName"]];
33
34
connectionString = dataProvider.Attributes["connectionString"];
35
if(connectionString == null || connectionString.Trim().Length == 0)
36
connectionString = ConfigurationSettings.AppSettings[dataProvider.Attributes["connectionStringName"]];
37
}
38
39
/**//// <summary>
40
/// Creates an instance of the provider using Activator. This instance should be
41
/// cached since it is an expesivie operation
42
/// </summary>
43
public static object CreateInstance(Provider dataProvider)
44
{
45
//Find the current attributes
46
string connectionString = null; //dataProvider.Attributes["connectionString"];
47
string databaseOwner = null;// dataProvider.Attributes["databaseOwner"];
48
49
GetDataStoreParameters(dataProvider, out connectionString, out databaseOwner);
50
51
//Get the type
52
Type type = Type.GetType(dataProvider.Type);
53
54
object newObject = null;
55
if(type != null)
56
{
57
newObject = Activator.CreateInstance(type,new object[]
{databaseOwner,connectionString});
58
}
59
60
if(newObject == null) //If we can not create an instance, throw an exception
61
ProviderException(dataProvider.Name);
62
63
return newObject;
64
}
65
66
/**//// <summary>
67
/// Creates and Caches the ConstructorInfo for the specified provider.
68
/// </summary>
69
public static ConstructorInfo CreateConstructorInfo (Provider dataProvider)
70
{
71
72
// The assembly should be in \bin or GAC, so we simply need
73
// to get an instance of the type
74
//
75
CSConfiguration config = CSConfiguration.GetConfig();
76
ConstructorInfo providerCnstr = null;
77
try
78
{
79
//string providerTypeName = ((Provider) config.Providers[providerName]).Type;
80
Type type = Type.GetType( dataProvider.Type );
81
82
// Insert the type into the cache
83
//
84
Type[] paramTypes = new Type[2];
85
paramTypes[0] = typeof(string);
86
paramTypes[1] = typeof(string);
87
88
providerCnstr = type.GetConstructor(paramTypes);
89
90
}
91
catch
92
{
93
ProviderException(dataProvider.Name);
94
}
95
96
if(providerCnstr == null)
97
ProviderException(dataProvider.Name);
98
99
return providerCnstr;
100
}
101
102
/**//// <summary>
103
/// Creates an instance of the specified provider using the Cached
104
/// ConstructorInfo from CreateConstructorInfo
105
/// </summary>
106
public static object Invoke(Provider dataProvider)
107
{
108
object[] paramArray = new object[2];
109
110
111
string dbOwner = null;
112
string connstring = null;
113
114
GetDataStoreParameters(dataProvider, out connstring, out dbOwner);
115
116
paramArray[0] = dbOwner;
117
paramArray[1] = connstring;
118
119
return CreateConstructorInfo(dataProvider).Invoke(paramArray);
120
}
121
122
Exception#region Exception
123
private static void ProviderException(string providerName)
124
{
125
CSConfiguration config = CSConfiguration.GetConfig();
126
HttpContext context = HttpContext.Current;
127
if (context != null)
128
{
129
130
// We can't load the dataprovider
131
//
132
StreamReader reader = new StreamReader( context.Server.MapPath("~/Languages/" + config.DefaultLanguage + "/errors/DataProvider.htm") );
133
string html = reader.ReadToEnd();
134
reader.Close();
135
136
html = html.Replace("[DATAPROVIDERCLASS]", providerName);
137
html = html.Replace("[DATAPROVIDERASSEMBLY]", providerName);
138
context.Response.Write(html);
139
context.Response.End();
140
}
141
else
142
{
143
throw new CSException(CSExceptionType.DataProvider, "Unable to load " + providerName);
144
}
145
}
146
#endregion
147
}
148
}
文章是越写越不知道写些什么?CS有很多人研究他,应该会有关于这样的文章,不多说了,呵呵.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架