WP7: Unable to catch FaultException in asynchronous calls to WCF service - wcf

I am currently developing a Windows Phone 7 App that calls a WCF web service which I also control. The service offers an operation that returns the current user's account information when given a user's login name and password:
[ServiceContract]
public interface IWindowsPhoneService
{
[OperationContract]
[FaultContract(typeof(AuthenticationFault))]
WsAccountInfo GetAccountInfo(string iamLogin, string password);
}
Of course, there is always the possibility of an authentication failure and I want to convey that information to the WP7 app. I could simply return null in that case, but I would like to convey the reason why the authentication failed (i.e. login unknown, wrong password, account blocked, ...).
This is my implementation of the above operation (for testing purposes, all it does is throwing an exception):
public WsAccountInfo GetAccountInfo(string iamLogin, string password)
{
AuthenticationFault fault = new AuthenticationFault();
throw new FaultException<AuthenticationFault>(fault);
}
Now, if I call this operation in my WP7 app, like this:
Global.Proxy.GetAccountInfoCompleted += new EventHandler<RemoteService.GetAccountInfoCompletedEventArgs>(Proxy_GetAccountInfoCompleted);
Global.Proxy.GetAccountInfoAsync(txbLogin.Text, txbPassword.Password);
void Proxy_GetAccountInfoCompleted(object sender, RemoteService.GetAccountInfoCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
return;
}
}
The debugger breaks in Reference.cs, saying that FaultException'1 was unhandled, here:
public PhoneApp.RemoteService.WsAccountInfo EndGetAccountInfo(System.IAsyncResult result) {
object[] _args = new object[0];
PhoneApp.RemoteService.WsAccountInfo _result = ((PhoneApp.RemoteService.WsAccountInfo)(base.EndInvoke("GetAccountInfo", _args, result)));
return _result;
}
BEGIN UPDATE 1
When pressing F5, the exception bubbles to:
public PhoneApp.RemoteService.WsAccountInfo Result {
get {
base.RaiseExceptionIfNecessary(); // <-- here
return ((PhoneApp.RemoteService.WsAccountInfo)(this.results[0]));
}
}
and then to:
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
{
// An unhandled exception has occurred; break into the debugger
System.Diagnostics.Debugger.Break();
}
}
After that, the app terminates (with or without the debugger).
END UPDATE 1
Now, I would love to catch the exception in my code, but I am never given the chance, since my Completed handler is never reached.
Based on similar questions on this site, I have already tried the following:
Re-add the service reference --> no change
Re-create a really simple WCF service from scratch --> same problem
Start the app without the debugger to keep the app from breaking into the debugger --> well, it doesn't break, but the exception is not caught either, the app simply exits
Tell VS 2010 not to break on FaultExceptions (Debug > Options) --> does not have any effect
wrap every line in my app in try { ... } catch (FaultException) {} or even catch (Exception) --> never called.
BEGIN UPDATE 2
What I actually would like to achieve is one of the following:
ideally, reach GetAccountInfoCompleted(...) and be able to retrieve the exception via the GetAccountInfoCompletedEventArgs.Error property, or
be able to catch the exception via a try/catch clause
END UPDATE 2
I would be grateful for any advice that would help me resolve this issue.

The framework seems to read your WsAccountInfo.Result property.
This rethrows the exception on client side.
But you should be the first to read this property.
I don't know your AuthenticationFault class, does it have a DataContractAttribute and is it a known type like the example in
http://msdn.microsoft.com/en-us/library/system.servicemodel.faultcontractattribute.aspx ?

I believe I had the same problem. I resolved it by extending the proxy class and calling the private Begin.../End... methods within the Client object rather than using the public auto-generated methods on the Client object.
For more details, please see:
http://cbailiss.wordpress.com/2014/02/09/wcf-on-windows-phone-unable-to-catch-faultexception/

Related

return type for wep api for easy error handling

