天天看點

艾偉_轉載:使用AOP動态調用WebService

    在網上搜了一下“動态調用WebService”相信都能搜出上千篇文章,但是都出自同一個版本:使用ServiceDescriptionImporter導入wsdl然後進行動态編譯,再調用相應的Method傳回值。這種方法不足之處就是編譯的時候可能會有些慢,畢竟是編譯整個WebService,而且前台都是使用同一個方法傳入調用的方法來進行調用的。再者,如果使用了Model,引用了WebService後的Model并非此Model,而且如果是List的話,那更差之千裡了,傳回的隻能是數組。

    本人經過思考,用AOP的原理實作了WebService的動态調用,實際上,是調用接口類的方法,然後使用反射得到該方法的傳回值,參數等,然後再構造一個WebService的代理類,動态編譯後調用傳回值。接下來将一一介紹。

    首先定義一個WebService如下。其中使用了FaibClass.Data資料架構。

艾偉_轉載:使用AOP動态調用WebService
艾偉_轉載:使用AOP動态調用WebService

Code

 1 using System;

 2 using System.Web;

 3 using System.Web.Services;

 4 using System.Web.Services.Protocols;

 5 using System.Xml.Serialization;

 6 using Test.Model;

 7 using Test.DA;

 8 using FaibClass.Data;

 9 

10 [WebService(Namespace = "http://tempuri.org/")]

11 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

12 public class Service : System.Web.Services.WebService

13 {

14     public Service () {

15     }

16     [WebMethod]

17     public TCompanyType ATest_GetCompanyType()

18     {

19         ATCompanyType da = new ATCompanyType();

20         da.AccessOptions = AccessOptions.SubEntityList;

21         //排除引用實體屬性

22         da.PropertyFilter = new DebarredAttributes(typeof(ReferenceEntityAttribute));

23         //列出分類

24         return da.Get("Name='大類'", (string[])null);

25     }

26     [WebMethod]

27     public TCompany ATest_GetFirstCompany()

28     {

29         return new ATCompany().Get(null);

30     }

31     [WebMethod]

32     public TCompanies ATest_GetCompanies()

33     {

34         return new ATCompany().Select();

35     }

36     [WebMethod]

37     [XmlInclude(typeof(TCompany))]

38     public bool ATest_Insert(TCompany info)

39     {

40         return true;

41     }

42     [WebMethod]

43     [XmlInclude(typeof(TCompanies))]

44     public bool ATest_InsertAll(TCompanies list)

45     {

46         return true;

47     }

48     [WebMethod]

49     public void ATest_TestNull()

50     {

51     }

52     private void ATest_ListSubType(TCompanyTypes list)

53     {

54         if (list == null) return;

55         foreach (TCompanyType type in list)

56         {

57             //該分類下的公司

58             ATest_ListSubCompany(type.Companies);

59             //該分類下的子類

60             ATest_ListSubType(type.SubCompanyTypes);

61         }

62     }

63 

64     //列出分類公司下面的子公司

65     private void ATest_ListSubCompany(TCompanies companies)

66     {

67         if (companies == null) return;

68         foreach (TCompany company in companies)

69         {

70             ATest_ListSubCompany(company.SubCompanies);

71         }

72     }

73 }

    用戶端也定義一個與之相似的類,暫将它稱為接口類,因為它并不實作操作,隻是為AOP調用提供方法資訊,但是傳回值都為null,即不操作。

艾偉_轉載:使用AOP動态調用WebService
艾偉_轉載:使用AOP動态調用WebService

 2 using System.Collections.Generic;

 3 using System.Text;

 4 using FaibClass.Data;

 5 using Test.Model;

 6 

 7 using FaibClass.Dynamic.WebService;

 8 

 9 namespace Test

10 {

11     [DynamicWebService1("ATest_{0}")]

12     public class ATest : DynamicWebService

13     {

14         public TCompanyType GetCompanyType()

15         {

16             return null;

17         }

18         public TCompany GetFirstCompany()

19         {

20             return null;

21         }

22         public TCompanies GetCompanies()

23         {

24             return null;

25         }

26         public bool Insert(TCompany info)

27         {

28             return false;

29         }

30         public bool InsertAll(TCompanies list)

31         {

32             return true;

33         }

34         public void TestNull()

35         {

36         }

37     }

38 }

    前台調用如下:

