I often come across the following questions about web service usage in Silverlight:
- Why are exceptions not "propagated" from WCF services to Silverlight clients?
- Why are SOAP Faults not supported?
- Given the limitations on exceptions/faults, are there any tricks I can use to make my scenario work? Is anything planned to improve this in the future?
- I can't even get basic error handling to work when calling web services in Silverlight. Can I at least tell when something went wrong, even if I can't access the exact fault details?
I'll tackle these one by one:
WCF Exceptions
Two things stop exceptions from propagating from a WCF service to a Silverlight client.
The first one is easy to fix: WCF normally hides exception details from the client, for security reasons, but it is possible to change this during debugging by changing the IncludeExceptionDetailInFaults setting as described in http://blogs.devdeo.com/carlos.medina/PermaLink,guid,b3bff742-0ec9-4f5c-a178-625220a46652.aspx. Just remember to turn it off when you're done debugging your service.
The step above is normally sufficient for most web service clients, but not for Silverlight. This is because exceptions are sent as SOAP Faults, and these are not supported in Silverlight 2, as explained in the next section.
SOAP Faults
Every HTTP response (including the SOAP message returned by the service) contains a status code (e.g. 200 - success, 404 - not found, or 500 - internal server error). The SOAP specification requires SOAP Faults to be sent with a status code in the 400/500 range, which indicates an error condition. Unfortunately, web browsers have a limitation with regards to status codes: When a browser plugin (such as Silverlight) makes an HTTP request, and the response status code is not 200, the browser hides the actual status code and the message body from the plugin. All Silverlight knows is that "something went wrong", but it has no way of discovering any details.
This browser limitation is the reason why SOAP Faults (and thus "exception propagation" from WCF) are not supported in Silverlight. Not all is lost though - you can often work around the issue as described in the next section.
Tricks, Workarounds and Future Plans
We've already seen that due to some fundamental restrictions on browser plugins, Silverlight cannot support SOAP Faults. To get around this, there are basically four approaches:
1. Do you really need the fault to get to the Silverlight client?
If all you need faults for is debugging, you can often debug in a different way. By using HTTP sniffing tools such as http://www.fiddlertool.com/fiddler/ or http://projects.nikhilk.net/webdevhelper/, you can observe faults directly on the wire, even if they don't get to Silverlight. You can also set up fault logging on the server side.
If all you need faults for is to be able to tell that "something went wrong", see the section on basic error handling at the end of this post.
2. Do you really need it to be a fault?
Suppose you have a web service operation like this:
[OperationContract] int GetCurrentTemperature();
The operation can actually return one of two things, an integer (in the case of success) or a SOAP Fault (in the case of failure). You can make it explicit in the contract:
[OperationContract] int GetTemperature(out MyFaultInfo fault);
Ugly, but it works. If you want to propagate exceptions, your entire GetCurrentTemperature implementation could be in a try/catch block, which returns null for fault if no exception happened, or the relevant information from the exception if one is caught.
In WCF, you can make this look somewhat nicer by using MessageContracts:
[MessageContract] public class MyStandardMessage {
[MessageBodyMember] public MyFaultInfo fault;
}
[MessageContract] public class TemperatureMessage : MyStandardMessage {
[MessageBodyMember] public int temperature;
}
[OperationContract] TemperatureMessage GetCurrentTemperature();
One caveat: If you're thinking of using actual exception types in your contract, like so:
[OperationContract] int GetTemperature(out System.Exception fault); //do not do this
... that is probably not a good idea. Exceptions may contain security-sensitive information that you would not want to reveal to a client. Also, in Silverlight exception types are generally not serializable, so you would not get the same .NET exception type in the Silverlight proxy. Finally, you may run into a number of issues around the Known Types mechanism (outside the scope of this post).
3. Does it have to follow the SOAP spec to the letter?
Strictly speaking, SOAP faults are not Silverlight-compatible. However, one can easily imagine a slight modification to the SOAP-over-HTTP protocol whereby faults will be sent with the 200 HTTP status code, thereby eliminating the problem. We are investigating along this direction for future versions of Silverlight, but there are things you can do even now.
If the service is in WCF, it should be possible to enable this "SOAP-for-the-browser" variant using WCF extensibility. In WCF, it is very easy to expose the same service in multiple variants (bindings) at different addresses, so you could easily expose the same service for the browser and for traditional SOAP clients by simply defining two endpoints in configuration.
If it is a third-party service, it should be possible to create a proxy (using WCF or another technology) that converts 400/500 status codes to 200. Some non-Microsoft web service stacks do not implement the SOAP specification correctly, and already return faults with a 200 code!
On the client side, you need to detect the fact that the message is a fault (e.g. by looking for the "soap:Fault" element) and handle it appropriately. This should be possible with WCF channel extensibility in Silverlight.
Notice that I am saying "should be possible". Actually making this work requires a deep knowledge of WCF. Our team will likely produce sample code that does this, effectively enabling faults when talking to a WCF service from Silverlight. Watch our Code Gallery site (http://code.msdn.com/SilverlightWS) where it will be posted when ready.
One more thing to note here: Since faults don't work by default, all of the fault-related code (such as the generic FaultExcetpion class) was cut from the Silverlight version of WCF in order to conserve size. Therefore, even with the approach above, the code you will have to write to handle faults will not be the same as what you may be used to writing in the regular .NET Framework. This may be addressed in a future version of Silverlight.
4. Does it have to work over the browser plugin model?
The browsers restrict information available to plugins (such as Silverlight) in case of a non-200 status code. However, there are alternatives to using the plugin model for making HTTP requests, some of which we are exploring for future versions of Silverlight.
One thing you can do along these lines even today is to use the JavaScript interop features of Silverlight, call out to JavaScript on the web page that hosts your Silverlight control, and then use the standard AJAX technique- xmlHttpRequest - to make your SOAP request and read the response. This lets you access the response regardless of the status code. However, you need to construct the requests and read the responses manually and so you lose the advantage of having a user-friendly automatically-generated proxy. Additionally, there are security restrictions on Silverlight code calling out to JavaScript, and this does not work for cross-domain access to services. Thus, this approach is probably not appropriate for most scenarios, but it is there as a last resort.
Basic Error Handling when Calling Services
Let's now consider the case where you don't actually care about getting any details about a web service fault. All you want to know is whether the call succeeded or not, and to handle the failure gracefully.
The normal way to invoke a service through a proxy is to call the ...Async method, and handle the result in the ...Completed event. For example, you set up the GetCurrentTemperatureCompleted event handler, and then call GetCurrentTemperatureAsync whenever you want to invoke the service.
However, when the call fails, you see exceptions thrown even before your GetCurrentTemperatureCompleted method starts executing, and there appears to be no way to catch them. What is going on?
Luckily, this was a temporary bug in Silverlight 2 Beta 2, and in the final version of Silverlight 2 this will all work correctly, as follows:
GetCurrentTemperatureCompleted always executes, regardless of whether the call succeeded or failed. If you try to access the Result property on the object that's passed to this method, and the call failed, an exception will be thrown (which you can catch). Also, you can check the Error property, which will be non-null only if the call failed.
Showing posts with label silverlight. Show all posts
Showing posts with label silverlight. Show all posts
Sep 30, 2008
Oct 25, 2007
Introducing Basic Back-End Services: From AJAX to Silverlight
My previous post describes the overall problem of communicating with services from Silverlight. Let's now concentrate on one specific but very important part of it: "basic back-end services" (and by the way, if you can think of a better name for this please let me know :)
What I mean by "basic back-end services" is services that you write specifically for your Silverlight app.
Let's take an example: Suppose you want to create an interactive shopping application (something like this or even this). Your users will search for products, add them to a shopping cart, enter payment information, and so on. Clearly some information needs to flow between the browser and the back-end server for this to work.
Traditionally (in the pre-AJAX world) if you wanted to do this on the Microsoft platform, you would create a bunch of .aspx pages in ASP.NET that would communicate with the server using postbacks. When a user entered a search string and hit "Search", it would generate a POST to the server, which would then respond with a newly-generated page.
AJAX eliminated the need for page refreshes, and introduced the notion of "back-end services". These services process very specific information and return very specific replies instead of resending the entire page after every request. In this model, when the user hits "Search", a request is sent to the back-end service which replies with just the search results (instead of an entire HTML page that happens to contain the results). It is the job of JavaScript code to then integrate these results with the rest of the page.
Again, if we look at the Microsoft platform, ASP.NET AJAX makes this very easy with the UpdatePanel control: you don't need to write any code and you don't have to even know that these back-end services are there - you can think of them as being created automatically for you.
There are limits to what the UpdatePanel can do, and so to get more flexibility you will need to write custom services (and the JavaScript code that uses them) yourself. With ASP.NET AJAX, there are different options to write them (page methods, .asmx services, WCF services), but it all essentially boils down to the same thing: you are using JavaScript to remotely call a method. The "Search" button on your shopping site will essentially call something like GetProductList("searchString") on your back-end server, "Add To Cart"will call something like AddToCart(productId), and so on.
Notice that these back-end methods are very specific to your particular application - they are normally written specifically for this purpose and not reused for anything else. This is exactly the basic back-end services that this post is about. The opposite of this case is the interoperability problem - talking to services that have already been established for purposes other than your specific application and that you cannot change - but I will cover that separately.
So how do basic back-end services work in Silverlight? Well, in 1.0 you cannot call them from within the Silverlight app itself - your only option is to use JavaScript on the page that hosts your Silverlight control and use all of the AJAX techniques I described above.
In 1.1, you will be able to call services directly from .NET code in your Silverlight application. I will explain how in the next post.
What I mean by "basic back-end services" is services that you write specifically for your Silverlight app.
Let's take an example: Suppose you want to create an interactive shopping application (something like this or even this). Your users will search for products, add them to a shopping cart, enter payment information, and so on. Clearly some information needs to flow between the browser and the back-end server for this to work.
Traditionally (in the pre-AJAX world) if you wanted to do this on the Microsoft platform, you would create a bunch of .aspx pages in ASP.NET that would communicate with the server using postbacks. When a user entered a search string and hit "Search", it would generate a POST to the server, which would then respond with a newly-generated page.
AJAX eliminated the need for page refreshes, and introduced the notion of "back-end services". These services process very specific information and return very specific replies instead of resending the entire page after every request. In this model, when the user hits "Search", a request is sent to the back-end service which replies with just the search results (instead of an entire HTML page that happens to contain the results). It is the job of JavaScript code to then integrate these results with the rest of the page.
Again, if we look at the Microsoft platform, ASP.NET AJAX makes this very easy with the UpdatePanel control: you don't need to write any code and you don't have to even know that these back-end services are there - you can think of them as being created automatically for you.
There are limits to what the UpdatePanel can do, and so to get more flexibility you will need to write custom services (and the JavaScript code that uses them) yourself. With ASP.NET AJAX, there are different options to write them (page methods, .asmx services, WCF services), but it all essentially boils down to the same thing: you are using JavaScript to remotely call a method. The "Search" button on your shopping site will essentially call something like GetProductList("searchString") on your back-end server, "Add To Cart"will call something like AddToCart(productId), and so on.
Notice that these back-end methods are very specific to your particular application - they are normally written specifically for this purpose and not reused for anything else. This is exactly the basic back-end services that this post is about. The opposite of this case is the interoperability problem - talking to services that have already been established for purposes other than your specific application and that you cannot change - but I will cover that separately.
So how do basic back-end services work in Silverlight? Well, in 1.0 you cannot call them from within the Silverlight app itself - your only option is to use JavaScript on the page that hosts your Silverlight control and use all of the AJAX techniques I described above.
In 1.1, you will be able to call services directly from .NET code in your Silverlight application. I will explain how in the next post.
Oct 24, 2007
Talking to the Outside World from Silverlight 1.1: An Introduction
(This post is basically a recap of the introduction part of my REMIX 07 Boston Talk )
Silverlight applications run in the user's browser. We all know about the rich graphics and interactivity that Silverlight provides. But any real-world application will, at some point, need to communicate with the "outside world".
This interaction can take many forms. The simplest one (at least from a developer's point of view) is accessing media from some remote server: you can display an image or play a video from any URL. This capability exists even in the 1.0 version of Silverlight. However, it is limited to only certain types of data - images, videos and sounds.
The next step up is being able to work with arbitrary blobs of data and then write code to make sense of them. In 1.0, your only option was to use JavaScript on the page that hosts your Silverlight control. You could use standard AJAX techniques: use XmlHttpWebRequest to GET any data from some HTTP location and then use JavaScript to adjust your Silverlight graphics accordingly. You could also POST any data to some HTTP location.
In 1.1, there is no need for external JavaScript - you can use the BrowserHttpWebRequest .NET class (a subclass of HttpWebRequest) directly from your Silverlight application to issue GET/POST requests with a Stream of bytes.
But what if you want to work with more than just bytes? Most data has some structure to it: You may be receiving data in XML or JSON format that you will want to parse, or getting an RSS feed that you want to process and then display, or you may be talking to a SOAP service that actually describes its structure using metadata. In other words, you are not just working with bytes but with products, search results or high scores - data that matters to your app. The data may come from a service you yourself create, or from some "mashup-friendly" source like Flickr or Facebook.
This is exactly the problem I am working on within the overall Silverlight effort, and what many of the posts here will be about - how do we make it easy to work with structured data - that is, how do you consume "services" (in the widest sense of the word)? Watch this blog to discover what is planned in this space, and of course leave comments if you have any ideas or feedback!
I should note that most of the information here will be about SL1.1. In the existing SL1.0 (and in 1.1 as well of course) you can use all of the usual AJAX techniques as I already mentioned. In fact, Fritz Onion did a great talk at REMIX on integrating Silverlight 1.0 with ASP.NET AJAX - you can do some pretty powerful things with this combination - check out the Channel9 videos (Parts 1 2 3 4) and sample code.
Silverlight applications run in the user's browser. We all know about the rich graphics and interactivity that Silverlight provides. But any real-world application will, at some point, need to communicate with the "outside world".
This interaction can take many forms. The simplest one (at least from a developer's point of view) is accessing media from some remote server: you can display an image or play a video from any URL. This capability exists even in the 1.0 version of Silverlight. However, it is limited to only certain types of data - images, videos and sounds.
The next step up is being able to work with arbitrary blobs of data and then write code to make sense of them. In 1.0, your only option was to use JavaScript on the page that hosts your Silverlight control. You could use standard AJAX techniques: use XmlHttpWebRequest to GET any data from some HTTP location and then use JavaScript to adjust your Silverlight graphics accordingly. You could also POST any data to some HTTP location.
In 1.1, there is no need for external JavaScript - you can use the BrowserHttpWebRequest .NET class (a subclass of HttpWebRequest) directly from your Silverlight application to issue GET/POST requests with a Stream of bytes.
But what if you want to work with more than just bytes? Most data has some structure to it: You may be receiving data in XML or JSON format that you will want to parse, or getting an RSS feed that you want to process and then display, or you may be talking to a SOAP service that actually describes its structure using metadata. In other words, you are not just working with bytes but with products, search results or high scores - data that matters to your app. The data may come from a service you yourself create, or from some "mashup-friendly" source like Flickr or Facebook.
This is exactly the problem I am working on within the overall Silverlight effort, and what many of the posts here will be about - how do we make it easy to work with structured data - that is, how do you consume "services" (in the widest sense of the word)? Watch this blog to discover what is planned in this space, and of course leave comments if you have any ideas or feedback!
I should note that most of the information here will be about SL1.1. In the existing SL1.0 (and in 1.1 as well of course) you can use all of the usual AJAX techniques as I already mentioned. In fact, Fritz Onion did a great talk at REMIX on integrating Silverlight 1.0 with ASP.NET AJAX - you can do some pretty powerful things with this combination - check out the Channel9 videos (Parts 1 2 3 4) and sample code.
Subscribe to:
Posts (Atom)