1: namespace Artech.WcfFrameworkSimulator.Client
2: {
3: public class ServiceRealProxy<IContract> : RealProxy
4: {
5: private Uri _remoteAddress;
6: private IDictionary<string, IClientMessageFormatter> _messageFormatters;
7: private MessageVersion _messageVersion = MessageVersion.Default;
8: private MessageEncoderFactory _messageEncoderFactory;
9:
10: public ServiceRealProxy(MessageVersion messageVersion, Uri address, IDictionary<string, IClientMessageFormatter> messageFormaters, MessageEncoderFactory messageEncoderFactory)
11: : base(typeof(IContract))
12: {
13: object[] attribute = typeof(IContract).GetCustomAttributes(typeof(ServiceContractAttribute), false);
14: if (attribute.Length == 0)
15: {
16: throw new InvalidOperationException(string.Format("The type \"{0}\" is not a ServiceContract!", typeof(IContract).AssemblyQualifiedName));
17: }
18: this._messageVersion = messageVersion;
19: this._remoteAddress = address;
20: this._messageFormatters = messageFormaters;
21: this._messageEncoderFactory = messageEncoderFactory;
22: }
23:
24: public override IMessage Invoke(IMessage msg)
25: {
26: IMethodCallMessage methodCall = (IMethodCallMessage)msg;
27:
28: //Get Operation name.
29: object[] attributes = methodCall.MethodBase.GetCustomAttributes(typeof(OperationContractAttribute), true);
30: if (attributes.Length == 0)
31: {
32: throw new InvalidOperationException(string.Format("The method \"{0}\" is not a valid OperationContract.", methodCall.MethodName));
33: }
34: OperationContractAttribute attribute = (OperationContractAttribute)attributes[0];
35: string operationName = string.IsNullOrEmpty(attribute.Name) ? methodCall.MethodName : attribute.Name;
36:
37: //序列化请求消息
38: Message requestMessage = this._messageFormatters[operationName].SerializeRequest(this._messageVersion, methodCall.InArgs);
39:
40: //添加必要的WS-Address报头
41: EndpointAddress address = new EndpointAddress(this._remoteAddress);
42: requestMessage.Headers.MessageId = new UniqueId(Guid.NewGuid());
43: requestMessage.Headers.ReplyTo = new EndpointAddress("http://www.w3.org/2005/08/addressing/anonymous");
44: address.ApplyTo(requestMessage);
45:
46: //对请求消息进行编码,并将编码生成的字节发送通过HttpWebRequest向服务端发送
47: HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(this._remoteAddress);
48: webRequest.Method = "Post";
49: webRequest.KeepAlive = true;
50: webRequest.ContentType = "application/soap+xml; charset=utf-8";
51: ArraySegment<byte> bytes = this._messageEncoderFactory.Encoder.WriteMessage(requestMessage, int.MaxValue, BufferManager.CreateBufferManager(long.MaxValue, int.MaxValue));
52: webRequest.ContentLength = bytes.Array.Length;
53: webRequest.GetRequestStream().Write(bytes.Array, 0, bytes.Array.Length);
54: webRequest.GetRequestStream().Close();
55: WebResponse webResponse = webRequest.GetResponse();
56:
57: //对HttpResponse进行解码生成回复消息.
58: Message responseMessage = this._messageEncoderFactory.Encoder.ReadMessage(webResponse.GetResponseStream(), int.MaxValue);
59:
60: //回复消息进行反列化生成相应的对象,并映射为方法调用的返回值或者ref/out参数
61: object[] allArgs = (object[])Array.CreateInstance(typeof(object), methodCall.ArgCount);
62: Array.Copy(methodCall.Args, allArgs, methodCall.ArgCount);
63: object[] refOutParameters = new object[GetRefOutParameterCount(methodCall.MethodBase)];
64: object returnValue = this._messageFormatters[operationName].DeserializeReply(responseMessage, refOutParameters);
65: MapRefOutParameter(methodCall.MethodBase, allArgs, refOutParameters);
66:
67: //通过ReturnMessage的形式将返回值和ref/out参数返回
68: return new ReturnMessage(returnValue, allArgs, allArgs.Length, methodCall.LogicalCallContext, methodCall);
69: }
70:
71: private int GetRefOutParameterCount(MethodBase method)
72: {
73: int count = 0;
74: foreach (ParameterInfo parameter in method.GetParameters())
75: {
76: if (parameter.IsOut || parameter.ParameterType.IsByRef)
77: {
78: count++;
79: }
80: }
81: return count;
82: }
83:
84: private void MapRefOutParameter(MethodBase method, object[] allArgs, object[] refOutArgs)
85: {
86: List<int> refOutParamPositionsList = new List<int>();
87: foreach (ParameterInfo parameter in method.GetParameters())
88: {
89: if (parameter.IsOut || parameter.ParameterType.IsByRef)
90: {
91: refOutParamPositionsList.Add(parameter.Position);
92: }
93: }
94: int[] refOutParamPositionArray = refOutParamPositionsList.ToArray();
95: for (int i = 0; i < refOutArgs.Length; i++)
96: {
97: allArgs[refOutParamPositionArray[i]] = refOutArgs[i];
98: }
99: }
100: }
101: }