/cfEvent

comment(s) 

Booty Calls using WS-Eventing to CF Web Server

http://www.brains-N-brawn.com/cfEvent 1/28/04 casey chesnut

Acronym Introduction

when finishing off the last article (/wsEvent ), i mentioned a follow up article ... tada. remind me to never type the word 'tada' again. /wsEvent was a good way to get acquainted with WS-Eventing, but i did not really do it proper. it was a Win Form client calling to a Web Service (WS), instead of web service to web service. plus, the notifications were generated from SQL Notification Services (NS), but they were not actually formatted or delivered in some meaningful way. so this article is going to fix those issues. ultimately, this exercises:

this article will put together WS-Eventing from web service to web service. the WS 'event source' will be on a desktop using the full .NET Framework (FX), and the WS 'event sink' will be running the Monash University Mobile Web Server (MWS) on a PocketPC (PPC) connected with WiFi (flavor B). SQL Notification Service will be the backend again for the event source, and the notifications will be formatted into SOAP calls and delivered over HTTP to the Compact Framework (CF) web server. the incoming event will be a booty call, and it will be kicked off however (not important). the booty call notification will be received at the CF web server event sink and it will use the PPC Notification API to pop up the notifcation dialog bubble on the device.

the main reason for the booty call service is that i needed a humorous idea to entertain myself while exploring these technologies. 2nd, i have missed countless booty calls (read zero) on my new phone, because it does not have an LED to notify me that i have a new voice or text message. it might have some option to make it beep annoyingly like other phones, but i would never turn that on because i loathe audio interruptions.

CF Mobile Web Service Server

