分享
 
 
 

把.Net整合进其他平台

王朝c#·作者佚名  2008-05-21
窄屏简体版  字體: |||超大  

整合分布式应用程序经常是一件非常困难并且错综复杂的任务,即使是最富有经验的开发者也可能会觉得头疼。当应用程序在不同的操作系统以及涉及不同的程序平台时,这个集成问题变得尤其复杂。虽然说,Web服务承诺可以减轻程序员完成集成任务的困难程度,但是也可能给程序员们带来一些意想不到的麻烦。在这里我们将把一个ASP.Net应用程序和一个PHP Web服务连结起来,以学习一些整合分布式应用程序的方法,以及必要的应对措施,包括运行什么以及不用去做什么。

这个Web服务在一个Apache服务器上运行,并且使用PHP开发。它从各种微软新闻组检索新闻摘要以及它们的关联的文本。即使由这个服务提供的数据可以直接使用内部的.Net对象存取,但是这个服务还是将使用并提供一个连接到非.Net平台上的不错的演示。我们这里要讨论的实例基于.Net beta 2版。

创建一个Web服务代理

Visual Studio.NET提供了一个出色的机制用于自动地生成可用于存取远程Web服务的代理对像。因此,要首先尝试使用这些函数来导入由PHP服务提供的Web服务描述语言(Web Services Description Language,WSDL)文件。 还可以使用.Net SDK的WSDL.exe命令行公用程序。不幸的是,在使用VS.Net向导导入WSDL之后,并不能成功地创建一个代理。所以我必须把导入原始的WSDL文件后由VS.Net生成的文件转换为WSDL:

1. 把模式域名空间从http://www.w3.org/1999/XMLSchema改成http://www.w3.org/2001/XMLSchema 然后清除所有的当WSDL导入过程中由VS.Net添加的”q”域名空间。

2. 删除 xmlns:tm=http://microsoft.com/wsdl/mime/textMatching/和xmlns: mime="http://schemas.xmlsoap.org/wsdl/mime/" 名字空间,因为这个应用程序中不需要包含这些。

3. 删除类型元素,因为原始的 WSDL文档 并没有包含Web服务的模式信息的指定的元素区段。

4. 改变输入输出元素消息属性值为包含tns域名空间前缀的形式:

<portType name="nntpSoapPortType"><operation name="getheaders" parameterOrder="newsgroup numitems"><input message="tns:getheaders" /><output message="tns:getheadersresponse" /></operation><operation name="getarticle" parameterOrder="newsgroup article"><input message="tns:getarticle" /><output message="tns:getarticleresponse" /></operation></portType>

在进行了下面的这些微小的改变,VS.Net向导能够读取WSDL并且自动地生成一个代理。在编译了这个代理之后,它被包含在一个ASP.Net页面中。然而,当这个ASP.Net页面被执行:“ message does not have a correct SOAP root XML tag.”,这个错误被当作一个SOAP错误从Web服务中返回。为了精确地评估这个错误,代理调用被一个名为Proxy Trace的公用程序使用,以便代理生成SOAP包装。这可以通过把下列代码添加进ASP.Net页面来实现:

msNews.Proxy = new System.Net.WebProxy( "http://localhost:8080");

在察看了由.Net代理生成的SOAP包装之后,我有点奇怪为什么会返回这个错误,因为实际上一个相对的SOAP包装被生成并被发送到Web服务。即使在尝试了好几个转化成代理代码之后这个错误依然持续。代码段列表2显示了从PHP Web服务返回的完整的SOAP错误包装。

