Skip to main content
Home Forums Silverlight Programming Programming with .NET - General Getting the actual Exception thrown from a WebService (not just a 404 / ProtocolException)
10 replies. Latest Post by ticcoid on April 3, 2009.
(0)
spoo
Member
21 points
43 Posts
07-03-2008 2:31 PM |
I'm calling a web service from my Silverlight application, but if any of the web service methods throw an Exception, I'm just getting a ProtocolException in the BeginInvoke() call for the generated proxy code for the web service method, instead of the actual Exception the web service threw.
E.g.the method could be something like:
[WebMethod]public void GetItem(/* some parameters */){ if (checkAccess()) throw new Exception("you're not allowed to do this"); else { doWhateverIfAllowed(); }}
The .InnerException is null.
The .Message property will be: "The remote server returned an unexpected response: (404) Not Found."
The .StackTrack will be something like:
" at System.ServiceModel.AsyncResult.End[TAsyncResult](IAsyncResult result)\r\n at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result)\r\n at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)\r\n at System.ServiceModel.ClientBase`1.ChannelBase`1.EndInvoke(String methodName, Object[] args, IAsyncResult result)\r\n at Schedule.ScheduleProxyServiceReference.ScheduleProxyWebServiceSoapClient.ScheduleProxyWebServiceSoapClientChannel.EndAddItem(IAsyncResult result)\r\n at Schedule.ScheduleProxyServiceReference.ScheduleProxyWebServiceSoapClient.Schedule.ScheduleProxyServiceReference.ScheduleProxyWebServiceSoap.EndAddItem(IAsyncResult result)\r\n at Schedule.ScheduleProxyServiceReference.ScheduleProxyWebServiceSoapClient.EndAddItem(IAsyncResult result)\r\n at Schedule.ScheduleProxyServiceReference.ScheduleProxyWebServiceSoapClient.OnEndAddItem(IAsyncResult result)\r\n at System.ServiceModel.ClientBase`1.OnAsyncCallCompleted(IAsyncResult result)"
(ScheduleProxyService is the web service)
And before someone starts suggesting this; NO, it's not a missing cross-domain policy file. The web services work fine as long as they don't throw any exceptions.
Is there no way of getting the actual Exception from the web service?
(And why am I getting a 404 here?? Shouldn't the WS return a 501 if there's was an internal error? :P)
Edit: if I open up the WS in IE and call the method that throws an exception, I'm actually getting a "500" response. Is there something else I have to do to make the WS pass on the exceptions? (This is through SOAP)
sladapter
All-Star
17439 points
3,172 Posts
07-03-2008 2:46 PM |
In this thread we talked about how to catch WCF exception and pass it back to Silverlight. For WCF it's little easier because we can add CustomException filed to all the return object from WCF so we do not need to do any seralization. For asmx call you also need to catch the exception at all your WebMethod and serialize it to some form. If all your returning data is packaged in xml, you can always insert a error element and error message in that xml so you can parse it back on Silverlight side.
http://silverlight.net/forums/p/17944/60019.aspx#60019
Some one also suggested using a out paramter to pass exception back in all WCF call. You can try the same in asxm call, I don't think you can pass the custom exception object back, but you can try to pass the error message (string type) back.
http://silverlight.net/forums/p/18885/64303.aspx#64303
07-03-2008 3:07 PM |
Hm, well so, testing the .asmx from the browser gives this text only, not even enveloped in XML - but literally just this - as content-type text/plain. Why doesn't the WS envelope this in a SOAP fault message? (Output of: throw new Exception("failed!") )
System.Exception: failed! at Schedule_Web.MiscWebService.DummyFail() in C:\work\dotnet_sl_schedule\Schedule\Schedule_Web\MiscWebService.asmx.cs:line 152
I see what you're saying with wrapping it in a result -- sure.... I could do that.
But aren't there any ways of getting this eveloped as a SOAP-fault response?
E.g. http://msdn.microsoft.com/en-us/library/aa480514.aspx says I should be getting that message wrapped something like:
<soap:Fault> <faultcode>soap:Server</faultcode> <faultstring>System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.Exception: Something bad happened at AYS17Sept2002.Service1.CallFault() in c:\inetpub\wwwroot\AYS17Sept2002\Service1.asmx.vb:line 49 --- End of inner exception stack trace ---</faultstring> <detail /></soap:Fault>
Is this some configuration error from my side, or is it some attributes I have to decorate the WS with, or what?
I'll admit I'm a noob at doing WSes from .NET based stuff. :)
07-03-2008 3:16 PM |
spoo:But aren't there any ways of getting this eveloped as a SOAP-fault response?
Not with current Silverlight. Maybe later, I don't know. I wish they do.
07-03-2008 3:22 PM |
Ok, thanks for the answer.
This is - to speak honestly - rather lame, but oh well. I'll just have to resort to passing the error string as part of the result set then.
Thanks.
sravoux
4 points
2 Posts
09-22-2008 4:04 AM |
My solution is :
Something like this :
[OperationContract] public void Hello() { try { … } catch (Exception ex) {
// NB: I give a nice context's message in UserState parameter HandleError("The hello method failed", ex); } } [DataContract] public class ErrorInfos { [DataMember] public string Message; [DataMember] public string Details; } private void HandleError(string message, Exception ex) { var error = new ErrorInfos() { Message = message , Details = null }; if (ex != null) { // Ajout du détails de l'exception error.Details = ex.ToString(); // Ajout du message de la premiere exception dans le message while (ex.InnerException != null) { ex = ex.InnerException; } error.Message += " (" + ex.Message + ")"; } // Mémorisation de l'erreur en session (Workaround du bug SL2 Beta 2) if (HttpContext.Current != null) { HttpContext.Current.Session["LastError"] = error; } // Génération d'une faute SOAP (NB: pas géré par SL2 Beta2) throw new FaultException(new FaultReason(error.Message)); } [OperationContract] public ErrorInfos GetLastError() { ErrorInfos error = null; if (HttpContext.Current != null) { error = (ErrorInfos)HttpContext.Current.Session["LastError"]; return error; } }
On the SL2 client :
private void OnXxxCompleted(object sender, AsyncCompletedEventArgs e) { try { var result = e.Result; //… } catch (ProtocolException ex) { CompleteAndDisplayError(ex); } } public static void CompleteAndDisplayError(string msg, Exception e) { var client = ServicesManager.GetClient(); client.GetLastErrorCompleted += new EventHandler(OnGetLastErrorCompleted); client.GetLastErrorAsync(msg); } private static void OnGetLastErrorCompleted(object sender, GetLastErrorCompletedEventArgs e) { if (!e.Cancelled && e.Error == null) { DisplayError(e.Result.Message, e.Result.Details); } else { DisplayError(e.UserState as string); } }
ticcoid
10 points
31 Posts
04-02-2009 7:15 AM |
hey, thank you for that code. i rebuilt it but there is always a runtime error. something like the exceptions are not handling by usercode. sry this is not the exact error because i translate it from german. but maybe you know what it can be. thank you
04-02-2009 9:54 AM |
The best solution for catching Exception thrown in WCF is given in this blog: http://blogs.msdn.com/silverlightws/
The sample code can download from here: http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=silverlightws&DownloadId=3473
The code they provided is very straightforward without having to change much of the current code. You do not have to do anything on the WCF end. All you need to do to create BasicHttpMessageInspectorBinding instead of BasicHttpBinding and pass it to the Service constructor. Then the e.Error should return the exceptions thrown from the Service end.
04-02-2009 6:01 PM |
thank you, i tested your approach from an other thread and it works fine. you said that the solution in that blog is the best. but which do you mean? i cant find catching exception in this blog. thank you
04-03-2009 9:29 AM |
You need to download the sample code from this link:
http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=silverlightws&DownloadId=3473
And run the SilverlightRawFault sample project you can see what I mean this is the best solution so far for handling the error thrown from WCF. If you take a look at WCF Service.svc.cs code you can see the DoWork function just throw an exception. There is nothing special in the service code. You just write your service code as you normally do. But the error thrown from WCF will be catched in the Silverlight end. All you need to do is the following:
1) Add reference of SilverlightFaultBehavior.dll (which is included in the sample files) to the Web project, and add the following behavior to the Web.config file:
<system.serviceModel> <extensions> <behaviorExtensions> <add name="silverlightFaults" type="Microsoft.Silverlight.Samples.SilverlightFaultBehavior, SilverlightFaultBehavior, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> </behaviorExtensions> </extensions> <behaviors> <endpointBehaviors> <behavior name="SilverlightFaultBehavior"> <silverlightFaults/> </behavior> </endpointBehaviors>
...
</system.serviceModel>
2) Add reference of SilverlightMessageInspector.dll (included in the sample) to the Silverlight project.
3) Add SilverlightFaultMessageInspector.cs (included in the sample) to your Silverlight project or your Silverlight Library project.
4) Change your WCF calling code to the following:
YourServiceClient proxy = new YourServiceClient(); // Your WCF service default consturctor
EndpointAddress address = new EndpointAddress("http://localhost:52620/Service.svc"); BasicHttpMessageInspectorBinding binding = new BasicHttpMessageInspectorBinding(new SilverlightFaultMessageInspector()); ServiceClient proxy = new ServiceClient(binding, address); // Use this WCF service constructor, pass new binding proxy.DoWorkCompleted += new System.EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(proxy_DoWorkCompleted); proxy.DoWorkAsync(); //code to call WCF
void proxy_DoWorkCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) { if (e.Error != null)
{
if(e.Error is RawFaultException) // Now you can catch the Exception thrown from WCF { RawFaultException exception = (RawFaultException)e.Error; MessageBox.Show("Service says: " + exception.FaultMessage + Environment.NewLine + "Exception type: " + exception.FaultType + Environment.NewLine + "Stack trace: " + exception.StackTrace); }
else // None WCF error
MessageBox.Show(e.Message);
}
04-03-2009 5:04 PM |
big big thank you sladapter. works very good.