Does returning IHttpActionResult stop request execution - c#

Here #GlennBlock mentioned that throwing HttpResponseException immediately stops request execution while returning HttpResponseMessage does not stop request propagation (as I understood it).
The exception is useful to immediately stop processing and exit.
If instead I return HttpResponseMessage, the request will happily continue the rest of it's processing and return a 404. The main difference being end the request or not.
In .NET Web API 2 you can also return IHttpActionResult from ApiController. Does it stop request propagation or it works similar to HttpResponseMessage?
Thank you;)

I think #GlennBlock is technically wrong here. Throwing an HttpResponseException does not do anything significantly different than returning an HttpResponseMessage.
Here is the pattern used in ASP.NET Web API courtesy of the source code:
try
{
return await SendAsyncCore(request, cancellationToken);
}
catch (HttpResponseException httpResponseException)
{
return httpResponseException.Response;
}
catch (Exception exception)
{
exceptionInfo = ExceptionDispatchInfo.Capture(exception);
}
At this point in the pipeline if you had thrown an HttpResponseException it gets treated the same as if you returned an HttpResponseMessage... it behaves exactly the same.
One thing you will notice is that when debugging with Visual Studio the debugger will break on a thrown HttpResponseException (since the catch is not happening in user code). If it's an expected error that happens commonly in normal operation of your site then this can get really annoying! In this case you probably instead want to return an error code with HttpResponseMessage.
On the other hand, if it's a bizarre error which should theoretically not happen then you want to be alerted by the debugger. You don't want the error to be quietly ignored. You want to know about it so you can theoretically fix it. In this case throwing the HttpResponseException makes more sense.
About the only other difference I can tell is that throwing an HttpResponseException allows you to catch it with an IExceptionFilter. Similar to how you can apply an action filter or an authorization filter to a method or controller, you can apply an exception filter to handle all exceptions. Perhaps you want to log them in your database. It's obviously a lot easier to apply an attribute filter than to have to write a try/catch in every single action method.
In this case throwing an exception actually does more work and takes longer than simply returning a response. But it is one difference.
An IHttpActionResult is used to create an HttpResponseMessage. Think of it as a HttpResponseMessage factory where you can write it once and use it by multiple action methods. In this case you could throw the HttpResponseException from within the IHttpActionResult. It's not any different than doing it directly from the action.

Related

OnActionExecutionAsync "result = new NotFoundObjectResult" does not change the result

I am trying to use ActionFilters to capture the result in my api call and change it if needed.
But it appears to change only the object i pass not the result type. (from OK to BadRequest)
return Ok(await _Data.Remove());
The above code in my controller leads to my filter:
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var resultContext = await next();
Guid userId = await _data.GetId();
BaseModel baseModel = (BaseModel)((ObjectResult)resultContext.Result).Value;
if (baseModel.ApiResponse == ApiResponse.AllGood)
{
BaseModel m = _data.GetBaseModel(userId);
m.ApiResponse = baseModel.ApiResponse;
resultContext.Result = new OkObjectResult(m);
}
else if (baseModel.ApiResponse == ApiResponse.NotFound)
resultContext.Result = new NotFoundObjectResult(baseModel);
else
resultContext.Result = new BadRequestObjectResult(baseModel);
}
The model is correctly captured and i can check against its contents. And i can change it and pass it back. But it always goes back to the controller and then returns the "ok" with the new model.
What i want is it returning BadRequest
I have tried putting doing this:
resultContext.Result = new BadRequestObjectResult(baseModel);
As you can see from the above code, but it does not work.
The reason you cannot get it to work, is because this approach isn't possible (in the general case, at least).
The async variant of the ActionFilter combines both the pre and post variants of the synchronous variant, in one callback, by giving you next().
Once you have called and successfully returned from next(), you are in 'executed' land, not 'executing' land anymore.
The trouble is, if next() has started sending the response to the client, it is too late to change the response. Your receiving client may already sit with 'http 200 ok' in his hand!
You can observe this, by trying to write to the response in context.HttpContext.Response (You can set the Http Status Code on it, and use WriteAsync on it),
in the spot where you attempt to modify Result.
If next had already started the response, you'll get a direct exception telling you this.
However, IF next() hadn't begun the response, you may actually be able to control the response.
A last-resort option you have, is to throw at this point, it will (mostly) break your http response into http-500 server error. This may or may not be good for your client.
Lastly, your resultContext actually has a 'Cancelled' attribute which you can flag.
However I don't know if that has any effect if the response has already begun (it might affect the middleware server side).
In my own case for this, I concluded it was the wrong place to solve our issue, so I moved our necessary handling to a wrapper in the controller method return statement.
I.e. you then get
return wrapper(OK(response));
where wrapper will decide whether to pass on OK(..) unharmed.
If you use this approach, be careful if you had
return OK(responseWIthSideEffect(..));
in that case, you must make sure the side effect code is forced to execute,
before your wrapper makes its decision (i.e. assuming the wrapper checks something that might depend on that side effect).