艾偉_轉載:使用AOP動态調用WebService
艾偉_轉載:使用AOP動态調用WebService

 1             ATest test = new ATest();

 2             test.TestNull();

 3             TCompanyType type = test.GetCompanyType();

 4             ListSubType(type.SubCompanyTypes);

 5             Console.WriteLine(test.GetFirstCompany().Name);

 6             Console.WriteLine(test.GetCompanies()[0].Name);

 7             TCompany a = new TCompany();

 8             a.Name = "dfdf";

 9             TCompanies list = new TCompanies();

10             list.Add(a);

11             Console.WriteLine(test.InsertAll(list));

12 

    下面将一一對每個類進行說明。

    一、自定義代理屬性 DynamicWebServiceAttribute。 

艾偉_轉載:使用AOP動态調用WebService
艾偉_轉載:使用AOP動态調用WebService

 1 //*******************************************************************

 2 // 子產品:動态WebService屬性的基類

 3 // 日期:2009-8-23 0:24

 4 // 作者:Faib

 5 // 版權:Copyright Faib Studio 2009

 6 // 官網:http://www.faib.net.cn

 7 // 郵箱:[email protected]

 8 // 備注:

 9 //*******************************************************************

10 using System;

11 using System.Runtime.Remoting.Proxies;

12 using System.Runtime.Remoting;

13 using System.Runtime.Remoting.Contexts;

14 using System.Runtime.Remoting.Activation;

15 

16 using FaibClass.Dynamic.Configuration;

17 

18 namespace FaibClass.Dynamic.WebService

19 {

20     /// 

21     /// 動态WebService屬性的基類。

22     /// 

23     [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]

24     public class DynamicWebServiceAttribute : ProxyAttribute

25     {

26         string m_match;

27 

28         public DynamicWebServiceAttribute(string match)

29         {

30             m_match = match;

31         }

32 

33         /// 

34         /// 建立執行個體。

35         /// 

36         /// 

37         /// 

38         public override MarshalByRefObject CreateInstance(Type serverType)

39         {

40             DynamicWebServiceSettings setting = DynamicWebServiceConfiguration.Settings[this.GetType().FullName];

41             //建立初始對象

42             MarshalByRefObject mobj = base.CreateInstance(serverType);

43             if (setting != null)

44             {

45                 RealProxy realProxy = new AspectDynamicWebServiceProxy(setting, m_match, serverType, mobj);

46                 //經過代理後傳回透明代理

47                 return realProxy.GetTransparentProxy() as MarshalByRefObject;

48             }

49             return mobj;

50         }

51 

52         /// 

53         /// 比對符。

54         /// 

55         public string Match

57             get { return m_match; }

58             set { m_match = value; }

59         }

60     }

61 }

62 

    用戶端還要為每一個WebService定義一個DynamicWebServiceAttribute的繼承類,如

艾偉_轉載:使用AOP動态調用WebService
艾偉_轉載:使用AOP動态調用WebService

 4 

 5 using FaibClass.Dynamic.WebService;

 7 namespace Test

 8 {

 9     internal class DynamicWebService1 : DynamicWebServiceAttribute

10     {

11         public DynamicWebService1(string match) : base(match){}

12     }

13 }

14 

    就是ATest上的那個特性,該類再在app.config裡定義相應的webservice調用參數,後面再介紹。這裡的Match你可能發現了,就是webservice裡方法名與ATest裡的比對方式。

    二、代理處理類 AspectDynamicWebServiceProxy 核心就在這裡了

