.NET 动态调用WCF

  • Post author:
  • Post category:其他


写在前面

接触WCF还是它在最初诞生之处,一个分布式应用的巨作。 从开始接触到现在断断续续,真正使用的项目少之又少,更谈不上深入WCF内部实现机制和原理去研究,最近自己做一个项目时用到了WCF。 从这个小项目中我学会了两个地方: 1、利用IIS部署WCF服务,也就是大家接触到的发布SVC文件。2、动态调用WCF接口。

在这个项目中接触WCF时遇到的其实不仅仅是这两个问题,甚至连IIS支持SVC文件也让我折腾了好几把,IIS都重新卸载了两次。 我在这篇文章里用两种方式来实现。

如何使用

1、第一种方式比较简单,而且也是大家喜欢的,因为不需要任何配置文件就可解决,只需知道服务契约接口和服务地址就可以调用。

2、使用Invoke的方式,但是需要在调用客户端配置WCF,配置后在Invoke类里封装服务契约接口即可。

客户端调用DEMO

1
2
3
4
5
6
7

//第一种方式

string


url =


"http://localhost:3000/DoubleService.svc"


;

IDoubleService proxy = WcfInvokeFactory.CreateServiceByUrl<IDoubleService>(url);

int


result = proxy.Add(1, 3);

//第二种方式<br><br>int result1  = WCFInvoke.Invoke(t => t.Add(1, 3));<br><br>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

<system.serviceModel>



<behaviors>



<endpointBehaviors>



<behavior name=


"NewBehavior"


>



<dataContractSerializer maxItemsInObjectGraph=


"65536000"


/>



</behavior>



</endpointBehaviors>



</behaviors>



<bindings>



<basicHttpBinding>



<binding name=


"BasicHttpBinding_IDoubleService"



closeTimeout=


"01:00:00"



openTimeout=


"01:00:00"



sendTimeout=


"01:00:00"



receiveTimeout=


"01:00:00"



maxBufferSize=


"2147483647"



maxBufferPoolSize=


"524288"



maxReceivedMessageSize=


"2147483647"


>



<readerQuotas maxDepth=


"128"


maxStringContentLength=


"2147483647"


maxArrayLength=


"16384"


maxBytesPerRead=


"4096"


maxNameTableCharCount=


"16384"


/>



</binding>



</basicHttpBinding>



<netMsmqBinding>



<binding name=


"NetMsmqBinding_IAsyncSender"


>



<security mode=


"None"


/>



</binding>



</netMsmqBinding>



</bindings>



<client>




<endpoint address=


"http://localhost:3000/DoubleService.svc"



binding=


"basicHttpBinding"



bindingConfiguration=


"BasicHttpBinding_IDoubleService"



contract=


"DoubleStone.WebHost.IDoubleService"



name=


"BasicHttpBinding_IDoubleService"


/>




</client>



</system.serviceModel>

第一种调用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

public


class


WcfInvokeFactory



