自定义Proxy 来做 rest wcf的客户端 与 WebChannelFactory<>的bug

[ServiceContract(Name="Profile")]
    public interface IProfile
    {
        [OperationContract]
        [WebGet(UriTemplate = "")]
        ProfileInfo Get();

        [OperationContract]
        [WebInvoke(UriTemplate = "", Method = "PUT")]
        ProfileInfo Update(ProfileInfo instance);

    }

    

        var httpRequest = (HttpWebRequest)WebRequest.Create(url);
            Client.AuthorizeRequest(httpRequest, Authorization.AccessToken);

            WebChannelFactory<IProfile> f = new WebChannelFactory<IProfile>(new Uri(url));
       
            IProfile service = f.CreateChannel();
            IClientChannel clientchanel = service as IClientChannel;
           
            try
            {
                var httpDetails = new HttpRequestMessageProperty();
                httpDetails.Headers[HttpRequestHeader.Authorization] = httpRequest.Headers[HttpRequestHeader.Authorization];
                    ProfileInfo info = new ProfileInfo();
                    info.Name="xxx";
                    var info2 = service.Update(info);
                    var test = service.Get();
                    var info3 = service.Update(info);
                    var test2 =  service.Get();
               
            }

我们可以看到的是 一但我用 Get方法来获取一次数据的话。
Update方法就无法把数据post出去了。很神奇的一个bug.

具体的原因就不清楚了。

为了可以解决这个问题。我们必须自己弄一个Proxy
里面的

