Exception Handling in ASP.NET Web Api 2 - c#

Problem:
I need to handle web api 2 exceptions and return a rich object with the correct status code (401 for Unauthorized, 404 for ContentNotFound, etc) and some extra information as the content. Moreover, I need the content to look like a serialized Exception object (have the message, exceptionMessage, stackTrace, ... properties).
Suggested Solutions:
Create custom exception classes and writing a custom exception filter to apply to any controller's action. this custom exception filters handles the exception thrown according to it's type (one of the custom exceptions that I've already defined) and responds accordingly via something like this (filter's code):
context.Response = context.Request.CreateErrorResponse(HttpStatusCode.Unauthorized,
new Exception("my exception")));
wrapping the already written web api 2 *ActionResult classes ( System.Web.Http.Results.UnauthorizedResult Unauthorized(), System.Web.Http.Results.OkResult Ok(), etc ) and adding some custom data to them and use them so that their result get passed to client every time they're called (the problem is in this case my controller's action's return type should be IHttpActionResult which is not as easily testable and readable as a strongly typed action).
What solution should I choose? Or is there any other way to do what I'm trying to achieve here?

Or you could use the built-in, out-of-the-box solution: exception filters.
Furthermore, you may be interested on exception handling starting from Web API 2.x.

From what I understand you don't want to handle exceptions thrown by the code, rather create them in your action methods. For the case where exceptions are thrown by other areas in the code (other things you call inside your actions or by other filters, you can either use exception filters or global error handling).
Hence I would go with your second approach (though you don't need to customize the action results much). Your code is actually a lot more easy to unit test with IHttpActionResult, because you can inspect the result type directly. In fact one of the reasons IHttpActionResults where added is to simplify unit testing.
The flow of your code is simpler as you don't need to throw to generate errors, and you can always inspect the content of an ok(returnValue) as you can see below.
[TestMethod]
public void GetProduct_ShouldReturnCorrectProduct()
{
var testProducts = GetTestProducts();
var controller = new SimpleProductController(testProducts);
var result = controller.GetProduct(4) as OkNegotiatedContentResult<Product>;
Assert.IsNotNull(result);
Assert.AreEqual(testProducts[3].Name, result.Content.Name);
}
http://www.asp.net/web-api/overview/testing-and-debugging/unit-testing-with-aspnet-web-api

Related

How to use C# FluentValidation ValidationContext.RootContextData

I'm new to FluentValidation and am trying to create a validator that accepts some context/parameters at validate time. I've created a custom validator and in the constructor I have something like:
RuleFor(request => request.someField).Custom((request, context) => {
var foo = context.ParentContext.RootContextData["someDependency"];
});
And in the calling code I do:
var validator = new FooValidator();
var context = new ValidationContext<SomeRequest>(request);
context.RootContextData["someDependency"] = someDependency;
validator.Validate(context);
which causes:
System.Collections.Generic.KeyNotFoundException: The given key 'someDependency' was not present in the dictionary.
Any ideas? The reason I want to pass in some context parameters is that they come from the database. If I instead pass that into the validator constructor, then by the time the validate method is called, those context parameters might be out of date. I also don't want to do the fetching from the database in the validator constructor as I will also need to fetch the same data before/after the validate method is called, and database caching is not possible in this scenario, so I'd like to avoid the unnecessary database roundtrips. I've read and am doing what seems to be the same as what is described https://docs.fluentvalidation.net/en/latest/advanced.html#root-context-data
As mentioned in my OP comment, the code looks sound but it's likely failing at the MVC validation pipeline stage and never makes it to your Validate invocation. With the former as it stands you've not added your dependency to the dictionary so it barfs.
There's probably a couple of ways to solve it. My first thought would be to introduce a rule set so this rule only executes server-side as part of your Validate invocation. There's a whole section on rule sets in the doco which covers it pretty well. You may need to combine it with a CustomizeValidator attribute so that the rule set doesn't get executed in the MVC validation pipeline (I've never had to when using a server-side rule set but I've mentioned it for completeness).
The nice thing with this is that you probably won't need to change much of your existing code; you've mentioned you load a number of dependencies into the validation context so it could be a good fit.
Another methodology that looks good, but one that I haven't tried myself, would be to populate the validation context in the BeforeMvcValidation validation interceptor. The value of this option is going to depend on how you gather those dependencies and whether they are used for anything other than validation. It'd probably require more effort than a rule set based on your implementation description as well.

Pass validation errors from service to controller

In my web app i have service layer responsible for all logic (like registering, etc.). I wanted to implement server-side validation for my forms. The thing is i can't just throw an exception every time i catch invalid data, because if user typed incorrect email AND password, my service method would just throw exception as soon as it checks email, and password error would be noticed only after user corrected email and resubmitted form. I want my entire form validated at once. The important thing is: i need only to pass error types, display messages must be added to ModelState in controller. I have some ideas and i would like you to help me decide which one is better from performance and good-practice point of view (maybe none - maybe there is another solution superior to all posted by me).
Ideas:
Collect errors in a dictionary and then throw single exception
containing all model errors in form of key-value (ex. "Password", "Must
be >5 signs"). In controller i catch error, and read all entries using switch() to detect error type and add proper message to ModelState.
Pros: uses built-in Exception.Data dictionary
Cons: need to decipher error type from the string
Similar to previous, but i create custom exception class, which has additional field-enum dictionary (ex. "Password", ValidationEnum.LessThanFiveSignsError).
Pros: Enums are more elegant solution for switch() operations
Cons: need to implement custom exception to do something that built-in exception class could do actually
Custom exception with dictionary, but with exceptions instead of enums - i create classes like StringTooShortException and UsernameAlreadyExistsException and add them to dictionary (ex. "Password", new StringTooShortException()). Switch would probably need to check type object...
Pros: i use exceptions? the more i think about it the more i believe this is not a good idea...
Cons: pass objects Exception subclass (with all Exception class attributes and stuff) and only use information of what type is that object?
Make my every service method return custom class containing {object regularReturnValueDependingOnMethod, MyCustomErrorContainer canBeListOfEnumsOrSomething}. Basic difference between this and previous ideas is that i don't throw an exception just to carry my error container up to controller, i use proper workflow.
Pros: doesn't throw exception, just returns validation errors to controller, uses proper workflow to pass values
Cons: isn't it too much to wrap return value of every method just to pass validation errors back to controller? maybe validation error is exactly the kind of situation, where i should use exception to carry a message to controller (whatever that message could be: a text string or, in this case, an entire object)
Don't wrap return value, just create validation error container in controller and pass it to service as "out" parameter
Pros: simple
Cons: need to create error container instance before calling any service method (ok, just ones which validate input). is it elegant?
What do you think? Which one is best? I'm not interested in just getting it done. I want to get it done the way it should be done. I want to learn good programming behavior :)
Thanks for any help :)
//edit:
My latest thought: I could create another service method just for validation purpose (ex. method: RegisterUser() for registration, and ValidateRegisterUser() for model validation, i would just have to make sure to call validation method before i call regular method. What do you think?

How to get a dump of all local variables?

How can I get a dump of all local & session variables when an exception occurs? I was thinking of writing some sort of reflection based function that would interrogate the calling function & create a dump of variables & values.
Is there an existing library that I can use?
UPDATE
After speaking to a colleague, I was pointed to AOP or Aspect Oriented Programming. Here is what I understand ... Using AOP, one would simple decorate the methods & classes with certain attributes. AOP framework then injects code in or around these classes & methods. There are two separate kinds of framework, one that injects code & then compiles the assembly & the second simply uses reflection & traps the call which you have decorated and wraps whatever code around the method at runtime.
I hope all that makes sense. I will be doing more research on this & post my approach.
Thanks guys ...
I'm not sure if this is what you're looking for. But if you're in a catch-block you can get all fields and properties of this class in the following way:
try
{
double d = 1 / 0;
}
catch (Exception ex)
{
var trace = new System.Diagnostics.StackTrace();
var frame = trace.GetFrame(1);
var methodName = frame.GetMethod().Name;
var properties = this.GetType().GetProperties();
var fields = this.GetType().GetFields(); // public fields
// for example:
foreach (var prop in properties)
{
var value = prop.GetValue(this, null);
}
foreach (var field in fields)
{
var value = field.GetValue(this);
}
foreach (string key in Session)
{
var value = Session[key];
}
}
I've showed how to get the method name where the exception occured only for the sake of completeness.
Type.GetProperties Method
Type.GetFields Method
PropertyInfo.GetValue Method
FieldInfo.GetValue Method
StackTrace Class
With BindingFlags you can specify constraints, for example that you only want properties of this class and not from inherited:
Using GetProperties() with BindingFlags.DeclaredOnly in .NET Reflection
Of course the above should give you only a starting-point how to do it manually and you should encapsulate all into classes. I've never used it myself so it's untested.
You should not use Exception handling in Try Catch form. Rather, it should be
Page Level Error
Application Level error
Suppose You have a Presentation Layer and a Business Logic Layer/DataAccess Layer.
Upon facing the error in say Business Logic, it will move directly to Glogal.asax.cs file under Application_Error Event without going back to the calling function. Here you can log the error message like below....
HttpContext.Current.Server.GetLastError().InnerException.StackTrace
HttpContext.Current.Server.GetLastError().InnerException.Message
HttpContext.Current.Server.GetLastError().InnerException.Source
HttpContext.Current.Server.GetLastError().InnerException.TargetSite.DeclaringType.FullName
HttpContext.Current.Server.GetLastError().InnerException.TargetSite.DeclaringType.Name
HttpContext.Current.Server.GetLastError().InnerException.TargetSite.DeclaringType.Namespace
In case of page level error, Priority is the Page OnError Override and finally the Application Level error event. here also you can log errors.
I will prefer Application_error handler because If you have 20 modules and a situation come when you need to create baseclass for each module. It is not good to make code redundancy.
Now in the Web Config you can write code to redirect the user on some default page like below.
<customErrors defaultRedirect="ErrorPage.htm" mode="On">
<error statusCode="404" redirect="ErrorPageNotFound.htm"/>
</customErrors>
This is a question asked ad nauseum on Stack Overflow, although phrased differently. In one thread, the answer was to use PostSharp. As others have suggested dumping the stack trace, you can do that. The easiest would be to manually dump the local variables. This can either be to Trace or you can create your own custom exception handler.

State Pattern in ASP.NET MVC 3.0

I have a registration page in my application. It has 3 states and 1 error state(If any error comes):
Fill Basic Information
Select Package
Say Thanks
Error
Now I want to use state pattern here. First I created a console application which is OK. Now I want to implement this logic in my MVC application but I am confused about the structure. I mean how many views, models and controller I need and where to place my logic.
1 controller: RegistrationController
6 action methods:
GET+POST for Index (fill in basic info)
GET+POST for Package
GET for Thank you
GET for Error
This is rough code to make your mind going:
public class RegistrationController : Controller
{
public ActionResult Index()
{
RegistrationState model = RegistrationState.Init();
// just display the "Fill Basic Info" form
return View(model);
}
[HttpPost]
public ActionResult Index(RegistrationState data)
{
// process data and redirect to next step
this.TempData["RegState"] = data;
if (!this.ModelState.IsValid || data.State == State.Error)
{
// error should handle provided state and empty one as well
return RedirectToAction("Error");
}
return RedirectToAction("Package");
}
public ActionResult Package()
{
RegistrationState data = this.TempData["RegState"] as RegistrationState;
if (data == null)
{
return RedirectToAction("Error");
}
// get packages and display them
IList<Package> model = this.repository.GetPackages();
return View(new Tuple.Create(data, model));
}
[HttpPost]
public ActionResult Package(RegistrationState data)
{
// process data blah blah blah
}
// and so on and so forth
....
}
As you can see you still have to write some MVC-related code to act upon state changes. In my example everything's done in action methods. But action filters could be used as well. If you can't come up with a general action filter that can serve many different state objects then it's best to just write the code in action methods.
Another approach
If you know Asp.net MVC good enough you could take this a step further and write a state machine ControllerFactory that would work along with routing in a sense as:
{StateObjectType}/{State}
ControllerFactory would therefore be able to parse view data to a known state object type and pass execution to particular action. According to state. This would make it a specially state machine suited Asp.net MVC application.
The more important question is of course whether you can create the whole application with this pattern or are there just certain parts of it that should work like this. You could of course combine both approaches and provide appropriate routing for each.
Important notices
You should be very careful how you define your error state, because entering invalid field data shouldn't result in error state but rather in data validation errors that actually display within the view beside the field with invalid data (ie. invalid date provided as 13/13/1313). Your error state should only be used for actual object state error that's not related to user input. What would that be is beyond my imagination.
As mentioned in my comment you should check out some Asp.net MVC intro videos and you'll see how validation works in Asp.net MVC. Also rather simple stuff.
State pattern of this kind is not something a regular Asp.net MVC developer would use, because it would most likely complicate code more than taking the normal approach. Analyse before you decide. Asp.net MVC is very clean code wise so adding additional abstraction over it may become confusing. And your domain model (state classes) would most likely have a much more complex code as simple POCOs with data annotations.
In your case data validation would also be more complicated (when used with data annotations) because you object should be validated according to its state which may be different between states. POCO objects are always validated the same. This may mean that we may use more classes but they are smaller, simpler and easier to maintain.
I think you are confusing states. Examples of state are:
Awaiting for a user to register
User registered successfully
User didn't register successfully
Now each of these states would have a page:
localhost:8034/Register
localhost:8034/Register/Success
localhost:8034/Register/Failure
If user can't register because they left some fields empty, they will be in the first state and you will have to display some validation messages.
Because of this, as the minimum I'll have a controller called Register and the following action methods:
Index() GET/POST
Success() GET
Failure() GET

Handling post requests in ASP.NET MVC

Recently I started working with MVC, before that I used "classic" ASP.NET.
After using Ruby on Rails (RoR), I wonder how to implement POST request handling in MVC similar to how RoR operates. In RoR you use the Post method, so you need only one function for a view.
In ASP.NET MVC I need to use 2 separate functions for GET and for POST, so I need to initialize the same data twice, and I don't like to repeat something in my code.
How can I check if the request is POST in one method?
Update:
Solution is found: I have to use Request.HttpMethod.
Thank you!
I came across this question wanting to know the same thing. Below is a detailed description of my situation and the solution that I used (which utilizes the other answers provided here). I originally tried to use the two separate method approach, but I ran into a problem when the method signatures of these methods became identical.
I have a page that displays report data. At the top of the page there is a form with some fields, which allow the user to specify report parameters such as start date, end date, etc.
I originally approached this by creating two separate methods to handle the Get and the Post methods. The post method would redirect the browser to the get method so that any parameters that were specified would be added to the query string and so that the browser would not prompt the user with a dialog saying that it is going to resend the data that they entered if they refresh. Note: I realized later that I could accomplish this by setting the method attribute of my form element to "Get", but I think ideally a controller shouldn't have knowledge of how a view is implemented, so in my opinion that is irrelevant.
As I developed these two methods I eventually found myself in a situation where the method signatures became identical. Furthermore, my code for these two methods became nearly identical, so I decided to merge them into a single method and to just check the request verb so that I could do something slightly different when the request is not a "Get". A distilled example of my two methods is shown below:
// this will not compile because the method signatures are the same
public ActionResult MyReport(DateRangeReportItem report)
{
// if there are no validation errors and the required report parameters are completed
if (ModelState.IsValid && report.ParametersAreComplete)
{
// retrieve report data and populate it on the report model
report.Result = GetReportData(report.CreateReportParameters());
}
return View(report);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult MyReport(DateRangeReportItem report)
{
if (ModelState.IsValid && report.ParametersAreComplete)
{
// redirect to the same action so that if the user refreshes the browser it will submit a get request instead of a post request
// this avoids the browser prompting the user with a dialog saying that their data will be resubmitted
return RedirectToAction("MyReport", new { StartDate = report.StartDate, EndDate = report.EndDate });
}
else
{
// there were validation errors, or the report parameters are not yet complete
return View(report);
}
}
Why am I accepting a model object as the parameter to my get method? The reason is that I wanted to take advantage of the validation logic already built into the model object. If someone navigates to my page directly with all parameters already specified in the query string, then I want to go ahead and retrieve the report data and display it on the page. However, if the parameters specified in the query string are invalid then I also want validation errors to appear on the page. By putting my model object as the parameter, the MVC framework will automatically attempt to populate it and will capture any validation errors without any additional work on my part.
I used the other answers posted for this question to create a RequestHttpVerb property on a base controller class in my project:
public HttpVerbs RequestHttpVerb
{
get { return (HttpVerbs)Enum.Parse(typeof(HttpVerbs), this.Request.HttpMethod, true); }
}
So finally my consolidated method looks like the following:
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
public ActionResult MyReport(DateRangeReportItem report)
{
// check if there are any validation errors in the model
// and whether all required report parameters have been completed
if (ModelState.IsValid && report.ParametersAreComplete)
{
// this is unnecessary if the form method is set to "Get"
// but within the controller I do not know for sure if that will be the case in the view
if (HttpVerbs.Get != this.RequestHttpVerb)
{
// redirect to the same action so that if the user refreshes the browser it will submit a get request instead of a post request
// this avoids the browser prompting the user with a dialog saying that their data will be resubmitted
return RedirectToAction("MyReport", new { StartDate = report.StartDate, EndDate = report.EndDate });
}
// there were no validation errors and all required report parameters are complete
// retrieve report data and populate that data on the model
report.Result = GetReportData(report.CreateReportParameters());
}
// display the view with the report object
// Any model state errors that occurred while populating the model will result in validation errors being displayed
return View(report);
}
That's my current solution to the problem. I would prefer not to have to check the Request.HttpMethod property in order to determine whether I needed to perform the redirect, but I didn't see another solution to my problem. I would have been fine with keeping two separate methods to handle Get and Post requests, but the identical method signature prevented this. I would have preferred to rename my Post action handler method to avoid the method signature conflict and to use some mechanism to indicate to the MVC framework that my renamed method should still handle the "MyReport" action, but I am not aware of any such mechanism in the MVC framework.
You only need separate methods for GET and POST if their method signatures differ, there's no reason why one action method can't handle GET and POST methods.
If you need to know whether it was a GET or POST, you could check using Request.HttpMethod in your action, but I would advise using a separate method decorated with the [AcceptVerbs(HttpVerbs.Post)] attribute as suggested by the other posters.
You don't check in ASP.NET MVC. You decorate your method with the [AcceptVerbs(HttpVerbs.Post)] attribute to indicate that the method applies to post only, and accept the model in the method used to handle the post.
I'd strongly suggest doing the walkthrough for NerdDinner to understand more about the ASP.NET MVC framework.
You may take a look at the Request.HttpMethod property.
Correct way to do is using ModelBinding during Post request.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(EmployeeViewModel model)
{
//validate data, save employee, handle validation errors...
}
This way you will not have to init your data again.

Categories