艾偉_轉載:使用AOP動态調用WebService
艾偉_轉載:使用AOP動态調用WebService

  1 //*******************************************************************

  2 // 子產品:動态調用WebService的代理處理類

  3 // 日期:2009-8-23 0:35

  4 // 作者:Faib

  5 // 版權:Copyright Faib Studio 2009

  6 // 官網:http://www.faib.net.cn

  7 // 郵箱:[email protected]

  8 // 備注:

  9 //*******************************************************************

 10 using System;

 11 using System.Text;

 12 using System.Collections;

 13 using System.Collections.Generic;

 14 using System.Runtime.Remoting.Proxies;

 15 using System.Runtime.Remoting.Messaging;

 16 using System.Runtime.Remoting;

 17 using System.Runtime.Remoting.Activation;

 18 using System.Runtime.Remoting.Services;

 19 using System.Web.Services.Description;

 20 using System.Xml;

 21 using System.CodeDom;

 22 using System.CodeDom.Compiler;

 23 using Microsoft.CSharp;

 24 using System.Reflection;

 25 

 26 using FaibClass.Data;

 27 using FaibClass.Dynamic.Configuration;

 28 

 29 namespace FaibClass.Dynamic.WebService

 30 {

 31     /// 

 32     /// 動态調用WebService的代理處理類。

 33     /// 

 34     internal class AspectDynamicWebServiceProxy : RealProxy

 35     {

 36         MarshalByRefObject target;

 37         DynamicWebServiceSettings m_setting;

 38         string m_match;

 39 

 40         /// 

 41         /// 構造代理類。

 42         /// 

 43         /// 

 44         public AspectDynamicWebServiceProxy(Type myType)

 45             : base(myType)

 46         {

 47         }

 48         /// 

 49         /// 構造代理類。

 50         /// 

 51         /// 

 52         /// 

 53         /// 

 54         /// 

 55         public AspectDynamicWebServiceProxy(DynamicWebServiceSettings setting, string match, Type myType, MarshalByRefObject obj)

 56             : base(myType)

 57         {

 58             this.m_setting = setting;

 59             this.m_match = match;

 60             target = obj;

 61         }

 62 

 63         public override IMessage Invoke(IMessage msg)

 64         {

 65             IMessage retMsg = msg;

 66             if (msg is IConstructionCallMessage)

 67             {

 68                 IConstructionCallMessage ccm = (IConstructionCallMessage)msg;

 69                 RemotingServices.GetRealProxy(target).InitializeServerObject(ccm);

 70                 ObjRef oRef = RemotingServices.Marshal(target);

 71                 RemotingServices.Unmarshal(oRef);

 72                 retMsg = EnterpriseServicesHelper.CreateConstructionReturnMessage

 73                     (ccm, (MarshalByRefObject)this.GetTransparentProxy());

 74             }

 75             else if (msg is IMethodCallMessage)

 76             {

 77                 IMethodCallMessage mcm = (IMethodCallMessage)msg;

 78                 MethodInfo minfo = mcm.MethodBase as MethodInfo;

 79                 //調用WebService傳回值

 80                 object result = DyamicCallWebService(minfo, mcm.Args);

 81                 if (result == null)

 82                     retMsg = RemotingServices.ExecuteMessage(target, mcm);

 83                 else

 84                     retMsg = new ReturnMessage(result, null, 0, null, mcm);

 85             }

 86             return retMsg;

 87         }

 88 

 89         /// 

 90         /// 動态調用WebService中的方法。

 91         /// 

 92         /// 方法名。

 93         /// 方法參數。

 94         /// 傳回值。

 95         private object DyamicCallWebService(MethodInfo method, object[] args)

 96         {

 97             Type agentType;

 98             object agent = null;

 99             string[] assemblies = m_setting.Assemblies.Split('|');

100             //調用的方法名

101             string methodName = method.Name;

102             if (!string.IsNullOrEmpty(m_match))

103             {

104                 methodName = string.Format(m_match, methodName);

105             }

106             //緩存鍵

107             string key = DataCacheKeyManager.GetServiceKey(m_setting.Type, method);

108             if (DataCache<object>.ContainsKey(key))

109             {

110                 agent = DataCache<object>.Get(key);

111                 agentType = agent.GetType();

112             }

113             else

114             {

115 

116                 CSharpCodeProvider icc = new CSharpCodeProvider();

117                 CompilerParameters cp = new CompilerParameters();

118                 //引用程式集

119                 cp.ReferencedAssemblies.Add("mscorlib.dll");

120                 cp.ReferencedAssemblies.Add("System.dll");

121                 cp.ReferencedAssemblies.Add("System.Web.Services.dll");

122                 cp.ReferencedAssemblies.Add("System.Xml.dll");

123                 cp.ReferencedAssemblies.Add("FaibClass.Data2.dll");

124                 cp.ReferencedAssemblies.Add("FaibClass.Dynamic.dll");

125                 foreach (string ass in assemblies)

126                 {

127                     cp.ReferencedAssemblies.Add(ass.Split(',')[1].Trim() + ".dll");

128                 }

129 

130                 StringBuilder classSource = new StringBuilder();

131                 //加入引用

132                 classSource.Append("using System;\n");

133                 classSource.Append("using System.Text;\n");

134                 classSource.Append("using System.Web.Services;\n");

135                 classSource.Append("using System.Web.Services.Protocols;\n");

136                 classSource.Append("using System.Web.Services.Description;\n");

137                 classSource.Append("using System.Xml.Serialization;\n");

138                 classSource.Append("using System.Diagnostics;\n");

139                 classSource.Append("using System.ComponentModel;\n");

140                 classSource.Append("using System.CodeDom.Compiler;\n");

141                 classSource.Append("using FaibClass.Data;\n");

142                 classSource.Append("using FaibClass.Dynamic.WebService;\n");

143                 foreach (string ass in assemblies)

144                 {

145                     classSource.Append("using " + ass.Split(',')[0].Trim() + ";\n");

146                 }

147                 classSource.Append("\n");

148                 //定義特性

149                 classSource.Append("[WebServiceBinding(Name = \"ServiceSoap\", Namespace = \"http://tempuri.org/\"), XmlInclude(typeof(MarshalByRefObject)), DesignerCategory(\"code\"), DebuggerStepThrough, GeneratedCode(\"Test\", \"1.0.0.0\")]\n");

150                 classSource.Append("public class DynamicWebService : DynamicSoapHttpClientProtocol\n");

151                 classSource.Append("{\n\tpublic DynamicWebService(){ base.Url = \"" + m_setting.Url + "\"; }");

152                 //方法開始=======

153                 classSource.Append("\n\t[SoapDocumentMethod(\"http://tempuri.org/" + methodName + "\", RequestNamespace = \"http://tempuri.org/\", ResponseNamespace = \"http://tempuri.org/\", Use=SoapBindingUse.Literal, ParameterStyle=SoapParameterStyle.Wrapped)]");

154                 classSource.Append("\n\tpublic ");

155                 //方法傳回類型

156                 if (method.ReturnType.FullName == "System.Void")

157                     classSource.Append("void");

158                 else

159                     classSource.Append(method.ReturnType.Name);

160                 //方法參數

161                 classSource.Append(" " + methodName + "(");

162                 bool first = true;

163                 ParameterInfo[] pinfos = method.GetParameters();

164                 foreach (ParameterInfo pinfo in pinfos)

165                 {

166                     if (!first) classSource.Append(",");

167                     else first = false;

168                     classSource.Append(pinfo.ParameterType.Name + " " + pinfo.Name);

169                 }

170                 //================

171                 classSource.Append(")\n\t{\n\t\t");

172                 if (method.ReturnType.FullName != "System.Void")

173                     classSource.Append("return (" + method.ReturnType.Name + ")");

174                 classSource.Append("base.Invoke(\"" + methodName + "\", ");

175                 if (pinfos.Length == 0)

176                     classSource.Append("new object[0]");

177                 else

178                 {

179                     classSource.Append("new object[]{");

180                     first = true;

181                     foreach (ParameterInfo pinfo in pinfos)

182                     {

183                         if (!first) classSource.Append(",");

184                         else first = false;

185                         classSource.Append(pinfo.Name);

186                     }

187                     classSource.Append("}");

188                 }

189                 classSource.Append(")");

190                 if (method.ReturnType.FullName != "System.Void")

191                     classSource.Append("[0]");

192                 classSource.Append(";\n\t}\n}");

193 

194                 CompilerResults cr = icc.CompileAssemblyFromSource(cp, classSource.ToString());

195                 int c = cr.Errors.Count;

196                 agentType = cr.CompiledAssembly.GetTypes()[0];

197                 agent = Activator.CreateInstance(agentType);

198                 DataCache<object>.Add(key, agent);

199             }

200 

201             if (agent != null)

202             {

203                 return agentType.GetMethod(methodName).Invoke(agent, args);

204             }

205             return null;

206         }

207     }

208 }