{




#region WCF服务工厂



public


static


T CreateServiceByUrl<T>(


string


url)



{




return


CreateServiceByUrl<T>(url,


"basicHttpBinding"


);



}



public


static


T CreateServiceByUrl<T>(


string


url,


string


bing)



{




try



{




if


(


string


.IsNullOrEmpty(url))


throw


new


NotSupportedException(


"This url is not Null or Empty!"


);



EndpointAddress address =


new


EndpointAddress(url);



Binding binding = CreateBinding(bing);



ChannelFactory<T> factory =


new


ChannelFactory<T>(binding, address);



return


factory.CreateChannel();



}



catch


(Exception ex)



{




throw


new


Exception(


"创建服务工厂出现异常."


);



}



}



#endregion



#region 创建传输协议



/// <summary>



/// 创建传输协议



/// </summary>



/// <param name="binding">传输协议名称</param>



/// <returns></returns>



private


static


Binding CreateBinding(


string


binding)



{




Binding bindinginstance =


null


;



if


(binding.ToLower() ==


"basichttpbinding"


)



{




BasicHttpBinding ws =


new


BasicHttpBinding();



ws.MaxBufferSize = 2147483647;



ws.MaxBufferPoolSize = 2147483647;



ws.MaxReceivedMessageSize = 2147483647;



ws.ReaderQuotas.MaxStringContentLength = 2147483647;



ws.CloseTimeout =


new


TimeSpan(0, 30, 0);



ws.OpenTimeout =


new


TimeSpan(0, 30, 0);



ws.ReceiveTimeout =


new


TimeSpan(0, 30, 0);



ws.SendTimeout =


new


TimeSpan(0, 30, 0);



bindinginstance = ws;



}



else


if


(binding.ToLower() ==


"nettcpbinding"


)



{




NetTcpBinding ws =


new


NetTcpBinding();



ws.MaxReceivedMessageSize = 65535000;



ws.Security.Mode = SecurityMode.None;



bindinginstance = ws;



}



else


if


(binding.ToLower() ==


"wshttpbinding"


)



{




WSHttpBinding ws =


new


WSHttpBinding(SecurityMode.None);



ws.MaxReceivedMessageSize = 65535000;



ws.Security.Message.ClientCredentialType = System.ServiceModel.MessageCredentialType.Windows;



ws.Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Windows;



bindinginstance = ws;



}



return


bindinginstance;



}



#endregion



}

第二种调用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14

public


class


WCFInvoke



{




/// <summary>



/// 你需要调用的服务契约



/// </summary>



/// <typeparam name="T"></typeparam>



/// <param name="func"></param>



/// <returns></returns>



public


static


T Invoke<T>(Func<IDoubleService, T> func)



{




IServiceInvoker serviceInvoker=


new


WCFServiceInvoker();



return


serviceInvoker.InvokeService(func);



}



}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

public


interface


IServiceInvoker



{




void


InvokeService<T>(Action<T> invokeHandler)


where


T :


class


;



TReslt InvokeService<T, TReslt>(Func<T, TReslt> invokeHandler)


where


T :


class


;



}

public


class


WCFServiceInvoker:IServiceInvoker



{




private


static


readonly


ChannelFactoryManager FactoryManager =


new


ChannelFactoryManager();



private


static


readonly


ClientSection ClientSection =



ConfigurationManager.GetSection(


"system.serviceModel/client"


)


as


ClientSection;



public


void


InvokeService<T>(Action<T> invokeHandler)


where


T :


class



{




KeyValuePair<


string


,


string


> endpointNameAddressPair = GetEndpointNameAddressPair(


typeof


(T));



var


arg = FactoryManager.CreateChannel<T>(endpointNameAddressPair.Key, endpointNameAddressPair.Value);



var


obj2 = (ICommunicationObject)arg;



try



{




invokeHandler(arg);



}



finally



{




try



{




if


(obj2.State != CommunicationState.Faulted)



{




obj2.Close();



}



}



catch



{




obj2.Abort();



}



}



}



public


TReslt InvokeService<T, TReslt>(Func<T, TReslt> invokeHandler)


where


T :


class



{




KeyValuePair<


string


,


string


> endpointNameAddressPair = GetEndpointNameAddressPair(


typeof


(T));



var


arg = FactoryManager.CreateChannel<T>(endpointNameAddressPair.Key, endpointNameAddressPair.Value);



var


obj2 = (ICommunicationObject)arg;



try



{




return


invokeHandler(arg);



}



finally



{




try



{




if


(obj2.State != CommunicationState.Closed || obj2.State != CommunicationState.Faulted)



{




obj2.Close();



}



}



catch



{




obj2.Abort();



}



}



}



private


KeyValuePair<


string


,


string


> GetEndpointNameAddressPair(Type serviceContractType)



{




var


configException =



new


ConfigurationErrorsException(



string


.Format(



"No client endpoint found for type {0}. Please add the section <client><endpoint name=\"myservice\" address=\"http://address/\" binding=\"basicHttpBinding\" contract=\"{0}\"/></client> in the config file."


,



serviceContractType));



if


(((ClientSection ==


null


) || (ClientSection.Endpoints ==


null


)) || (ClientSection.Endpoints.Count < 1))



{




throw


configException;



}



foreach


(ChannelEndpointElement element


in


ClientSection.Endpoints)



{




if


(element.Contract == serviceContractType.ToString())



{




return


new


KeyValuePair<


string


,


string


>(element.Name, element.Address.AbsoluteUri);



}



}



throw


configException;



}



}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

