Web Services 和WCF技术分析之反射

来源:转载

1,两者的区别。


WCF可以不依赖于IIS。


WCF可以配置成BasicHttpBinding来兼容(或者说变身成)WS。 WCF可以基于TCP或者MessegeQueue来传输数据。 WCF的可配置性比WS强,比如安全性。 WCF可以是有状态的,并支持事务。 WCF 支持多种通信协议 Http/Https 、TCP/UDP、MSMQ、命名管道、对等网、 消息可达性、事务流等。 WCF 可以与ASP.NET 集成、共享一个上下文(HttpContext)。 WCF 支持多种消息传输格式 :text,binary,mtom,Json 等。 WCF 安全性要强:支持对称安全、非对称安全、消息安全、传输安全、 SSL 流安全、Windows 流安全等。 WCF 支持多种会话模式:单向、双向、请求/响应。 WCF 支持REST 。 WCF 支持多种格式化方式。DataContractSerializer、XmlSerializer、 DataContractJsonSerializer 等。 WCF 支持 WAS hosting、Windows 服务 hosting、Self-Hosting、IIS hosting 等。 WCF 支持多种并发模式:单例、单调、会话


2,这里要讲的是通过纯运行时代理实现方法的调用。主要用到的技术是反射。


一,web services


private object agent;


private Type agentType;


private const string CODE_NAMESPACE = "Demo";


///

/// 构造函数


///

///

public WebServiceAgent(string url)


{


try


{



XmlTextReader reader = new XmlTextReader(url + "?wsdl");

//创建和格式化 WSDL 文档

System.Web.Services.Description.ServiceDescription sd = System.Web.Services.Description.ServiceDescription.Read(reader);

//创建客户端代理代理类


ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();


sdi.AddServiceDescription(sd, null, null);

//使用 CodeDom 编译客户端代理类


CodeNamespace cn = new CodeNamespace(CODE_NAMESPACE);


CodeCompileUnit ccu = new CodeCompileUnit();


ccu.Namespaces.Add(cn);


sdi.Import(cn, ccu);


Microsoft.CSharp.CSharpCodeProvider icc = new Microsoft.CSharp.CSharpCodeProvider();


CompilerParameters cp = new CompilerParameters();


CompilerResults cr = icc.CompileAssemblyFromDom(cp, ccu);


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


agent = Activator.CreateInstance(agentType);


}


catch (Exception ex)


{


throw ex;


}


}


实现思路:利用wsdl生成xml文档,利用反射生成客户端代理agent = Activator.CreateInstance(agentType);


二,WCF,引用WCF服务,网上能够找到详细的例子,但都集中于两种方式,1,添加服务引用,这样每次服务变更,需要更新一下引用。2,通过ChannelFactory快速绑定一个终结点,但也需要客户端代理(契约)。WCF一个好处是它是基于契约的,意思是我不管里面如何实现,客户端只关心契约的结果。在构建复杂应用场景中,如何让我们代码高内聚,低耦合,有同学说了可以面向接口编程呀,诚然,WCF实现了,这是终极解决方案么?当然不是,假如接口变动了么?相信这是所有程序员的噩梦。.net用反射机制来解决此类问题,所有操作动态生成,这样,我们不用在关心服务端的变更会影响到客户端。只需阅读接口文档,这样我们关心的问题转移到配置文件。这种方式会牺牲一些性能(反射),这里我们需要在性能和便于维护之前平衡了。


public WebServiceAgent(string url,string aa)


{


try


{


//获取WSDL


WebClient wc = new WebClient();


Stream stream = wc.OpenRead(url + "?singleWsdl");


System.Web.Services.Description.ServiceDescription sd = System.Web.Services.Description.ServiceDescription.Read(stream);


ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();


sdi.AddServiceDescription(sd, "", "");


CodeNamespace cn = new CodeNamespace(CODE_NAMESPACE);


//生成客户端代理类代码


CodeCompileUnit ccu = new CodeCompileUnit();


ccu.Namespaces.Add(cn);


sdi.Import(cn, ccu);


CodeDomProvider provider = new CSharpCodeProvider();//设定编译参数


CompilerParameters cplist = new CompilerParameters();


cplist.GenerateExecutable = false;


cplist.GenerateInMemory = true;


cplist.ReferencedAssemblies.Add("System.dll");


cplist.ReferencedAssemblies.Add("System.XML.dll");


cplist.ReferencedAssemblies.Add("System.Web.Services.dll");


cplist.ReferencedAssemblies.Add("System.Data.dll");


//编译代理类


CompilerResults cr = provider.CompileAssemblyFromDom(cplist, ccu);


if (true == cr.Errors.HasErrors)


{


System.Text.StringBuilder sb = new System.Text.StringBuilder();


foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors)


{


sb.Append(ce.ToString());


sb.Append(System.Environment.NewLine);


}


throw new Exception(sb.ToString());


}


//生成代理实例


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


agent = Activator.CreateInstance(agentType);


EndpointAddress address = new EndpointAddress("http://localhost:6666/UserInfo/");


WSHttpBinding binding = new WSHttpBinding();



}


catch (Exception ex)


{


throw new Exception(ex.InnerException.Message, new Exception(ex.InnerException.StackTrace));


}


}


原理同web services。


3,通过代理调用方法,这里主要介绍WCF,因为没有亲自编码,后面不对webservices在做介绍。


public object Invoke(string methodName, params object[] args)


{


MethodInfo mi = agentType.GetMethod(methodName);


try


{


var ret = this.Invoke(mi, args);


var ds = new DataContractJsonSerializer(ret.GetType());


var ms = new MemoryStream();


ds.WriteObject(ms, ret);


var strJSON = Encoding.UTF8.GetString(ms.ToArray());


ms.Close();


return strJSON;


}


catch (Exception e)


{


return e.Message;


}



}


这里我默认返回是一个集合,因为客户端不清楚返回集合的结构,而我们又不想编写多余的客户端脚本,这里通过DataContractJsonSerializer实现到json的转换。这个前提是服务端实体类通过[DataContract]标记为可被序列化。


///

///调用指定方法


///

///

///

///

public object Invoke(MethodInfo method, params object[] args)


{


try


{


return method.Invoke(agent, args);


}


catch (Exception e)


{


return e.Message;


}



}


4,关于WCF传递参数问题,由于没有客户端代理是动态创建的,我们用object[] args存放参数。


服务端代码:


[OperationContract]


LoginCheckResult CheckLogin(string userName, string authorizationCode);


客户端调用:


object[] args = new object[2];


// args[0] = rtbSend.Text;


args[0] = "superadmin";


args[1] = "aaa";


var receive = service.Invoke(methodName, args).ToString() ;


这里service是上面我们动态生成的代理,methodName是我们动态解析出来的方法名--CheckLogin


近年来REST风格服务非常流行,这种松散的接口是前端界的一股清流,所到之处,无不夸赞,传统的Web Services和WCF备受歧视,轻量级和安全将是未来主导面向服务编程的两大特性

分享给朋友:
您可能感兴趣的文章:
随机阅读: