{"id":18,"date":"2008-06-08T13:09:35","date_gmt":"2008-06-08T18:09:35","guid":{"rendered":"http:\/\/blog.monnet-usa.com\/?p=18"},"modified":"2009-07-24T21:33:03","modified_gmt":"2009-07-25T04:33:03","slug":"silverlight-2-beta-2-now-supports-web-services-interoperability","status":"publish","type":"post","link":"https:\/\/blog.monnet-usa.com\/?p=18","title":{"rendered":"Silverlight 2 Beta 2 now supports Web Services Interoperability"},"content":{"rendered":"<p>This week, the Silverlight team released beta 2. This is a critical new beta since apart from the many UI-oriented features, the networking stack now offers web services interoperability (WSI).<\/p>\n<p>Why is this important?<br \/>\nWell if you are a Microsoft-only shop and all your web services are .asmx-based then you are using a document-style web service model (as opposed to an RPC-style).<br \/>\nBut if your enterprise environment has mixed technologies (e.g. MS, Java, Ruby, etc.) then you will find that many older (and sometime not so old) web services follow the SOAP\/RPC style.<br \/>\nE.g.<br \/>\n&#8211; if you are Ruby On Rails developer and expose web services using the Action Web Service plugin then your services are RPC-style<br \/>\n&#8211; if you are using Apache Axis 1.x (often 3rd party software embeds older version of Axis, not Axis 2 which does offer document-style SOAP) &#8211; same thing<\/p>\n<p>In beta 1, Silverlight could only call .asmx web services or services using a document-style SOAP implementation. Unfortunately for me, I had built a simplistic web service using the Rails Action Web Service plugin. So I could not get my web service implementation to even build let alone work.<\/p>\n<p>Here is what my test scenario looked like.<\/p>\n<p>In Rails I declared my web service API like so:<\/p>\n<pre class=\"brush: ruby\">\r\nclass WsTstApi < ActionWebService::API::Base\r\napi_method :get_time,\r\n:returns => [:string]\r\nend\r\n<\/pre>\n<p>Then I created an implementation for the API in a Rails controller like so:<\/p>\n<pre class=\"brush: ruby\">\r\nrequire 'date'\r\nclass WsTstController < ApplicationController\r\nwsdl_service_name 'WsTst'\r\nweb_service_api WsTstApi\r\nweb_service_scaffold :invoke\r\n\r\ndef get_time\r\nreturn DateTime.now.strftime(\"%H:%M:%S\")\r\nend\r\n\r\nend\r\n<\/pre>\n<p>This allowed Rails to generate the following WSDL (abbreviated for clarity) when calling the when requested through http:\/\/***mywebservicedomain***\/ws_tst\/service.wsdl:<\/p>\n<pre class=\"brush: xml\">\r\n&lt;definitions name=\"WsTst\" xmlns:typens=\"urn:ActionWebService\" ...&gt;\r\n\r\n&lt;message name=\"GetTime\"\/&gt;\r\n&lt;message name=\"GetTimeResponse\"&gt;\r\n&lt;part name=\"return\" type=\"xsd:string\"\/&gt;\r\n&lt;\/message&gt;\r\n\r\n&lt;portType name=\"WsTstWsTstPort\"&gt;\r\n\r\n&lt;operation name=\"GetTime\"&gt;\r\n&lt;input message=\"typens:GetTime\"\/&gt;\r\n&lt;output message=\"typens:GetTimeResponse\"\/&gt;\r\n&lt;\/operation&gt;\r\n\r\n&lt;\/portType&gt;\r\n\r\n&lt;binding name=\"WsTstWsTstBinding\" type=\"typens:WsTstWsTstPort\"&gt;\r\n&lt;soap:binding transport=\"http:\/\/schemas.xmlsoap.org\/soap\/http\" style=\"rpc\"\/&gt;\r\n\r\n&lt;operation name=\"GetTime\"&gt;\r\n&lt;soap:operation soapAction=\"\/ws_tst\/api\/GetTime\"\/&gt;\r\n\r\n&lt;input&gt;\r\n&lt;soap:body namespace=\"urn:ActionWebService\" use=\"encoded\" encodingStyle=\"http:\/\/schemas.xmlsoap.org\/soap\/encoding\/\"\/&gt;\r\n&lt;\/input&gt;\r\n\r\n&lt;output&gt;\r\n&lt;soap:body namespace=\"urn:ActionWebService\" use=\"encoded\" encodingStyle=\"http:\/\/schemas.xmlsoap.org\/soap\/encoding\/\"\/&gt;\r\n&lt;\/output&gt;\r\n\r\n&lt;\/operation&gt;\r\n\r\n&lt;\/binding&gt;\r\n\r\n&lt;service name=\"WsTstService\"&gt;\r\n&lt;port name=\"WsTstWsTstPort\" binding=\"typens:WsTstWsTstBinding\"&gt;\r\n&lt;soap:address location=\"http:\/\/***mywebservicedomain***\/ws_tst\/api\"\/&gt;\r\n&lt;\/port&gt;\r\n&lt;\/service&gt;\r\n&lt;\/definitions&gt;\r\n<\/pre>\n<p>I then created a Silverlight project and added a service reference to http:\/\/***mywebservicedomain***\/ws_tst\/service.wsdl to generate the web service proxy.<br \/>\nHowever, it seemed like Visual Studio only knew how to generate a proxy assuming a WCF scenario as opposed to a Silverlight-specific WCF stack. This unfortunately generated an serialization attribute (below the statement with the OperationContractAttribute) such as:<\/p>\n<pre class=\"brush: csharp\">\r\n[System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, Use=System.ServiceModel.OperationFormatUse.Encoded)]\r\n<\/pre>\n<p>The Silverlight ServiceModel library did not implement the XML serializer feature or offer any alternatives.<br \/>\nI tried to comment those out and play around with a different set of attributes but at the end of the day I could not set the serialization to be XML RPC-based.<br \/>\nMicrosoft indicated at the time in the Silverlight forums that WSI compatibility would be implemented in beta 2.<\/p>\n<p>Well now the wait is over. So this morning I started a brand new Silverlight 2 project. I added my service reference and looked at the generated proxy. Same problem! The XmlSerializerFormatAttribute is not implemented. So I went back to MSDN to look at the new beta 2 documentation for ServiceModel. And oh surprise, there is now an equivalent feature called DataContractFormatAttribute. I replaced the name and rebuilt. Well it seems that the Use property is not implemented so I removed it. So now my full web service proxy decoration looks like this:<\/p>\n<pre class=\"brush: csharp\">\r\n[System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action=\"\/ws_tst\/api\/GetTime\", ReplyAction=\"*\")]\r\n[System.ServiceModel.DataContractFormatAttribute (Style=System.ServiceModel.OperationFormatStyle.Rpc)]\r\nSystem.IAsyncResult BeginGetTime(System.AsyncCallback callback, object asyncState);\r\n\r\n[return: System.ServiceModel.MessageParameterAttribute(Name=\"return\")]\r\nstring EndGetTime(System.IAsyncResult result);\r\n<\/pre>\n<p>The solution now built successfully. I modified added a button and a text box to my Page.xaml, then implemented the button click handler to do the following:<br \/>\n1. Instantiate the generated SOAP port client<br \/>\n2. Subscribe to the asynchronous web service call response event<br \/>\n3. Call the web service asynchronously<\/p>\n<p>The code looks like this:<\/p>\n<pre class=\"brush: csharp\">\r\nprivate void btnTest_Click(object sender, RoutedEventArgs e)\r\n{\r\nbtnTest.IsEnabled = false; \/\/ Disable the button while the web service call is in progress\r\nWsTstWsTstPortClient client = new WsTstWsTstPortClient();\r\ntry\r\n{\r\nclient.GetTimeCompleted += new EventHandler&lt;GetTimeCompletedEventArgs&gt;(client_GetTimeCompleted);\r\nclient.GetTimeAsync();\r\ntxtResults.Text = \"Calling web svc ...\";\r\n}\r\ncatch (Exception ex)\r\n{\r\ntxtResults.Text = string.Format(\"Error calling web svc: {0}\", ex.ToString());\r\n}\r\n}\r\n<\/pre>\n<p>I then implemented the web service response event handler so that it gets the Result value from the web service response as follows:<\/p>\n<pre class=\"brush: csharp\">\r\nvoid client_GetTimeCompleted(object sender, GetTimeCompletedEventArgs e)\r\n{\r\nstring results = string.Empty;\r\n\r\ntry\r\n{\r\nresults = (e == null)\r\n? \"Received null response!\"\r\n: ((e.Result == null)\r\n? \"Received some data but Result is null!\"\r\n: e.Result);\r\n}\r\ncatch (Exception ex)\r\n{\r\nresults = string.Format(\"Error: {0}\", ex.ToString());\r\n}\r\n\r\ntxtResults.Text = string.Format(\"Web svc call completed at: {0}nResults: [{1}]\",\r\nDateTime.Now.ToString(),\r\nresults);\r\nbtnTest.IsEnabled = true;\r\n}\r\n<\/pre>\n<p>I built my solution, deployed the .xapp file to my web site and navigated to my test page. The moment of truth was there as I clicked the Test button.<br \/>\n...<br \/>\n<a title=\"Silverlight calling a RoR web service\" class=\"imagelink\" href=\"https:\/\/blog.monnet-usa.com\/wp-content\/uploads\/2008\/06\/sl2rorws.Png\"><img loading=\"lazy\" decoding=\"async\" width=\"484\" height=\"65\" alt=\"Silverlight calling a RoR web service\" id=\"image19\" src=\"https:\/\/blog.monnet-usa.com\/wp-content\/uploads\/2008\/06\/sl2rorws.Png\" \/><\/a><br \/>\n... and YES the web service call was successful and the result was displayed in my Silverlight client.<\/p>\n<p>Very cool. This opens up a lot of opportunities for Silverlight client to be used in internal web applications interacting with a broad range of WSI profile web services.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This week, the Silverlight team released beta 2. This is a critical new beta since apart from the many UI-oriented features, the networking stack now offers web services interoperability (WSI). Why is this important? Well if you are a Microsoft-only shop and all your web services are .asmx-based then you are using a document-style web [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,7],"tags":[],"class_list":["post-18","post","type-post","status-publish","format-standard","hentry","category-ruby","category-silverlight"],"_links":{"self":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts\/18","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=18"}],"version-history":[{"count":3,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts\/18\/revisions"}],"predecessor-version":[{"id":155,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts\/18\/revisions\/155"}],"wp:attachment":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=18"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=18"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=18"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}