本文主要讲述如何在.Net CF中发送自定义的SOAP消息来调用WebService。可能大家对如何实现自定义的SOAP有一定的了解。但是在.Net CF中,有一些地方值得大家注意。
为何要实现自定义的SOAP呢?以及SOAP的好处在于?
一般调用WebService时,我们可以发送Http信息,也可以发送SOAP1.1/1.2信息。如果我们希望在调用某些方法时只针对于特定的用户时。那通常做法,在调用函数中加入一些判断参数,然后来判断是否是被授权的用户。使用自定义SOAP消息不但可以减少传入参数,可以在该方法调用前,就过滤掉,通知客户端,没有足够的权限。通常,我们可以将这些信息放到SOAP的header部分,传递到服务器端时,解析时,可以验证header部分的信息是否符合。
概念讲述那么多。通过代码来说明吧。
首先定义一个WebService。
1[WebService(Namespace = "http://tempuri.org/")] 2[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 3public class Service : System.Web.Services.WebService 4{ 5 public MySoapHeader myHeader; 6 7 public Service () { 8 } 9 10 [WebMethod] 11 public string HelloWorld() { 12 return "Hello World"; 13 } 14 15 [WebMethod, SoapHeader("myHeader")] 16 public string GetInfo(string userName) 17 { 18 return string.Format("Hello, {0}", userName); 19 } 20} 该Service中声明了2个方法,其中GetInfo就是验证SOAP的方法。在该Service中提供了一个MySoapHeader,这个是自定义的SOAP头,用于定义一些验证信息。为何这样定义,等下文中叙述。
实现完WebService后,该实现扩展的SOAP信息了。 1 public override void ProcessMessage(SoapMessage message) 2 { 3 switch (message.Stage) 4 { 5 case SoapMessageStage.AfterDeserialize: 6 break; 7 case SoapMessageStage.AfterSerialize: 8 break; 9 case SoapMessageStage.BeforeDeserialize: 10 Check(message); 11 break; 12 case SoapMessageStage.BeforeSerialize: 13 break; 14 default: 15 break; 16 } 17 } 18 19 private void Check(SoapMessage message) 20 { 21 if (message is SoapServerMessage) 22 { 23 MemoryStream ms = new MemoryStream(); 24 System.IO.StreamWriter sw = new StreamWriter(ms); 25 StreamReader sr = new StreamReader(message.Stream); 26 char[] buffer = new char[(int)message.Stream.Length]; 27 sr.Read(buffer, 0, (int)message.Stream.Length); 28 29 sw.Write(buffer, 0, buffer.Length); 30 sw.Flush(); 31 message.Stream.Position = 0; 32 string sb = System.Text.Encoding.ASCII.GetString(ms.ToArray()); 33 34 Debug.WriteLine(sb); 35 36 XDocument doc = XDocument.Parse(sb); 37 XNamespace name = "urn:com-appleseeker"; 38 XNamespace soapheader = "http://schemas.xmlsoap.org/soap/envelope/"; 39 MySoapHeader header = new MySoapHeader(); 40 41 if (doc.Descendants(soapheader + "Header").Descendants().Elements(name + "userid").First() == null) 42 { 43 throw new Exception(""); 44 } 45 header.userid = doc.Descendants(soapheader + "Header").Descendants().Elements(name + "userid").First().Value; 46 47 string[] temp = message.Action.ToString().Split('/'); 48 string methodName = temp[temp.Length - 1]; 49 50 if (header.userid == "0345") 51 { 52 } 53 else 54 { 55 throw new Exception("No Access"); 56 } 57 } 58 } 这是服务器端的扩展的SOAP处理,必须重写一些方法,其中ProcessMessage中,在做BeforeDeserialize这一步操作时,解析接受到的SOAP消息。通常SOAP会有4部分操作。可以参考代码说列。 在验证消息时,从SOAP消息中取到内容,就是流中的内容,该流只读,可以通过复制到内存中来取得。当然,取道流的内容后,肯定是一个XML格式,通过对XML格式的文件解析方式,取到SOAP头部说含内容。这里我只验证userid=0345时,才能调用。否则则返回一个异常。
客户端部份相对简单。 1 public override void ProcessMessage(SoapMessage message) 2 { 3 switch (message.Stage) 4 { 5 case SoapMessageStage.AfterDeserialize: 6 break; 7 case SoapMessageStage.AfterSerialize: 8 break; 9 case SoapMessageStage.BeforeDeserialize: 10 break; 11 case SoapMessageStage.BeforeSerialize: 12 message.Headers.Add(new MySoapHeader() { userid = "0345" }); 13 break; 14 default: 15 break; 16 } 17 } 只是在ProcessMessage的BeforeSerialize前加入头文件的内容。
自定义的SOAPHeader
1 [XmlRoot("MyHeader", Namespace = "urn:com-appleseeker")] 2 public class MySoapHeader: SoapHeader 3 { 4 public string userid; 5 public string username; 6 public string department; 7 }Namespace约定了在header部分的tag,通过定义,我们可以用它来解析。
我们做完了代码上的大部分活,接下来就是配置了,如何让WebService在接收到SOAP消息后,自动来解析呢,只需要在web.config中加入下面配置即可 1 2 3 4 5在add type中,第一个是自定义的扩展SOAP类名,需加命名空间,后面一个是程序集名
服务器端配置完成了。接下来就是客户端部分。 这里介绍下非Mobile程序如何使用,我创建一个控制台程序简单说明下,在客户端部分,有2种方式使用扩展SOAP。 1.可以像服务器端那样,自定义一个SOAP类,然后加入相应信息,再在app.config中加入相应配置即可。 2.在服务器的WebService的方法的Attribute中加入SoapHeader参数,表明可以使用的自定义SOAP头文件内容。 并在WebService中提供一个Public的自定义的头属性。在客户端只需要在调用时对自定义的头属性赋值即可。
在WM中,只能使用第2种方法来实现,不支持第1种方式。 1private void menuItem1_Click(object sender, EventArgs e) 2{ 3 localhost.Service service = new SmartDeviceProject1.localhost.Service(); 4 service.Url = service.Url.Replace("localhost", "192.168.0.157"); 5 localhost.MySoapHeader myHeader = new SmartDeviceProject1.localhost.MySoapHeader(); 6 myHeader.userid = "0345"; 7 service.MyHeader = myHeader; 8 MessageBox.Show(service.GetInfo("Gordon")); 9} 以上在WM中就能使用自定义的SOAP消息了。各位在实际应用中如果遇到什么问题,可以参考我下面提供的代码。我在做Demo的过程中也或多或少遇到一些问题,大家可以相互探讨交流。
这篇文章的主旨在于,如何在WebService中验证用户信息。 在下一篇文章中,我可能会讲述如何在WCF中实现用户的验证。同样会基于.Net CF,希望大家能够留意。
|