I have a web api which I call from my angularjs application. I have a method where (if all is OK) I return a list of strings. But if something goes wrong and I catch an exception, how should I handle this?
I'm quite new to this and I'm wondering how I should do about error handling? Are there any best practices for what return type I should use in a case like this?
1.
[HttpGet]
[Route("{user}")]
public IHttpActionResult GetItems(string user)
{
try
{
return Ok(adObject.GetItems(user)); //List of strings
}
catch (Exception e)
{
//return e how? Or log error? Both?
throw;
}
}
2.
[HttpGet]
[Route("{user}")]
public List<string> GetItems(string user)
{
return adObject.GetItems(user);
}
You should return a 500 http status code with enough information to tell the UI that an error occurred without revealing the inner workings of the API. For instance, you might say "unable to insert a new record". If the error is a result of the UI sending bad data, you would instead send a 400 series status code such as a 422.
To do all of this, there are two options. You can simply send back an InternalServerError like this:
[HttpGet]
[Route("{user}")]
public IHttpActionResult GetItems(string user)
{
try
{
return Ok(adObject.GetItems(user)); //List of strings
}
catch (Exception e)
{
Return InternalServerError();
LogError(e);
}
}
Which will just return a 500 error and log the the exception (you would need to write the LogError method).
You could also call ResponseMessage instead of InternalServerError and return your own HttpResponseMessage with more detail on the problem. Both of these methods are on the ApiController if you want to investigate their signatures or see others that you might be able to use.
The other option is to create a custom exception filter that inherits from ExceptionHandler. A good example of how to do this is available on this website:
http://www.brytheitguy.com/?p=29
Hope that helps.

Exception handling in Controller in ASP.Net MVC 4 with ELMAH and ajax