How to make elmah.io work well with ASP.NET Core and error handing middleware?

Note: this question is regarding elmah.io (https://elmah.io/), the cloud based exception logging service, and not the traditional Elmah .Net library.
I'm using ASP.NET Core and have a simple exception handling middleware.
public class HandleExceptionMiddleware
{
public HandleExceptionMiddleware(RequestDelegate next)
{
Next = next;
}
RequestDelegate Next { get; }
public async Task Invoke(HttpContext httpContext)
{
try
{
await Next(httpContext);
}
catch (Exception ex)
{
await HandleExceptionAsync(httpContext, ex);
}
}
Task HandleExceptionAsync(HttpContext context, Exception ex)
{
var code = HttpStatusCode.InternalServerError;
if (ex is ArgumentException)
code = HttpStatusCode.BadRequest;
var result = JsonConvert.SerializeObject(new { message = ex.Message });
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)code;
return context.Response.WriteAsync(result);
}
}
This middleware will return the following JSON responses depending on the exceptions that it sees:
For ArgumentException:
HTTP/1.1 400 Bad Request
{"message":""}
For all other exceptions:
HTTP/1.1 500 Internal Server Error
{"message":""}
I'd like elmah.io to log 500 responses and ignore 400 responses (which is the default elmah.io configuration). However, when the exception handler and elmah.io are registered in this order in Startup's Configure hook, nothing gets logged in elmah.io:
app.UseElmahIo("API_KEY", new Guid("LOG_ID"));
app.UseMiddleware<HandleExceptionMiddleware>()
If, however, I change the registration order to the following, everything gets logged (including 400 responses). This makes sense as elmah.io handles the exceptions before HandleExceptionMiddleware gets a chance to change the response:
app.UseMiddleware<HandleExceptionMiddleware>()
app.UseElmahIo("API_KEY", new Guid("LOG_ID"));
What is the best way to configure these services so that elmah.io logs 500 responses and ignores 400 responses?
The only workaround I came up with is to create and register 2 exception handing middlewares instead of just 1. One that registers before and one that registers after elmah.io. It works, but seems a bit ugly:
app.UseMiddleware<HandleInternalExceptionMiddleware>() // set 500 responses (these will have already been logged in elmah.io)
app.UseElmahIo("API_KEY", new Guid("LOG_ID"));
app.UseMiddleware<HandleExternalExceptionMiddleware>() // set 400 responses but ignore exceptions that should return 500 (these won't be logged in elmah.io)
I created a sample project here to demonstrate this behavior:
https://github.com/johnnyoshika/elmah-io-experiment
The correct way to configure elmah.io, is using behavior 2. You want to call the UseElmahIo method after calling other methods dealing with exceptions. This is because a lot of error handling middleware (including your HandleExceptionMiddleware) swallow all exceptions and convert the result to something else. In your case, HandleExceptionMiddleware catches all exceptions and set a new response. In this case, our middleware is never notified about the exception (as you mention as well).
We have a couple of different ways to solve this:
Solution 1
Call UseElmahIo after calling UseMiddleware and add a custom ignore filter to ignore the errors eventually becomming bad requests:
app.UseMiddleware<HandleExceptionMiddleware>();
app.UseElmahIo("API_KEY", new Guid("LOG_ID"), new ElmahIoSettings
{
OnFilter = msg => msg.Type == typeof(ArgumentException).Name
});
The downside of this approach is, that you will need to maintain a set of similar rules in both HandleExceptionMiddleware and in your elmah.io config.
Solution 2
Call UseElmahIo before calling UseMiddleware and specify which status codes to log, even though an exception isn't thrown (swallowed by HandleExceptionMiddleware in this case):
app.UseElmahIo("API_KEY", new Guid("LOG_ID"), new ElmahIoSettings
{
HandledStatusCodesToLog = new List<int> { 404, 500, ... }
});
app.UseMiddleware<HandleExceptionMiddleware>();
The downside if this approach is, that you will need to specify all status codes manually and that the information from the actual exception thrown, isn't available on elmah.io. The reason for this again is, that HandleExceptionMiddleware make it impossible for elmah.io to see that an exception were thrown.
I personally prefer solution 1, since that makes sure that all exceptions are catched, including information like stacktrace and the exception type.