在使用VS.Net中创建的代理对象的好几个把ASP.Net页面与PHP Web服务连结的不成功的尝试之后,我决定从头开始创建SOAP包装以便执行更有效的程序调试。{起先,它看起来好像由.Net代理生成的模式域名空间可能是问题的关键,因为.Net使用2001模式规范而PHP服务使用的是1999版本的规范。

然而,我把自定义的SOAP包装改为用1999版本代替2001版本,错误依然存在。在尝试了好几个其他的小的改变之后,我决定把SOAP包装使用的域名空间前缀和正文元素从soap (由.Net代理生成)改为SOAP - ENV,因为我看见在SOAP错误信息中返回了SOAP - ENV前缀。(见代码2)这表面上看上去微不足道的改变竟解决了问题!当处理任何请求的时候,PHP服务显然需要SOAP - ENV前缀,而拒绝不包含SOAP - ENV前缀的要求。

创建一个自定义代理

既然已经了解了为什么Web服务返回一个SOAP错误,我们就可以创建一个自定义代理来生成网服务期待的SOAP包装。虽然创建一个自定义SOAP包装肯定比使用一个由VS.Net或者WSDL.exe公用程序生成的SOAP包装要花更多的时间,但是这样做可以完全控制包装的内容。为了开始创建自定义代理,我创建一个名为msnewsserviceproxy的包含两个字段的新类:

public class MSNewsServiceProxy {string _uri;string _soapAction;}

uri字段保存了Web服务的位置,而_soapAction字段保存了将要使用SOAP包装发送的SOAPAction数据头的名称。在MSNewsServiceProxy类之内,添加CreateSoapEnvelope (),SendSoapEnvelope ()和FilterResult ()这三个方法。这些方法生成SOAP包装请求,把它发送到Web服务,然后过滤返回的SOAP包装。让我们逐一的看看每个方法。注意代码在SOAP包装的根元素上添加一个SOAP - ENV域名空间前缀。Web服务显然需要这个特定的前缀,而拒绝任何不包含这个前缀的信息。因为VS.Net生成的代理发送一个soap域名空间前缀(而不是SOAP - ENV),所以它的消息被拒绝。Web服务不应该需要一个特定的域名空间前缀而为此拒绝不带此前缀的消息,但是域名空间问题也是你必须注意要想使工作更好的完成,要执行一些看上去不{0>可思议的事情。

在SOAP包装被创建之后,SendSoapEnvelope ()方法(见代码段4)使用了几个System.Net和System.IO域名空间中的类来把这个包装发送到Web服务中。代码首先通过把_uri变量传送到对象构造器来创建一个HttpWebRequest对象。其次,与这个请求相关联的相应的Method,ContentType和Header都将被发送。然后一个StreamWriter对象和HttpWebRequest对象的请求流相关联,SOAP包装就被使用StreamWriter的Write ()方法写到流中。

从Web服务返回的SOAP包装被HttpWebResponse对象的SendSoapEnvelope ()方法获得。

HttpWebResponse response = (HttpWebResponse)request.GetResponse();

如果应答不是空值,它将被载入一个XmlTextReader,XmlTextReader被用来填充XmlDocument对象。然后从这个方法中返回XmlDocument对象。

FilterSoapEnvelope ()方法分析SOAP应答包装并把从Web服务中返回的数据装入自定义代理的“消费者”使用的XmlDocument对象:

private XmlDocumentFilterSoapEnvelope(XmlDocument doc) {XmlDocument filterDoc =new XmlDocument();XmlNode result = doc.SelectSingleNode("//results");XmlNode resultImport = filterDoc.ImportNode(result,true);filterDoc.AppendChild(resultImport);return filterDoc;}

虽然过滤器可以使用好几种方法执行,但是FilterSoapEnvelope ()方法依靠XPath语句可以在应答SOAP包装中得到结果元素。

微软新闻组PHP Web服务展示了允许取得新闻组新闻摘要的两种方法:getheaders ()和getmessage ()。 你可以看到如何在自定义代理类中使用这两种方法(见代码段5)。 注意每个方法中的代码传递Web服务方法名被调用到CreateSoapEnvelope ()方法和任何使用这个方法关联的参数。 在SOAP包装被发送以及应答被接受之后,FilterSoapEnvelope ()方法被调用来把返回的数据加载到一个XmlDocument对象中,同样,这个对象也是代理“消费者”使用的。

整合PHP Web服务

既然一个自定义代理类已经准备好被使用,那么把它整合进一个ASP.Net页面就变得很简单了。getHeaders ()和getMessage ()方法可以调用Web服务,存取返回的XmlDocument对象(见代码段6和7) 在XmlDocument内的子结点中的枚举可以显示这些数据。 虽然许多Web服务可以很容易地使用VS.Net或者WSDL.exe创建的代理类自动地生成,但是仍然会有你需要创建自定义SOAP包装来把.Net和其他的平台整合起来的情况。 本文中介绍的内容以及代码就提供了完成这个整合工作的一种方法。

代码段1:

POST http://www.codecraze.com/soap/nntp.php HTTP/1.1User-Agent: Mozilla/4.0 (compatible;MSIE 6.0; MS Web Services Client Protocol 1.0.2914.16)Content-Type: text/xml; charset=utf-8SOAPAction: "http://www.codecraze.com/soap/nntp.php"Content-Length: 683Expect: 100-continueConnection: Keep-AliveHost: www.codecraze.com<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"xmlns:tns="http://tempuri.org/"xmlns:types="http://tempuri.org/encodedTypes"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Bodysoap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><q1:getheaders xmlns:q1="http://www.codecraze.com/soap/nntp.xsd"><newsgroup xsi:type="xsd:string">microsoft.public.dotnet.xml</newsgroup><numitems xsi:type="xsd:string">15</numitems></q1:getheaders></soap:Body></soap:Envelope>

代码段2:

HTTP/1.1 200 OKDate: Apr, 16 Dec 2002 15:57:47 GMTServer: Apache/1.3.20 (Unix) ApacheJServ/1.1.2 PHP/4.0.4pl1 FrontPage/5.0.2.2510 Rewrit/1.1aX-Powered-By: PHP/4.0.4pl1Content-Length: 419Keep-Alive: timeout=15, max=100Connection: Keep-AliveContent-Type: text/xml; charset="utf-8"<?xml version="1.0" encoding="utf-8"?><SOAP-ENV:Envelopexmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Client.SOAPMessageFormat</faultcode><faultstring>message does not have a correct SOAP root XML tag</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>

代码段3 :

private string CreateSoapEnvelope(string method,string[] param1,string[] param2) {StringBuilder sb = new StringBuilder();sb.Append("<SOAP-ENV:Envelope");sb.Append(" xmlns:SOAP-" +"ENV="http://schemas.xmlsoap.org/soap/envelope/"");sb.Append(" xmlns:xsi="http://www.w3.org/1999/XMLSchema-" +instance"");sb.Append(" xmlns:xsd="http://www.w3.org/1999/XMLSchema">");sb.Append("<SOAP-ENV:Body>");sb.Append("<m:" + method + " xmlns:m="nntp.xsd">");sb.Append("<" + param1[0] + ">" + param1[1] +"</" + param1[0] + ">");sb.Append("<" + param2[0] + ">" + param2[1] +"</" + param2[0] + ">");sb.Append("</m:" + method + ">");sb.Append("</SOAP-ENV:Body>");sb.Append("</SOAP-ENV:Envelope>");return sb.ToString();}

代码段4:

private XmlDocument SendSoapEnvelope(string soapEnv) {HttpWebRequest request =(HttpWebRequest)WebRequest.Create(_uri);XmlTextReader xmlReader = null;XmlDocument xmlDoc = null;request.Method = "POST";request.ContentType = "text/xml";request.Headers.Add("SOAPAction",_soapAction);StreamWriter writer = new StreamWriter(request.GetRequestStream());writer.Write(soapEnv);writer.Close();HttpWebResponse response =(HttpWebResponse)request.GetResponse();if (response != null) {xmlReader = new XmlTextReader(response.GetResponseStream());xmlDoc = new XmlDocument();xmlDoc.Load(xmlReader);return xmlDoc;} else {return xmlDoc;}}

代码段5:

public XmlDocument getHeaders(string newsgroup,string numitems) {string soapEnv = CreateSoapEnvelope("getheaders",new string[2]{"newsgroup",newsgroup},new string[2]{"numitems",numitems});return FilterSoapEnvelope(SendSoapEnvelope(soapEnv));}public XmlDocument getMessage(string newsgroup,string article) {string soapEnv = CreateSoapEnvelope("getmessage",new string[2]{"newsgroup",newsgroup},new string[2]{"article",article});return FilterSoapEnvelope(SendSoapEnvelope(soapEnv));}

代码段6:

private void Page_Load(object sender, System.EventArgs e){StringBuilder sb = new StringBuilder();try {MSNewsService.MSNewsServiceProxy news =new MSNewsService.MSNewsServiceProxy();XmlDocument newsHeaders =news.getHeaders("microsoft.public.dotnet.xml","15");sb.Append("<ul>");foreach (XmlNode node innewsHeaders.DocumentElement.ChildNodes) {sb.Append("<li><a href="JavaScript:readArticle('" + node.FirstChild.InnerText + "','" +node.ChildNodes.Item(1).InnerText +"')">" + node.ChildNodes.Item(1).InnerText +"</a></li>");}sb.Append("<ul>");lblMessages.Text = sb.ToString();}catch (Exception exp) {lblMessages.Text ="The Web Service appears to be" + " unavailable";}}

代码MSNewsServiceProxy.cs:

using System.Net;using System.Xml;using System.IO;using System.Text;namespace MSNewsService {public class MSNewsServiceProxy {string _uri;string _soapAction;public MSNewsServiceProxy() {_uri = "http://www.codecraze.com/soap/nntp.php";_soapAction = "http://www.codecraze.com/soap/nntp.php";}private XmlDocument SendSoapEnvelope(string soapEnv) {HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_uri);XmlTextReader xmlReader = null;XmlDocument xmlDoc = null;request.Method = "POST";request.ContentType = "text/xml";request.Headers.Add("SOAPAction",_soapAction);StreamWriter writer = new StreamWriter(request.GetRequestStream());writer.Write(soapEnv);writer.Close();HttpWebResponse response = (HttpWebResponse)request.GetResponse();if (response != null) {xmlReader = new XmlTextReader(response.GetResponseStream());xmlDoc = new XmlDocument();xmlDoc.Load(xmlReader);return xmlDoc;} else {return xmlDoc;}}private string CreateSoapEnvelope(string method,string[] param1, string[] param2) {StringBuilder sb = new StringBuilder();sb.Append("<SOAP-ENV:Envelope");sb.Append(" xmlns:SOAP-" +"ENV="http://schemas.xmlsoap.org/soap/envelope/"");sb.Append(" xmlns:xsi="http://www.w3.org/1999/XMLSchema-" +"instance"");sb.Append(" xmlns:xsd="http://www.w3.org/1999/XMLSchema">");sb.Append("<SOAP-ENV:Body>");sb.Append("<m:" + method + " xmlns:m="nntp.xsd">");sb.Append("<" + param1[0] + ">" + param1[1] + "</" + param1[0] + ">");sb.Append("<" + param2[0] + ">" + param2[1] + "</" + param2[0] + ">");sb.Append("</m:" + method + ">");sb.Append("</SOAP-ENV:Body>");sb.Append("</SOAP-ENV:Envelope>");return sb.ToString();}public XmlDocument getHeaders(string newsgroup,string numitems) {string soapEnv = CreateSoapEnvelope("getheaders",new string[2]{"newsgroup",newsgroup},new string[2]{"numitems",numitems});return FilterSoapEnvelope(SendSoapEnvelope(soapEnv));}public XmlDocument getMessage(string newsgroup,string article) {string soapEnv = CreateSoapEnvelope("getmessage",new string[2]{"newsgroup",newsgroup},new string[2]{"article",article});return FilterSoapEnvelope(SendSoapEnvelope(soapEnv));}private XmlDocument FilterSoapEnvelope(XmlDocument doc) {XmlDocument filterDoc = new XmlDocument();XmlNode result = doc.SelectSingleNode("//results");XmlNode resultImport = filterDoc.ImportNode(result,true);filterDoc.AppendChild(resultImport);return filterDoc;}}}

代码msNewsClient.aspx.cs

using System;using System.Collections;using System.ComponentModel;using System.Data;using System.Drawing;using System.Web;using System.Web.SessionState;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.HtmlControls;using System.Xml;using System.Text;namespace MSNewsService{public class MSNewsServiceClient : System.Web.UI.Page{protected System.Web.UI.WebControls.Label lblMessages;public MSNewsServiceClient(){Page.Init += new System.EventHandler(Page_Init);}private void Page_Load(object sender, System.EventArgs e) {StringBuilder sb = new StringBuilder();try {MSNewsService.MSNewsServiceProxy news = new MSNewsService.MSNewsServiceProxy();XmlDocument newsHeaders = news.getHeaders("microsoft.public.dotnet.xml","15");sb.Append("<ul>");foreach (XmlNode node in newsHeaders.DocumentElement.ChildNodes) {sb.Append("<li><a href="JavaScript:readArticle('" + node.FirstChild.InnerText +"','" + node.ChildNodes.Item(1).InnerText +"')">" + node.ChildNodes.Item(1).InnerText + "</a></li>");}sb.Append("<ul>");lblMessages.Text = sb.ToString();}catch (Exception exp) {lblMessages.Text = "The Web Service appears to be unavailable";}}private void Page_Init(object sender, EventArgs e){InitializeComponent();}private void InitializeComponent(){this.Load += new System.EventHandler(this.Page_Load);}}}

代码msNewsMessage.aspx

<%@ Page language="c#" src="msNewsMessage.aspx.cs" Codebehind="msNewsMessage.aspx.cs" AutoEventWireup="false" Inherits="MSNewsService.msNewsMessage" %><HTML><body bgcolor="#ffffff"><h2><asp:Label ID="lblMessageTitle" Runat="server" /></h2><p><asp:Label ID="lblMessageText" Runat="server" /></p></body></HTML>代码msNewsMessage.aspx.csusing System;using System.Collections;using System.ComponentModel;using System.Data;using System.Drawing;using System.Web;using System.Web.SessionState;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.HtmlControls;using System.Xml;namespace MSNewsService{public class msNewsMessage : System.Web.UI.Page{protected System.Web.UI.WebControls.Label lblMessageTitle;protected System.Web.UI.WebControls.Label lblMessageText;public msNewsMessage(){Page.Init += new System.EventHandler(Page_Init);}private void Page_Load(object sender, System.EventArgs e) {try {MSNewsService.MSNewsServiceProxy news = new MSNewsService.MSNewsServiceProxy();XmlDocument newsHeaders = news.getMessage("microsoft.public.dotnet.xml",Request["articleID"]);lblMessageTitle.Text = Request["title"];lblMessageText.Text = newsHeaders.FirstChild.InnerText;}catch (Exception exp) {lblMessageText.Text = "The Web Service appears to be unavailable";}}private void Page_Init(object sender, EventArgs e){InitializeComponent();}private void InitializeComponent(){this.Load += new System.EventHandler(this.Page_Load);}}}

代码msNewsClient.apsx

<%@ Page language="c#" src="msNewsClient.aspx.cs" Codebehind="msNewsClient.aspx.cs" AutoEventWireup="false" Inherits="MSNewsService.MSNewsServiceClient" %><HTML><head><script language="javascript">function readArticle(id,title) {openWindow("msNewsMessage.aspx?articleID=" + id +"&title=" + title,500,400);}function openWindow(page,w,h) {window.open(page,"","status=no,width=" + w +",height=" + h + ",scrollbars=yes");}</script></head><body bgcolor="#ffffff"><h2>Recent posts from: microsoft.public.dotnet.xml</h2><p /><asp:Label ID="lblMessages" Runat="server" /></body></HTML><0}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有