Skip to main content

Articles

Featured Products

Windows Mobile Developer Controls
Windows Mobile Developer Controls

Twitter Updates

    News

    New site design will be posted by Wednesday.
    6/2/2008 8:07:00 AM

    Windows Mobile Developer Controls
    Windows Mobile Developer Controls
    Skip Navigation Links Breadcrumb Articles BreadcrumbCompact Framework

    SmartPhone (SP) and WebService Enhancements (WSE) with .NETcf

    Written by casey chesnut  [author's bio]  [read 47304 times]
    Edited by Derek

    Download the code

    Page 1  Page 2  Page 3  Page 4 

    Tracing

    When testing the above, I had to do alot more debugging then I preferred. This involved a lot of sniffing what was actually being sent over the wire. My preferred method is to use the Soap Toolkit Trace Utility. You can redirect to it at a certain port, and it will listen for incoming requests and then redirect to another endpoint. The really nice thing is that it can parse DIME messages as well. Occasionally my app would exception because of 'no end of entity mark', this seems to be caused by a parsing bug in the Soap Toolkit Trace Utility? If I would make the same WS call again immediately after, it would work fine. Also, I used the de facto TraceExtension SoapExtension example. Only changes it needed were to remove the SoapServerMessage usage and to write out to a filepath that exists on the SP. Then the problem is being able to view the actually file because there is no file explorer on SP. One of the managed code samples that comes with the SP SDK is a file explorer (CompactNav). With a little code addition (below), it can open .txt and .xml files in Pocket IE. Another option might be to use the ActiveSync-Emulator powertoy that has come out, which might let you browse to the file, although it has been way too finicky for me to use. Finally, WSE has some nice tracing options built-in for the server-side if you control that endpoint as well.

    else if (fullPath[depth].ToLower().EndsWith(".txt") || 
    				fullPath[depth].ToLower().EndsWith(".xml"))
    {
    	//add to bottom of CompactNav.listView1_ItemActivate
    	//after if (fullPath[depth].ToLower().EndsWith(".exe"))
    	ProcessInfo pi = new ProcessInfo();
    	// launch the exe using our pinvoked CreateProcess call
    	CreateProcess(@"\Windows\iexplore.exe", fullPath[depth], pi);
    	// back up since we didn't actually enter the directory
    	--depth;
    }

    WS-Routing

    This specification is basically dead. WS 2.0 uses WS-Addressing instead. I did go ahead and update this SoapHeader to better support the spec for existing WSE 1.0 apps that are already live. Tested it against the WSE1 Routing sample, which ends up routing the call to the SumService web service. NOTE the referralCache.config change below

    //request
    <wsrp:path soap:actor="http://schemas.xmlsoap.org/soap/actor/next" soap:mustUnderstand="1" 
        xmlns:wsrp="http://schemas.xmlsoap.org/rp">
      <wsrp:action>http://microsoft.com/wse/samples/SumService/AddInt</wsrp:action>
      <wsrp:to>http://localhost/wsequickstart/router/sumservice.asmx</wsrp:to>
      <wsrp:id>uuid:a435db9a-f8a1-453a-a75e-8ca8839b3863</wsrp:id>
    </wsrp:path>

    WS-Referral

    This spec. all happens on the server, to handle the actual routing of messages, so we do not have to worry about it from the client side. It is worth noting that you will have to change the referral.config file to develop with a SmartDevice. This is because SmartDevices cannot call web services with 'localhost' domains, and have to use machine name or ip address. The WSE Routing samples use localhost, so have to be modified to the ip address or machine name that you use from your device. If you have already called the WSE Routing sample, then referralCache.config will be locked, so you will have to iisreset to unlock it and make the changes. NOTE that capitalization might be an issue. Also if you are using a Soap tracing mechanism that depends on port redirection, then you will have to make changes for that as well.

    WS-Addressing

    I dont really like this spec. because it has a number of SoapHeaders that are scattered about and not contained by something like an <Addressing/> parent element. I did implement it as SoapHeaders, as well as in a SoapExtension (below). Tested it against the WSE2 Routing sample, which calls the BaseStockService web service. NOTE the referralCache.config change above

    //request
    <wsa:Action>http://stockservice.contoso.com/wse/samples/2003/06/StockQuoteRequest</wsa:Action> 
    <wsa:From>
      <wsa:Address>http://schemas.xmlsoap.org/ws/2003/03/addressing/role/anonymous</wsa:Address> 
    </wsa:From>
    <wsa:MessageID>uuid:140eaeb5-bb6d-58b1-8f31-ed56619e353b</wsa:MessageID> 
    <wsa:To>http://notebook:8080/TimeStampService/TimeStamp.asmx</wsa:To> 
    
    //response
    <wsa:From>
      <wsa:Address>http://schemas.xmlsoap.org/ws/2003/03/addressing/role/anonymous</wsa:Address> 
    </wsa:From>
    <wsa:MessageID>uuid:de8f245e-cb33-4366-bfb5-70f9445f6b17</wsa:MessageID> 

    SoapExtension

    Manually adding all those SoapHeaders for Timestamp and Addressing got annoying. With the WSE, routing and timestamp info is sent from the client without you having to specify anything. I wanted this same sort of automagic behavior, so decided to wrap the SoapHeaders with a SoapExtension. In the SoapExtension, on BeforeSerialize, you can add SoapHeaders to a Headers collection. On .NETfx, these will get serialized and sent out just fine, but not on .NETcf. On .NETcf, you have to hook AfterSerialize, load the stream into an XmlDocument, add the proper XmlElements to the doc, and then handle the stream properly. This sucks, because you lose all the typing. Also, when calling XmlDocument.Load, .NETcf closes the underlying stream, while .NETfx does not. A related trick (per Alex Feinman) to this is to add a generic SoapFault to the web ref proxy, and then you can add a typed SoapHeader and it will be sent appropriately.

    The other problem with SoapExtensions is that you have to register them using Attributes on .NETcf. I wish there was a programmatic way, so that my application logic could add them dynamically. Christian Weyer came up with a slick way to register them on .NETfx by reflecting to the app.config way of registering files; there should be a similar way to do the same through the client-side attribute method although i have not dug into it.

    Finally, there is another problem when stacking SoapExtensions. On the full framework, you can stack multiple SoapExtensionAttributes on top of the client proxy web method, and each SoapExtension will run in order based on whether the response is incoming or outgoing. This fails on the .NETcf because the stream will not get passed properly from SoapExtension to SoapExtension. You can get around this by just having one SoapExtension, and call a handler for each type of logic in the proper order. I really hope the problems with SoapExtensions get fixed for Whidbey. Mainly so that most of the code can be moved from doing Xml manipulation in AfterSerialize and BeforeDeserialize to working with typed objects in BeforeSerialize and AfterDeserialize. I would have preferred that programming model instead :(

    Proxy Authentication

    When calling an external WS, I tried it behind a proxy that required authentication. Initially, this was a problem to get the WSDL. The VS.NET 'add web reference' was not able to handle it, although it looks like wsdl.exe can. To get around this I used IE to browse to the WSDL, then saved it locally and reference the locally saved file in VS.NET to generate the proxy. Once the proxy was created, then it became a problem when calling the actual WS. On the .NETcf this was handled by catching a WebException, and then inserting the proper credentials. On .NETfx I would have done this by adding NetworkCredentials to the GlobalProxySelection.Select. Although that class exists on .NETcf it did not work for me and I had to add the NetworkCredentials to the webRefProxy.Proxy property instead. A UI would have to be supplied to let a user enter credentials, so hopefully this will not happen to SPs that are wirelessly connected because user input is a pain

    DIME / WS-Attachments

    My 1st version of this only was able to send one attachment out. In DIME this is actually 2 DimeRecords, the 1st being the SoapMessage, and the 2nd being the actual Attachment. It was also ugly in that you had to use the HttpWebRequest class directly and build up the SoapRequest manually. First, I extended this by making it support multiple attachments going out. Next, I updated it to support receiving multiple files in a Dime Response. Finally, I rehooked the SoapExtensions to work with the modified WSE interface and port to run on .NETcf. This makes it work with the web reference proxies so you dont have to manually get the SoapRequest. I doubt that chunking would work; which is used to break up a file among multiple DimeRecords in a single DimeMessage. Tested this against the WSE2 Attachments sample and it should also work for WSE1 DIME-enabled web services. The .xml files below show the DIME header parsed by the Soap Toolkit Trace Utility. The .txt files show the raw HTTP streams. I modified the sample to return DIME as well, so neither request nor response is your typical SOAP message

    dimeReq.xml / dimeReq.txt / dimeRes.xml / dimeRes.txt

    Cryptograpic Algorithms

    I actually wrote the previous parts of this article (Addressing and DIME) about a month ago. Then I started tackling WS-Security, and had to do a major segue. Reason being is that 2 big aspects of WS-Security are Xml-Encryption and Xml-Signature, both of which depend heavily on cryptographic algorithms. Since the .NETcf does not have the System.Security.Cryptography namespace at all, I spent almost a month filling in those missing pieces. The result is my /spCrypt article.

    The System.Security.Cryptography wrapping ended up being rather successful. Both the Xml-Enc and Xml-Sig specifications name a number of algorithms, and whether they are required / recommended or optional. For Required, we are missing AES Block Encryption. In a recent MSDN magazine, a C# AES implementation was provided that will compile in .NETcf. It works, except I could not get it to work with data larger than 16 bytes. Don't know if I was calling it wrong? Regardless, TripleDes is the other required Symmetric algorithm, and WSE uses it by default. For key transport we are missing RSA-OAEP, although we have RSA-PKCS1 which is used by default. For Recommended algs, we are only missing a SHA256 hash, but we do have the required SHA1 hash. For Optional algs, the smartPhone does have Diffie-Hellman for key agreement, although the full .NETfx does not support it. Finally, MacTripleDes is not working for the device but it is not needed for either Xml-Enc or Xml-Sig. Also, we dont have Rijndael symmetric (related to AES), but its not needed for WS-Security either. The result is the CryptoApi wrapping gave us access to just about everything we will need to continue.

    Previous Page  Next Page