209 

    在invoke中,攔截了ATest的調用方法,DyamicCallWebService進行分析并構造WebServicw的代理類代碼,這裡使用了緩存,第一次調用 方法都要經過編譯,以後就不用了。

    三、配置類

DynamicWebServiceSectionHandler

艾偉_轉載:使用AOP動态調用WebService
艾偉_轉載:使用AOP動态調用WebService

 2 // 子產品:WebService配置節的通路

 3 // 日期:2009-8-12 9:22:24

11 using System.Configuration;

12 using System.Xml;

13 

14 namespace FaibClass.Dynamic.Configuration

15 {

16     /// 

17     /// 處理WebService配置節的通路。

18     /// 

19     public sealed class DynamicWebServiceSectionHandler : IConfigurationSectionHandler

20     {

21         /// 

22         /// 建立動态WebService節處理程式

23         /// 

24         /// 父對象。

25         /// 上下檔案對象。

26         /// Xml節點。

27         /// 

28         public object Create(object parent, object configContext, XmlNode section)

30             return new DynamicWebServiceConfiguration(section);

32     }

33 }

34 

DynamicWebServiceConfiguration

艾偉_轉載:使用AOP動态調用WebService
艾偉_轉載:使用AOP動态調用WebService

 2 // 子產品:動态WebService

 3 // 日期:2009-8-23 0:51