public


class


ChannelFactoryManager : IDisposable



{




private


static


readonly


Dictionary<Type, ChannelFactory> Factories =


new


Dictionary<Type, ChannelFactory>();



private


static


readonly


object


SyncRoot =


new


object


();



public


void


Dispose()



{




Dispose(


true


);



}



public


virtual


T CreateChannel<T>()


where


T :


class



{




return


CreateChannel<T>(


"*"


,


null


);



}



public


virtual


T CreateChannel<T>(


string


endpointConfigurationName)


where


T :


class



{




return


CreateChannel<T>(endpointConfigurationName,


null


);



}



public


virtual


T CreateChannel<T>(


string


endpointConfigurationName,


string


endpointAddress)


where


T :


class



{




T local = GetFactory<T>(endpointConfigurationName, endpointAddress).CreateChannel();



((IClientChannel)local).Faulted += ChannelFaulted;



return


local;



}



protected


virtual


ChannelFactory<T> GetFactory<T>(


string


endpointConfigurationName,


string


endpointAddress)



where


T :


class



{




lock


(SyncRoot)



{




ChannelFactory factory;



if


(!Factories.TryGetValue(


typeof


(T),


out


factory))



{




factory = CreateFactoryInstance<T>(endpointConfigurationName, endpointAddress);



Factories.Add(


typeof


(T), factory);



}



return


(factory


as


ChannelFactory<T>);



}



}



private


ChannelFactory CreateFactoryInstance<T>(


string


endpointConfigurationName,


string


endpointAddress)



{




ChannelFactory factory =


null


;



factory = !


string


.IsNullOrEmpty(endpointAddress) ?


new


ChannelFactory<T>(endpointConfigurationName,


new


EndpointAddress(endpointAddress)) :


new


ChannelFactory<T>(endpointConfigurationName);



factory.Faulted += FactoryFaulted;



factory.Open();



return


factory;



}



private


void


ChannelFaulted(


object


sender, EventArgs e)



{




var


channel = (IClientChannel)sender;



try



{




channel.Close();



}



catch



{




channel.Abort();



}



}



private


void


FactoryFaulted(


object


sender, EventArgs args)



{




var


factory = (ChannelFactory)sender;



try



{




factory.Close();



}



catch



{




factory.Abort();



}



Type[] genericArguments = factory.GetType().GetGenericArguments();



if


((genericArguments.Length == 1))



{




Type key = genericArguments[0];



if


(Factories.ContainsKey(key))



{




Factories.Remove(key);



}



}



}



protected


virtual


void


Dispose(


bool


disposing)



{




if


(disposing)



{




lock


(SyncRoot)



{




foreach


(Type type


in


Factories.Keys)



{




ChannelFactory factory = Factories[type];



try



{




factory.Close();



}



catch



{




factory.Abort();



}



}



Factories.Clear();



}



}



}



}

总结

第一种方式比较常见,第二种方式是我参考另外一个项目中的写法,其中的有一些细节我还没有搞明白,实现了这个功能后还需要再看看这部分代码,再消化消化。由于是直接在项目中,所以没有提供源代码下载,有朋友需要的话我会整理出demo,稍后放出下载链接。

转载于:https://www.cnblogs.com/leo-gong/p/9365418.html