Handle an unreliable/unresponsive SOAP web service or REST API from a C# applicaiton

I don't like error handling via try catch blocks but in this case I did not see any other clear path. In my code I'm calling a web service but it might soon be a rest API in the near future. This web service is external and unfortunately not 100% reliable. What I need to do is create code that can handle an unresponsive web service. Today it looks like this:
SOAP Proxy is set to have a timeout of 120 seconds
var myProxy = new WebReference.ProxyClass();
myProxy.Timeout = 120000;
try
{
CreditInformation creditInformation = myProxy.Retrieve(prospect.CorporateIdentity);
agreement.Company.Name = creditInformation.CompanyName;
agreement.FinancialInformation.NetRevenue = creditInformation.Revenue / 1000;
}
catch (WebException e) when (e.Status == WebExceptionStatus.Timeout)
{
logger.Error("Web service timed out");
}
//Continiue running code even if the web service time out
Is this a bad standard and could it be better performed? As I said before I don't like handling errors via try catch but it seemed viable here. I thought about creating some code to check if the web service was responding but i decided not to go this way. This is because the web service is quite slow, a request takes 30-60 seconds by default and that would leave the user waiting even longer for me to check if it is up. Another solution might be to ping the host but it does not guarantee that the service is actually up. Sample code:
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response != null && response.StatusCode == HttpStatusCode.OK)
{
//Do stuff here
}
There are two opposite camps about how to handle exceptional situations. One camp prefers exceptions, another camp prefers to return error codes (or similar) from a function that might fail in one form or another. What is "better" is arguable and situation-dependent (see for example: http://www.joelonsoftware.com/items/2003/10/13.html for the arguments of "error code" camp). I'm telling this because as I understand you would prefer that myProxy.Retrieve return some error code on timeout, not throwing an exception. It might be reasonable, but that's not how it works and you cannot change that. Whole .NET framework uses exceptions almost everywhere (sometimes in situations which might be considered "part of normal flow", though definition of normal flow is again not trivial).
Long story short - a lot of code you use in .NET will throw exceptions on errors, even in sutations which you consider normal, and you have to live with that and act accordingly - catch and handle them - that's perfectly normal. Usually there are 2 points against exceptions:
They cost some time and resources to construct, as you mention in comment. That's reasonable concern in some code which executes thousands of operations per second, and those operations throw thousands of exceptions. In your case however, request takes 30-60 seconds, and as such cost of exception is absolutely zero compared to that.
They change control flow, sometimes moving it very far from actual exception source (like goto statement). To handle this (if you are in the "error code" camp, but have to work with exceptions anyway), you should put try-catch block as close as possible to the function which produces it, and handle exception immedatly, because you know exactly where and why it happened. This if what you already do in your example.
So, surrounding soap service call with try-catch block and handling timeout exception is the best way to go here, and there is absolutely no need to try to avoid this exception being thrown. You might want to not throw exceptions in "normal" conditions yourself, in your own code, but if that happens in third party code - you have to handle and not avoid them.

Exception handling in Controller (ASP.NET MVC)

When an exception is thrown by your own code that's called from an action in a controller how should that be handled? I see a lot of examples of best practices where there are no try-catch statements at all. For example, accessing data from a repository:
public ViewResult Index()
{
IList<CustomModel> customModels = _customModelRepository.GetAll();
return View(customModels);
}
Clearly this code could throw an exception if the call is to a database that it can't access and we are using an ORM like Entity Framework for example.
However all that I can see will happen is that the exception will bubble up and show a nasty error message to the user.
I'm aware of the HandleError attribute but I understand it's mostly used to redirect you to an error page if an exception that's unhandled occurs.
Of course, this code could be wrapped in a try-catch but doesn't separate nicely, especially if you have more logic:
public ViewResult Index()
{
if (ValidationCheck())
{
IList<CustomModel> customModels = new List<CustomModel>();
try
{
customModels = _customModelRepository.GetAll();
}
catch (SqlException ex)
{
// Handle exception
}
if (CustomModelsAreValid(customModels))
// Do something
else
// Do something else
}
return View();
}
Previously I have extracted out all code that could throw exceptions like database calls into a DataProvider class which handles errors and returns messages back for showing messages to the user.
I was wondering what the best way of handling this is? I don't always want to return to an error page because some exceptions shouldn't do that. Instead, an error message to the user should be displayed with a normal view. Was my previous method correct or is there a better solution?
I do three things to display more user-friendly messages:
Take advantage of the global exception handler. In the case of MVC: Application_Error in Global.asax. Learn how to use it here: http://msdn.microsoft.com/en-us/library/24395wz3(v=vs.100).aspx
I subclass Exception into a UserFriendlyException. I do my very best in all of my underlying service classes to throw this UserFriendlyException instead of a plain old Exception. I always try to put user-meaningful messages in these custom exceptions. The main purpose of which is to be able to do a type check on the exception in the Application_Error method. For the UserFriendlyExceptions, I just use the user-friendly message that I've set deep down in my services, like "Hey! 91 degrees is not a valid latitude value!". If it's a regular exception, then it's some case I haven't handled, so I display a more generic error message, like "Oops, something went wrong! We'll do our best to get that fixed!".
I also create an ErrorController that is responsible for rendering user-friendly views or JSON. This is the controller whose methods will be called from the Application_Error method.
EDIT:
I thought I'd give a mention to ASP.NET Web API since it's closely related. Because the consumer of Web API endpoints won't necessarily be a browser, I like to deal with errors a little differently. I still use the "FriendlyException" (#2 above), but instead of redirecting to an ErrorController, I just let all my endpoints return some kind of base type that contains an Error property. So, if an exception bubbles all the way up to the Web API controllers, I make sure to stick that error in the Error property of API response. This error message will either be the friendly message that has bubbled up from the classes the API controller relies on, or it will be a generic message if the exception type is not a FriendlyException. That way, the consuming client can simply check whether or not the Error property of the API response is empty. Display a message if the error is present, proceed as usual if not. The nice thing is that, because of the friendly message concept, the message may be much more meaningful to the user than a generic "Error!" message. I use this strategy when writing mobile apps with Xamarin, where I can share my C# types between my web services and my iOS/Android app.
With Asp.Net MVC you can also override the OnException method for you controller.
protected override void OnException(ExceptionContext filterContext)
{
if (filterContext.ExceptionHandled)
{
return;
}
filterContext.Result = new ViewResult
{
ViewName = ...
};
filterContext.ExceptionHandled = true;
}
This allow you to redirect to a custom error page with a message that refer to the exception if you want to.
I used an OnException override because I have several projects referenes to one that have a Controller that handle errors:
Security/HandleErrorsController.cs
protected override void OnException(ExceptionContext filterContext)
{
MyLogger.Error(filterContext.Exception); //method for log in EventViewer
if (filterContext.ExceptionHandled)
return;
filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
filterContext.Result = new JsonResult
{
Data = new
{
Success = false,
Error = "Please report to admin.",
ErrorText = filterContext.Exception.Message,
Stack = filterContext.Exception.StackTrace
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
filterContext.ExceptionHandled = true;
}
All questions like this are not very constructive, because the answer is always "it depends", because there are so many ways of dealing with error handling.
Many people like to use the HandleError method, because any exception is basically non-recoverable. I mean, what are you going to do if you can't return the objects? You're going to show them an error anyways, right?
The question becomes, how you want to show them the error. If showing them an error page is acceptable, than HandleError works fine, and provides an easy place to log the error. If you're using Ajax or want something fancier, then you need to develop a way to do that.
You talk about a DataProvider class. That's basically what your Repository is. Why not build that into your repository?

Exceptions in validation

I currently have some code that delibratly throws an exception if the user sends me data that fails validation (see below). I like it because im sure any errors in the application are caught and handled. A am however worried the code being slow as throwing exceptions takes a lot of memory. Im also worried it might be "bad code". Whats your advice? Thanks
public class BTAmendAppointmentRequest
{
public DataLayer.WebserviceMessage AddBTAmendAppointmentRequest(DataLayer.BTAmendAppointmentRequest req)
{
DataLayer.WebserviceMessage rsp = new DataLayer.WebserviceMessage();
try
{
if (!String.IsNullOrEmpty(req.AppointmentReference))
req.AppointmentReference = req.AppointmentReference.Trim();
if (req.OrderRequestID < 1 || string.IsNullOrEmpty(req.AppointmentReference))
{
throw new Exception("Amend appointment failed, you must supply a valid appointment reference and order reference");
}
...Do other stuff
}
catch (Exception ex)
{
rsp = new Service.WebserviceErrorMessage(ex);
}
return rsp;
}
}
If you are expecting these errors, you should return error messages to the user, not throw exceptions.
Reserve exceptions to exceptional situations.
Apart from being expensive, the meaning of an exception, the semantics are that of something exceptional having happened. Validation failing is not exceptional, it is expected.
Having said that, seeing as you are on a web service, an exception is a reasonable thing to do, assuming you also validate before the service call. It is reasonable since a web service can be called by anything - validation may not have happened, and such errors should be exceptional. Additionally, at least with .NET web services, web exceptions are probably the best way to communicate such things back to the client.
Exceptions should be considered as last resort error trap. They should be "exceptional". Data input errors are not exceptions - they are very common, expected events. You shoudl handle validation issues with validation controls or processes, that handle them - display an error message and do not let the processing continue.
Your other problem is that you cannot easily do full form validation if the first error you encounter throws an exception. If I was filling out a form where each error was separately highlighted, I would give up very quickly. You need to be able to validate and display ALL errors on a page, and not permit progress without validation succeeding.
I tend to agree with Oded in that exceptions should only be used for stuff you aren't expecting. The other way to look at it is with using an errors collection, you are able to validate a larger batch instead of throwing an exception on the first problem. This can be more usable for the person consuming your service.
In the case of web services, I would package the entire response in a custom response object, which features a return code. This allows you to have a return code of error, and then encapsulate an errors collection in the response object.

Categories

Resources