11 using System.Xml;

12 using System.Configuration;

17     /// 動态WebService配置。

19     public sealed class DynamicWebServiceConfiguration

21         DynamicWebServiceDictionary m_dic;

22         static DynamicWebServiceDictionary m_dic1;

23 

24         /// 

25         /// 由XmlNode生成執行個體配置集合。

26         /// 

28         internal DynamicWebServiceConfiguration(XmlNode section)

30             if (section == null) throw new ArgumentNullException();

31 

32             m_dic = new DynamicWebServiceDictionary();

33             foreach (XmlNode node in section.SelectNodes("webservice"))

34             {

35                 string type = node.Attributes["type"] != null ? node.Attributes["type"].Value : "";

36                 string url = node.Attributes["url"] != null ? node.Attributes["url"].Value : "";

37                 string assemblies = node.Attributes["assemblies"] != null ? node.Attributes["assemblies"].Value : "";

38                 if (!string.IsNullOrEmpty(type) && !string.IsNullOrEmpty(url))

39                 {

40                     m_dic.Add(type, new DynamicWebServiceSettings(type, url, assemblies));

41                 }

42             }

43         }

44 

45         internal DynamicWebServiceDictionary settings

46         {

47             get { return m_dic; }

48         }

49 

50         public static DynamicWebServiceDictionary Settings

51         {

52             get

53             {

54                 if (m_dic1 == null)

55                 {

56                     object obj = ConfigurationManager.GetSection("faibclass.dynamic.webService");

57                     if (obj != null)

58                     {

59                         m_dic1 = ((DynamicWebServiceConfiguration)obj).settings;

60                     }

61                 }

62                 return m_dic1;

63             }

64         }

65     }

66 }

67 

DynamicWebServiceDictionary

艾偉_轉載:使用AOP動态調用WebService
艾偉_轉載:使用AOP動态調用WebService

 2 // 子產品:動态WebService配置字典

 3 // 日期:2009-8-12 9:21:05

11 using System.Collections;

13 namespace FaibClass.Dynamic.Configuration

