很少用C#動態的去調用Web Service,一般都是通過添加引用的方式,這樣的話是自動成了代理,那么動態代理調用就是我們通過代碼去調用這個WSDL,然后自己去生成客戶端代理。更多的內容可以看下面的兩個地址:
http://blog.csdn.net/limlimlim/article/details/8651043
http://www.cnblogs.com/VisualStudio/archive/2008/10/29/1322228.html
1.動態調用的url后面注意一定要加上?WSDL
例如:string _url = "http://服務器IP:端口/CITI_TRANS_WH/wsTransData_InWH.asmx?WSDL";
---------------------------------------------------------------------------------------------------
2.WebService中傳遞List泛型對象
[WebMethod]
public List<TestModel> TestTransDataByClass(int _max)
注意TestModel必須是可以序列化的類
//必須可序列化
[Serializable]
public class TestModel
{
public int No
{
get;
set;
}
public string Des
{
get;
set;
}
}
---------------------------------------------------------------------------------------------------
3.WebService中不能直接傳遞輸出dictionary<string,object>這樣的泛型對象,必須自定義一個類來輸出,這個類同樣也是可以序列化的
[Serializable]
public class MyDictionary
{
public List<TestModel> Table1
{
get;
set;
}
public List<TestModel2> Table2
{
get;
set;
}
}
---------------------------------------------------------------------------------------------------
4.動態調用WebService的類封裝
public static class InvokeWebServiceDynamic
{
/// <summary>
/// 動態調用WebService
/// </summary>
/// <param name="_url">web服務url地址</param>
/// <param name="_methodName">web服務中的方法</param>
/// <param name="_params">傳遞給方法的參數</param>
/// <returns></returns>
public static object InvokeWebMethod(string _url ,string _methodName,
params object[] _params)
{
WebClient client = new WebClient();
//String url = "http://localhost:3182/Service1.asmx?WSDL";//這個地址可以寫在Config文件里面
Stream stream = client.OpenRead(_url);
ServiceDescription description = ServiceDescription.Read(stream);
ServiceDescriptionImporter importer = new ServiceDescriptionImporter();//創建客戶端代理代理類。
importer.ProtocolName = "Soap"; //指定訪問協議。
importer.Style = ServiceDescriptionImportStyle.Client; //生成客戶端代理。
importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties |
CodeGenerationOptions.GenerateNewAsync;
importer.AddServiceDescription(description, null, null); //添加WSDL文檔。
CodeNamespace nmspace = new CodeNamespace(); //命名空間
nmspace.Name = "TestWebService"; //這個命名空間可以自己取
CodeCompileUnit unit = new CodeCompileUnit();
unit.Namespaces.Add(nmspace);
ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters parameter = new CompilerParameters();
parameter.GenerateExecutable = false;
parameter.OutputAssembly = "MyTest.dll";//輸出程序集的名稱
parameter.ReferencedAssemblies.Add("System.dll");
parameter.ReferencedAssemblies.Add("System.XML.dll");
parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
parameter.ReferencedAssemblies.Add("System.Data.dll");
CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);
if (result.Errors.HasErrors)
{
// 顯示編譯錯誤信息
}
Assembly asm = Assembly.LoadFrom("MyTest.dll");//加載前面生成的程序集
Type t = asm.GetType("TestWebService.wsTransData_InWH"); //前面的命名空間.類名,類必須是webservice中定義的
object o = Activator.CreateInstance(t);
MethodInfo method = t.GetMethod(_methodName);//GetPersons是服務端的方法名稱,你想調用服務端的什么方法都可以在這里改,最好封裝一下
object item = method.Invoke(o, _params); //注:method.Invoke(o, null)返回的是一個Object,如果你服務端返回的是DataSet,這里也是用(DataSet)method.Invoke(o, null)轉一下就行了
//foreach (string str in item)
// Console.WriteLine(str); //上面是根據WebService地址,模似生成一個代理類,如果你想看看生成的代碼文件是什么樣子,可以用以下代碼保存下來,默認是保存在bin目錄下面
//TextWriter writer = File.CreateText("MyTest.cs");
//provider.GenerateCodeFromCompileUnit(unit, writer, null);
//writer.Flush();
//writer.Close();
return item;
}
}
---------------------------------------------------------------------------------------------------
5.通過反射提取web方法返回的自定義類數據
說明:
<1>.WebService方法TestTransDataByDic返回自定義的MyDictionary對象
<2>.它包含兩個屬性table1,table2
<3>.類定義代碼如下
[Serializable]
public class MyDictionary
{
public List<TestModel> Table1
{
get;
set;
}
public List<TestModel2> Table2
{
get;
set;
}
}
<4>.客戶端調用代碼
private void InvokeDic_Click(object sender, EventArgs e)
{
//要注意加?WSDL
//string _url = "http://localhost:58764/wsTransData_InWH.asmx?WSDL";
int _count = int.Parse(txtCount.Text);
object o = InvokeWebServiceDynamic.InvokeWebMethod(_url, "TestTransDataByDic",
new object[] { _count });
PropertyInfo _propertyTable1 = o.GetType().GetProperty("Table1");
PropertyInfo _propertyTable2 = o.GetType().GetProperty("Table2");
//讀取Table1屬性中的數據
object[] _table1Items = (object[])_propertyTable1.GetValue(o, null);
if(_table1Items.Length>0)
{
lstData1.Visible = false;
lstData1.Items.Clear();
//反射出對象TestModel的屬性
PropertyInfo _propertyNo = _table1Items[0].GetType().GetProperty("No");
PropertyInfo _propertyDes = _table1Items[0].GetType().GetProperty("Des");
for (int i = 0; i < _table1Items.Length; i++)
{
//根據屬性取值
string _no = _propertyNo.GetValue(_table1Items[i], null).ToString();
string _des = _propertyDes.GetValue(_table1Items[i], null).ToString();
string _format = string.Format("第{0}條:{1}", _no, _des);
lstData1.Items.Add(_format);
}
lstData1.Visible = true;
}
//讀取Table2屬性中的數據
object[] _table2Items = (object[])_propertyTable2.GetValue(o, null);
if (_table2Items.Length > 0)
{
lstData2.Visible = false;
lstData2.Items.Clear();
//反射出對象TestModel2的屬性
PropertyInfo _propertyMyFNo = _table2Items[0].GetType().GetProperty("MyFNo");
PropertyInfo _propertyMyFDes = _table2Items[0].GetType().GetProperty("MyFDes");
for (int i = 0; i < _table1Items.Length; i++)
{
//根據屬性取值
string _no = _propertyMyFNo.GetValue(_table2Items[i], null).ToString();
string _des = _propertyMyFDes.GetValue(_table2Items[i], null).ToString();
string _format = string.Format("第{0}條:{1}", _no, _des);
lstData2.Items.Add(_format);
}
lstData2.Visible = true;
}
MessageBox.Show("OK");
}
---------------------------------------------------------------------------------------------------
6.客戶端傳遞序列化對象給webserice方法
/// <summary>
///
/// </summary>
/// <param name="_dicGet">是一個客戶端傳過來的序列化的對象</param>
/// <returns></returns>
[WebMethod]
public string TestInsertData(byte[] _dicGet)
{
//反序列化對象
object _dicGetOK = SqlHelper.DeserializeObject(_dicGet);
return "ok";
}
注意:
<1>.創建一個.NET類庫,把要傳輸的對象做成一個結構或類放在類庫(假設為ClassLib.dll)中。如:
<2>.然后在客戶端程序和webservice項目中都引用ClassLib.dll
<3>.上面兩步的目的是讓客戶端序列化的對象,在webservice服務端能正常反序列化,不會出現反序列化時找不到命名空間的問題
---------------------------------------------------------------------------------------------------
7.修改webserivce最大傳輸的長度
<?xml version="1.0" encoding="utf-8"?>
<!--
有關如何配置 ASP.NET 應用程序的詳細消息,請訪問
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<connectionStrings>
<add name="ConStr" connectionString="$(ReplacableToken_ConStr-Web.config Connection String_0)"/>
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpRuntime maxRequestLength="2147483647" />
</system.web>
</configuration>
8.修改webservice的超時時間
<?xml version="1.0" encoding="utf-8"?>
<!--
有關如何配置 ASP.NET 應用程序的詳細消息,請訪問
executionTimeout="120" 超時時間120秒
maxRequestLength="2147483647" 最大請求長度
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<connectionStrings>
<add name="ConStr" connectionString="Data Source=192.128.58.248;Initial catalog=Citibank_test;Uid=sa;pwd=kicpassword"/>
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpRuntime maxRequestLength="2147483647" executionTimeout="240" />
</system.web>
</configuration>
9.序列化,反序列化方法
public static byte[] SerializeObject(object pObj)
{
if (pObj == null)
return null;
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, pObj);
memoryStream.Position = 0;
byte[] read = new byte[memoryStream.Length];
memoryStream.Read(read, 0, read.Length);
memoryStream.Close();
return read;
}
public static object DeserializeObject(byte[] pBytes)
{
object newOjb = null;
if (pBytes == null)
{
return newOjb;
}
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(pBytes);
memoryStream.Position = 0;
BinaryFormatter formatter = new BinaryFormatter();
newOjb = formatter.Deserialize(memoryStream);
memoryStream.Close();
return newOjb;
}