I've seen a number of posts and articles but am not able to see the solution crisply.
I've installed Elmah.MVC via NuGet and have commented out this line from FilterConfig.cs:
//filters.Add(new HandleErrorAttribute());
So that Elmah would pick up the errors.
It works when I provide an invalid action name and I get a yellow page as well as an email.
I want to know about two other types of errors that my code may generate... how are we supposed to handle them:
1.E.g. if my repository or manager (business logic) layer throws an exception when trying to access database or send an email etc.
a. Is the correct way to NOT implement any kind of try catch in Controllers (or anywhere else for that matter) and let Elmah take care of exceptions?
b. If so, and if it shows a yellow error page, how can we show a view of our own liking?
2.If my view contains ajax calls, e.g. via jqgrid, and behind the scenes there are errors, I've noticed they also get picked up properly by Elmah. But how do I show some kind of an error message to the user as well?
Thanks
Here is what I did:
In controller, I placed try catch:
try
{
//model = getmodelfromdb();
return View("MyView", model);
}
catch (Exception ex)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
return View("../Error/ShowException", ex);
}
For custom view for 404, I did this in global.asax:
protected void Application_OnError( )
{
var exception = Server.GetLastError( );
Elmah.ErrorSignal.FromCurrentContext().Raise(exception);
Helper.SetSessionValue(SessionKeys.EXCEPTION, exception);
Response.Redirect( "~/Error/ShowException");
}
For jqgrid, I did this in my controller:
[HttpPost]
public ActionResult ListRecords( int page , DateTime? fromdate , DateTime? todate)
{
try
{
var list = FetchListFromDB();
var result = new
{
total = Math.Ceiling(list.Count / (decimal)Helper.PAGE_SIZE),
page = page, //--- current page
records = list.Count, //--- total items
rows = list.List.Select(x => new
{
id = x.EntityID,
cell = new string[]
{
x.Property1,
x.Property2
}
}).ToArray()
};
return Json(result, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
var result = new
{
errorMessage = "An unexpected error occurred while fetching data. An automatic email has been generated for the support team who will address this issue shortly. Details: " + ex.Message,
records = 0
};
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
return Json(result, JsonRequestBehavior.AllowGet);
}
And this in the View (in the jqgrid definition):
loadComplete:function(data)
{
if (data.errorMessage)
{
alert(data.errorMessage);
}
},
In a general ajax scenario:
success: function(data)
{
if (data.errorMessage)
{
alert(data.errorMessage);
}
else
{
//...
}
},
a. Is the correct way to NOT implement any kind of try catch in Controllers (or anywhere else for that matter) and let Elmah take care of exceptions?
I'd say that Elmah doesn't "take care" of exceptions, it records them. Ideally, you should try to handle the errors - by all means log them, but also add logic to deal with them so that they don't interrupt the user's workflow.
I'd wrap logic in try blocks, and in the catch use
Elmah.ErrorSignal.FromCurrentContext().Raise(exception);
to record anything that goes wrong. Immediately after that line, however, I'd then do something to try to recover from the exception - catch specific exception types, never just catch (Exception e), and deal with them after logging them. The idea is that you should be reviewing your logs, working out what's causing the exceptions, and improving your program so that it doesn't throw exceptions any more.
To show your own error pages, there's the HandleErrorAttribute, or if you don't want to use that there's also the controller's OnException() method, which is called when a controller action method quits with an exception rather than finishing normally. An ExceptionContext object is passed into that method, so you can use that to get the exception that was thrown and log it, do any cleanup that might be required etc.
I know i'm very late to the party but I stumbled upon this answer while searching something similar form Google.
I don't like using try catch blocks everywhere in my code, especially in web apps. I let Elmah catch everything and log it behind the scenes. Then in the web.config file you can redirect based on the error type...
<customErrors mode="RemoteOnly" defaultRedirect="~/Error" >
<error statusCode="500" redirect="~/Error"/>
<error statusCode="404" redirect="~/NotFound"/>
</customErrors>

WCF Streaming - who closes the file?

According to Microsoft's samples, here's how one would go about streaming a file throuhg WCF:
// Service class which implements the service contract
public class StreamingService : IStreamingSample
{
public System.IO.Stream GetStream(string data)
{
//this file path assumes the image is in
// the Service folder and the service is executing
// in service/bin
string filePath = Path.Combine(
System.Environment.CurrentDirectory,
".\\image.jpg");
//open the file, this could throw an exception
//(e.g. if the file is not found)
//having includeExceptionDetailInFaults="True" in config
// would cause this exception to be returned to the client
try
{
FileStream imageFile = File.OpenRead(filePath);
return imageFile;
}
catch (IOException ex)
{
Console.WriteLine(
String.Format("An exception was thrown while trying to open file {0}", filePath));
Console.WriteLine("Exception is: ");
Console.WriteLine(ex.ToString());
throw ex;
}
}
...
Now, how do I know who's responsible for releasing the FileStream when the transfer is done?
EDIT: If the code is put inside a "using" block the stream gets shut down before the client receives anything.
The service should clean up and not the client. WCF's default for OperationBehaviorAttribute.AutoDisposeParameters seems to be true, therefore it should do the disposing for you. Although there doesn't seem to be a fixed answer on this.
You could try using the OperationContext.OperationCompleted Event:
OperationContext clientContext = OperationContext.Current;
clientContext.OperationCompleted += new EventHandler(delegate(object sender, EventArgs args)
{
if (fileStream != null)
fileStream.Dispose();
});
Put that before your return.
Check this blog
Short answer: the calling code, via a using block.
Long answer: sample code should never be held up as an exemplar of good practice, it's only there to illustrate one very specific concept. Real code would never have a try block like that, it adds no value to the code. Errors should be logged at the topmost level, not down in the depths. Bearing that in mind, the sample becomes a single expression, File.OpenRead(filePath), that would be simply plugged into the using block that requires it.
UPDATE (after seeing more code):
Just return the stream from the function, WCF will decide when to dispose it.
The stream needs to be closed by party who is responsible to read it. For example, if service returns the stream to client, it's client application responsibility close the stream as Service doesn't know or have control when client finishes reading stream. Also, WCF will not take care of closing the stream again because of the fact that it doesn't know when receiving party has finished reading. :)
HTH,
Amit Bhatia

How to prevent transaction scope from throwing an exception I have already handled?

I've got a WCF operation conceptually like this:
[OperationBehavior(TransactionScopeRequired = true)]
public void Foo()
{
try { DAL.Foo(); return Receipt.CreateSuccessReceipt(); }
catch (Exception ex) { return Receipt.CreateErrorReceipt(ex); }
}
If something goes wrong (say, foreign key constraint violaion) in executing the DAL code, control passes to the catch block as I'd expect. But when the method returns, it seems the transaction scope has sniffed out that the transaction failed, and it decides it better throw an exception to make sure to notify the caller about it.
In turn my client application does not get the receipt I want to return, but rather an exception:
System.ServiceModel.FaultException:
The transaction under which this method call was executing was asynchronously aborted.
What is wrong with my design?
I could have the service not catch anything, but this has it's own problems as the service needs to use exception shielding and the client (a batch tool internal to the system) needs to log the error information. The service logs errors too, but not in the same way and to the same place as the batch.
Be careful here! If you set TransactionAutoComplete=true then if the service returns normally the transaction will be committed. Only if there is an unhandled exception (which for the most part you don't have because you are catching exceptions and returning a receipt message) will the transaction be rolled back. See http://msdn.microsoft.com/en-us/library/system.servicemodel.operationbehaviorattribute.transactionautocomplete.aspx.
Think about a scenario where you successfully executed some DAL calls but some other exception (e.g. NullReferenceException) occurs. Now the transaction will be committed when the method completes because no unhandled exception has occurred but the client receives an ErrorReceipt.
For your scenario, I think you will have to manage the transactions yourself. For example:
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
public Receipt Foo()
{
// Create TransactionScope using the ambient transaction
using (var scope = new TransactionScope() )
{
try { DAL.Foo(); return Receipt.CreateSuccessReceipt(); scope.Complete(); }
catch (Exception ex) { return Receipt.CreateErrorReceipt(ex); }
}
}
You could eliminate boilerplate code by creating a helper method that wraps it all within the transaction or you could use policy injection/interception/aspects to manage transactions.
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
public Receipt Foo()
{
return ProcessWithTransaction(() =>
{
DAL.Foo();
return Receipt.CreateSuccessReceipt();
}
, (ex) =>
{
return Receipt.CreateErrorReceipt(ex);
}
);
}
T ProcessWithTransaction<T>(Func<T> processor, Func<Exception, T> exceptionHandler)
{
using (var scope = new TransactionScope())
{
try
{
T returnValue = processor();
scope.Complete();
return returnValue;
}
catch (Exception e)
{
return exceptionHandler(e);
}
}
}
You mention that you need to use exception shielding. If you are not averse to throwing faults when an error occurs then you could use Enterprise Library Exception Handling Block's exception shielding which also lets you log the information on the way out (if you desire).
If you decided to go that route your code would look something like this:
[OperationBehavior(TransactionScopeRequired = true)]
public void Foo()
{
// Resolve the default ExceptionManager object from the container.
ExceptionManager exManager = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();
exManager.Process(() =>
{
DAL.Foo();
return Receipt.CreateSuccessReceipt();
},
"ExceptionShielding");
}
Enterprise Library (via configuration) would then catch any exceptions and replace them with a new FaultException that is returned to the client.
[OperationBehavior(TransactionAutoComplete = true, TransactionScopeRequired = true)]
Presumably because the transaction is now rolled back as soon as the error occurs, rather than asynchronously when the scope goes out of scope :D, this behaves like I expected things to behave originally, and I can leave my design as it is.
(I had already written up the question when trying this occured to me. Hopefully posting it Q&A style will be more helpful than not posting the question at all.)

Error Handling in WCF Service

With the following service method example:-
[PrincipalPermission(SecurityAction.Demand, Role="BUILTIN\\Administrator")]
public string GetTest()
{
try
{
return "Hello";
}
catch (Exception ex)
{
throw ex;
}
}
How do I get an error from the method when the caller is not in the correct Role. In design time the error breaks on the method line (i.e. public string GetTest) and does not reach the catch. At run time it is reported in my silverlight application as an unhandled error (I have try.. catch blocks there too).
There doesn't seem to be a place to catch the error as it never gets into the try blocks!!
The check for the role is made (by the WCF runtime) before the method is actually called - not inside the method!
You need to handle this exception on the caller's side when you make this call.
If you need to check certain conditions inside your service code, don't decorate the method with an attribute, but instead use the role provider in code to check for a given condition.
If you want global error handler for your WCF service you can implement IErrorHandler and add it in custom behavior. Operation can't catch exceptions thrown outside of its try block.