14 {

15     /// 

16     /// 動态WebService配置字典。

17     /// 

18     public class DynamicWebServiceDictionary : DictionaryBase

19     {

20         internal void Add(string key, DynamicWebServiceSettings setting)

21         {

22             Dictionary.Add(key, setting);

23         }

24 

25         /// 

26         /// 擷取本字典内的鍵集合。

28         public ICollection Keys

30             get { return Dictionary.Keys; }

34         /// 由鍵名傳回對應的配置資訊。

38         public DynamicWebServiceSettings this[string key]

40             get 

41             {

42                 if (Dictionary.Contains(key))

43                 {

44                     return (DynamicWebServiceSettings)Dictionary[key];

45                 }

46                 return null;

47             }

49     }

50 }

DynamicWebServiceSettings

艾偉_轉載:使用AOP動态調用WebService
艾偉_轉載:使用AOP動态調用WebService

 2 // 子產品:動态WebService配置資訊

 3 // 日期:2009-8-23 0:12

11 using System.Collections.Generic;

12 using System.Text;

17     /// 動态WebService配置資訊。

19     public class DynamicWebServiceSettings

22         /// 處理類型

24         public string Type;

26         /// WebService位址

28         public string Url;

29         /// 

30         /// 引用程式集

31         /// 

32         public string Assemblies;

33 

34         public DynamicWebServiceSettings(string type, string url, string assemblies)

36             Type = type;

37             Url = url;

38             Assemblies = assemblies;

39         }

40     }

41 }

42 

    ap.config配置如下

艾偉_轉載:使用AOP動态調用WebService
艾偉_轉載:使用AOP動态調用WebService

xml version="1.0" encoding="utf-8" ?>

<configuration>

  <configSections>

    <section name="faibclass.data.instance" type="FaibClass.Data.Configuration.DataInstanceSectionHandler, FaibClass.Data2" />

    <section name="faibclass.dynamic.webService" type="FaibClass.Dynamic.Configuration.DynamicWebServiceSectionHandler, FaibClass.Dynamic"/>

  configSections>

  <faibclass.dynamic.webService>

    <webservice type="Test.DynamicWebService1" url="http://localhost:1574/WebService/Service.asmx" assemblies="Test.Model, Model" />

  faibclass.dynamic.webService>

  <faibclass.data.instance defaultInstance="sqlite">

    

    <file name="access1">

      <instanceType>FaibClass.Data.OleDb, FaibClass.Data2instanceType>

      <filename>{APP}\1.xmlfilename>

      <path>//config/connectionpath>

    file>

    <file name="access2">

      <interfaceType>SysXmlinterfaceType>

      <filename>1.xmlfilename>

    <file name="access3">

      <interfaceType>AppXmlinterfaceType>

      <path>constrpath>

    <reg name="sqlserver">

      <instanceType>FaibClass.Data.SqlServer, FaibClass.Data2instanceType>

      <registryKey>CurrentUserregistryKey>

      <subKey>Software\MicrosoftsubKey>

      <key>ckey>

    reg>

    <file name="sqlserver2005">

      <interfaceType>BinaryinterfaceType>

      <filename>{APP}\connection.binfilename>

      <path>Chinapath>

    <string name="sqlite">

      <instanceType>FaibClass.Data.DataDriverConverter, FaibClass.Data2instanceType>

      <dataDriver>

        <assemblyName>System.Data.SQLiteassemblyName>

        <connectionType>System.Data.SQLite.SQLiteConnectionconnectionType>

        <commandType>System.Data.SQLite.SQLiteCommandcommandType>

        <parameterType>System.Data.SQLite.SQLiteParameterparameterType>

        <dataAdapterType>System.Data.SQLite.SQLiteDataAdapterdataAdapterType>

        <parameterPrefix>@parameterPrefix>

      dataDriver>

      <connectionString>Data source={App}BitracDB.db3;Pooling=TrueconnectionString>

    string>

  faibclass.data.instance>

  <appSettings>

    <add key="constr" value="Provider=Microsoft.Jet.OLEDB.4.0;Data Source={App}\test.mdb">add>

  appSettings>

configuration>

繼續閱讀