the 1st thing to do was get my hands around the existing Mobile Web Server framework (linked above). i knew right away not to run it on an emulator, because they cannot listen, and immediately deployed to my device. then i started getting some missing dir/file IOExceptions, because everything did not deploy. also, i saw that the config.web (not dyslexic) file had the IP address in there, so i removed that and had the code retrieve it dynamically; as well as the hardcoded config.web path. manually copied those files over, and eventually figured out what files needed to be where. got rid of the whole MWS Interface project and just called the MobileWebService project directly, with a PPC console installed so i could trace out some messages. then was able to do standard calls for HTML, to get the default page and images. even hit the sample WebService page, and it returned WSDL for me. quickly created a desktop WinForm app to consume the web service from the device, and saw that it generated a WebMethod with the same method name, but different parameter overloads (for ASP.NET you have to name them differently, at least with an attribute). tried to invoke the web service and had the socket closed :( the code was doing reflection to invoke into an HtmlModule or SoapModule based on the incoming request, so i was not able to debug what was failing on the server within the SoapModule. tried to add some more dependencies to get rid of the reflection and got circular dependencies (of course). so i created a single project and threw all the source code into it, so that i would be able to debug what was going on. started debugging and saw that my test app was unexpectedly passing the WS-Addressing headers. ripped that out and the HelloWorld call from the desktop WinForm to device WebService worked! initial observation is that the MobileWebServer is a good start. it needs some work. specifically the SOAP parsing is done with string parsing, and should use the XmlTextReader instead. since i only plan on hosting the simplest web service, it will work fine for the scenario in mind. [pic of the MWS listening]

WS-Eventing from device

using the MWS was the highest risk for this article, so that is why i did it first. from here on out this article will be pretty much chronological to get to my desired goal. /wsEvent showed how a desktop WinForm could call a desktop WebService using WS-Eventing. so now i needed to push the WS-Eventing piece to the device. now the funny part is that most of WS-Eventing lives in Soap:Body, and is described in WSDL, so i just had to add the web reference and have it auto generate the proxy. Cool! remember i did have to do some WS-Addressing additions, so those did require minimal changes on my bits from the /spWSE article. to make sure the calls worked, i ripped out the code from the desktop WinForm test app, and threw it into a device WinForm app. made the web service call and got a 'null reference' exception before the call WS request was event sent. hmmm, that seems familiar. read over the /spWSE article, and sure enough i had documented how CF has bugs handling {any} and {@any}. damnit, i knew that was going to burn me sooner or later. go into my auto generated proxy, and start ripping them all out (except one i needed). try to run it, and get an IndexOutOfRangeException. reading the same paragraph from /spWSE and i've got that documented as well. really, the articles i write are just documentation for my own personal use. if you read them is of no consequence to me :) including this one :) the problem is i really need one of the {any} elements to pass a ReferencePropertyType to the WS eventing source when subscribing. for the ReferenceProperty, i ended up strongly typing it for my specific situation ... i.e. a string named 'MySubscription' that will be serialized into an XmlElement. Lame. really dont understand the true import of the ReferenceProperty, but the spec singles it out as being important, and when i needed to pass a UID parameter to Sql NS it seemed to be the right spot? so now i had totally decimated the auto-generated code. knew i was going to be re-gen'ing, so i created a proxy wrapper and moved my code changes into there. now firing up the test app, and the device was able to successfully Subscribe / Renew / and Unsubscribe from the WS-Eventing event source on the desktop. [pic of the CF tester app ... i'm a UI design expert]

CF WinForm to CF WebService

next order of business was to make sure i could have a PPC app kick off PPC WS calls. then i could have a simple interface make calls to the WS, to have it do the WS-Eventing calls, Subscribing in particular. so i extended the PPC test app from above to call the WebMethods exposed by the MWS on the same device. fired it up and got an exception, expecting text/xml, but got text/html instead. ok, so the MWS really should be spitting out SoapFaults from the SoapModule of type text/xml, instead of the error page as text/html. went into it and started to extend its logging features, to log more of the message. debugging on the device, i also fired up a winForm app on the desktop app to call into it. from the MWS documentation it says dont call it from apps in DEBUG mode, because it will crash. well, i did that by accident and found a pretty fundamental flaw in the ReadAvailableData method. basically it kept writing to the start of the buffer all the time, so only REALLY simple calls would work :) err, umm basically this thing was barely running at all, and because they it string parsing the message is the reason it limped along. an XmlReader would have puked out as being invalid XML from the beginning. fixed that, and was able to call it from the desktop with an app in RELEASE as well as DEBUG mode. i retried sending over the WS-Addressing SoapHeaders at that point, but they still failed. also, i attempted the device test again and it failed too. hell. looked at the return streams to both desktop and device ... and they were identical as they should have been. so the device web service implementation must find something wrong with the stream which the desktop will forgive. the only odd thing i saw was that the HTTP headers had a space before the carriage returns (\r\n), like HTTP/1.1 200 OK \r\n. removed that space, and then i had a CF app that could call a CF web service on the same device. there might have been another bug for this section, involving the MWS expecting all incoming requests to have an xml declaration (e.g. <?xml version="1.0" encoding="utf-8" ?>) [pic of the MWS processing a SoapRequest ... what the h3ll is yoi? or salah? crazy aussies]

CF WS to FX WS

now i could make a thin UI for the CF to make calls to the CF WS. so i gave it WebMethods to make the WS-Eventing source calls. So the UI would kick off a CF WS call to Subscribe to the desktop WS. the CF WS could also call the desktop WS to renew and unsubscribe. this uncovered another error in the MWS, in that it was trying to serialize void returns on WebMethods, so i just made it check for null'ness, and all the calls worked. so the scenario is, i have the PPC running the WS and a simple app. all the app does is kick off a WS call to its local MWS, telling it to subscribe to the service located on the desktop. did you get that? yea, i'm a little lost at this point too

SQL NS mods for Booty Call

the communication loop is almost complete at this point. now i had to add-in the backend logic for SQL NS. actually, i just modified the Stock sample some more. 1st, i ripped out stock symbol and value from the subscription. i changed the event so that it contained a 'to' user, a 'from' user, and a 'message' ... the universal booty call schema; soon to be published in UDDI and recommnded by the W3C. the 'to' user is the MySubscription ReferenceProperty when Subscribing. so i have to be subscribed to receive booty calls. then when a booty call comes in, the rule makes sure my subscription exists, and picks up my NotifyTo info from that subscription. this info was then added to the Notification schema, so that it would be generated. then, that info is transformed with XSLT into a valid SoapMessage, and delivered to the web service running on the PPC. the 'from' user is kind of interesting, because that would let me extend this to support response booty calls, if that user is also subscribed.

to recap, i kick off the WS on my PPC. i call it from a PPC app, to tell it to subscribe to the WS running on my desktop. a booty call comes into the event source web service running on the desktop. it inserts the event into SQL NS, which executes its rules logic to generate notifications. if any notifications are generated, they are then delivered. in this instance, they are deliverd to the event sink WS running on my PPC, because it previously subscribed. all that is left is for the PPC to actually notify me.

Notification API

went and grabbed some code to pop up the Notification bubble and tested it in a CF win app 1st. then all i did was throw that code in the CF WS WebMethod that would be called from the desktop WS event source. created the event feed WS on the desktop and then fired it off. sure enough, a Notification bubble showed up on my PPC about a minute later. actually ... it's never that simple. this uncovered another bug with MWS, and i believe its related to the same problem of not handling my SoapHeaders earlier. it seems that the call from the desktop WS to the CF WS included a trailing \r in the message and that was throwing off the string parsing. they already had some code where they were turning \n into spaces, so i added another line for \r, and then the call worked. [pic of a notification being spawned from a WebMethod hosted by MWS ... it's a quote from 'The Brak Show']

Silliness

you can send me a booty call if you want ... and if you're female. just kidding ... or am i? since my web server does not have SQL NS installed, i setup up a Tester web service that calls the Mobile Web Server directly on my Pocket PC. when i'm at home, i'll keep it on WiFi with the MWS running to receive notifications from the desktop server. here is the test page

Conclusion

the MWS ends up being rather fragile out of the box, but can be fortified to handle basic WS hosting scenarios on a device. would really like to see some sort of GotDotNet workspace or OpenNetCF effort to keep working on it ... maybe its already being done? else, i hope Indigo is being written in such a way that it will provide more advanced client-side and server-side hosting capabilities for devices in the future.

Updates

if i would update this one, i would extend the MWS to support the WS-Eventing bits as an event source on the PPC; currently it only acts as an event sink.

Future

installed Virtual PC with Whidbey, and was going to make the jump ... but it was too slow, so now i'm waiting for a RAM upgrade to make that a more enjoyable experience. have tried to start a couple Speech articles, but they've each had a bucket of cold water dumped on them for some reason or another. dang, i've got no cool ideas at the moment