Response类是出错时的对象,这样你就可以进行出错的处理了,可以自己抛出异常。跟服务端的Response的属性必须一样
比如说 GetUser()的方法 但是可能因为权限不过,所以要抛出一个xml的消息。这个就必须用到了。
代码
 public class WebShopProxy<T> : RealProxy
    {
        
public WebShopProxy(string baseUrl)
            : 
base(typeof(T))
        {
            BaseUrl 
= baseUrl;
            
        }

        
public AuthorizationState Authorization
        {
            
get;
            
set;
        }


        
private string BaseUrl
        {
            
get;
            
set;
        }

        
private static Dictionary<Type, string> TypeNameCache = new Dictionary<Type, string>();
        
private string GetServiceName(Type t)
        {
            
if (TypeNameCache.ContainsKey(t))
            {
                
return TypeNameCache[t];
            }
            
object[] objs = t.GetCustomAttributes(typeof(ServiceContractAttribute), false);
            
if (objs !=null && objs.Length>0)
            {
                
string name = "";
                ServiceContractAttribute attribute 
= objs[0as ServiceContractAttribute;
                
if (!string.IsNullOrEmpty(attribute.Name))
                {
                    name 
= attribute.Name;
                    TypeNameCache.Add(t, name);
                    
return name;
                }
                
else
                {
                    
string msg = string.Format("Type:{0} ServiceContract Attribute does not have name property", t.Name);
                    
throw new Exception(msg);
                }
            }
            
else
            {
                
string msg = string.Format("Type:{0} does not have ServiceContract Attribute", t.Name);
                
throw new Exception(msg);
            }
        }

        
private WebClient WebClient = new WebClient();
        
public override IMessage Invoke(IMessage msg)
        {

            IMethodCallMessage methodCall 
= msg as IMethodCallMessage;
            
byte[] buffer = GetResource(methodCall);
            
return ReturnMessage(methodCall, buffer);
        }

        
private static IMessage ReturnMessage(IMethodCallMessage methodCall, byte[] buffer)
        {
            
try
            {
                
if (buffer.Length==0)
                {
                    
return new ReturnMessage(nullnull0null, methodCall);
                }
                MemoryStream stream 
= new MemoryStream(buffer);
                var returnType 
= ((System.Reflection.MethodInfo)(methodCall.MethodBase)).ReturnType;
                DataContractSerializer serizlizer 
= new DataContractSerializer(returnType);
                
object o = serizlizer.ReadObject(stream);
                
return new ReturnMessage(o, null0null, methodCall);
            }
            
catch (SerializationException)
            {
                DataContractSerializer serizlizer2 
= new DataContractSerializer(typeof(Response));
                
try
                {
                    MemoryStream stream 
= new MemoryStream(buffer);
                    var response 
= (Response)serizlizer2.ReadObject(stream);
                    
return new ReturnMessage(new WebShopException(response), methodCall);
                }
                
catch (Exception e)
                {
                    
return new ReturnMessage(e, methodCall);
                }
            }
        }

        
private byte[] GetResource(IMethodCallMessage methodCall)
        {
            WebClient.Headers.Add(
"Content-Type""application/xml; charset=utf-8");
            
if (Authorization!=null)
            {
                WebClient.Headers[
"Authorization"= "oauth token="+Authorization.AccessToken;
            }

            
string serviceName = GetServiceName(typeof(T));
            
string uritemplate = "";
            
string url ="";
            
byte[] buffer;
            
object[] webGetObjs = methodCall.MethodBase.GetCustomAttributes(typeof(WebGetAttribute), false);
            
object[] webInvokeObjs = methodCall.MethodBase.GetCustomAttributes(typeof(WebInvokeAttribute), false);
            
if (webGetObjs !=null && webGetObjs.Length>0)
            {
                WebGetAttribute attribute 
= webGetObjs[0as WebGetAttribute;
                uritemplate 
= attribute.UriTemplate.ToLower();
                
for (int i=0; i<methodCall.ArgCount; i++)
                {
                    
object o = methodCall.GetArg(i);
                    
string name =  methodCall.GetArgName(i).ToLower();
                    
string replaceName = "{"+name+"}";
                    
if (uritemplate.IndexOf(name)!=-1)
                    {
                        
if (CheckType(o))
                        {
                            uritemplate 
= uritemplate.Replace(replaceName, HttpUtility.UrlEncode(o.ToString()));
                        }
                        
else
                        {
                            
throw new Exception(string.Format("parameter {0} should be int or string type", name));
                        }
                    }
                    
else
                    {
                        
throw new Exception(string.Format("WebGet Attribute can not support parameter {0}.", name));
                    }
                }
                url 
= MakeUrl(serviceName, uritemplate, url);
                buffer 
=  WebClient.DownloadData(url);
            }
            
else if (webInvokeObjs !=null && webInvokeObjs.Length>0)
            {
                WebInvokeAttribute attribute 
=  webInvokeObjs[0as WebInvokeAttribute;
                uritemplate 
= attribute.UriTemplate.ToLower();
                StringBuilder postData 
= new StringBuilder();
                
int warper =0;
                
for (int i=0; i<methodCall.ArgCount; i++)
                {
                    
object o = methodCall.GetArg(i);
                    
string name =  methodCall.GetArgName(i).ToLower();
                    
string replaceName = "{"+name+"}";
                    
if (uritemplate.IndexOf(name)!=-1)
                    {
                        
if (CheckType(o))
                        {
                           uritemplate 
= uritemplate.Replace(replaceName, HttpUtility.UrlEncode(o.ToString()));
                        }
                        
else
                        {
                            
throw new Exception(string.Format("Parameter {0} should be int or string type.", name));
                        }
                    }
                    
else
                    {
                        
if (warper>0)
                        {
                            
throw new Exception("At most one body parameter can be serialized.");
                        }

                        XmlWriterSettings settings 
= new XmlWriterSettings();
                        settings.Indent 
= true;
                        settings.OmitXmlDeclaration 
= true;
                        settings.NewLineOnAttributes 
= true;
                      
                        XmlWriter writer 
= XmlWriter.Create(postData,settings);
                        DataContractSerializer serizlizer 
= new DataContractSerializer(o.GetType());
                        serizlizer.WriteObject(writer, o);
                        writer.Flush();
                        warper
++;
                    }
                }
                url 
= MakeUrl(serviceName, uritemplate, url);
                
byte[] data = Encoding.UTF8.GetBytes(postData.ToString());
                buffer 
=  WebClient.UploadData(url, attribute.Method, data);
            }
            
else
            {
                
throw new Exception("You should add webget or webinvoke attribute on this method.");
            }
            
return buffer;
        }

        
private static bool CheckType(object o)
        {
            
return o is int || o is string || o is bool;
        }

        
private string MakeUrl(string serviceName, string uritemplate, string url)
        {
            
if (uritemplate.StartsWith("/"))
            {
                url 
= BaseUrl+serviceName+uritemplate;
            }
            
else
            {
                url 
= BaseUrl+serviceName+"/"+ uritemplate;
            }
            
return url;
        }
    }
完整的客户端在这边可以下到http://dev.starteenwinkel.nl/doc/DotNetSDK
原文地址:https://www.cnblogs.com/lovebanyi/p/1961258.html