best Approach for Catching exception from my model class - asp.net

I got lost on what/where/when i should catch exceptions inside my asp.net mvc web application. and how to display error messages for end users. For example i got the following Action method:-
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ServerToEdit serverToEdit)
{
try
{
if (ModelState.IsValid)
{
if (!(repository.IsIPUnique(serverToEdit.TechnologyIP.IPAddress, 0)))
{
ModelState.AddModelError("TechnologyIP.IPAddress", "Error occured. The Same IP might already assinged.");
return View(serverToEdit);
}
if (!(repository.IsServerNameUnique(serverToEdit.Server.Name, 0)))
{
ModelState.AddModelError("Server.Name", "Error occured. The Same Server Name might already assinged.");
return View(serverToEdit);
}
repository.InsertOrUpdateServer(serverToEdit.Server,serverToEdit.TechnologyIP,User.Identity.Name);
repository.Save();
return RedirectToAction("Index");
}
else
{
return View(serverToEdit);
}
}
catch (DbUpdateException)
{
ModelState.AddModelError(string.Empty, "Error occured. The Same IP/Name might already assinged.");
}
catch (DbEntityValidationException)
{
ModelState.AddModelError(string.Empty, "Error occured. User might not be defiend inside Active Directory.");
}
return View(serverToEdit);
}
I have the following questions regarding my code:-
i have two services methods (IsIPUnique & IsServeNameUnique); but is the Controller action method that best place to call these service methods from my repository model class?
currently if the service method fail, i am manually writing the model state error and return the view to the user. so is this the right way to write model state errors for the service methods?
if the DBUpdateException was raised, i am assuming that either the IP or serve-name already exists in the database (This might happen if the service methods fail to check in a high traffic application). but there are many other reasons for the DBUpdateExceptio to be raised. so my question is about what is the best approach to handle the DBUpdateException . and show exactly the reason it was raised for?

The controller is usually the right place to do your model state validation, but, as I discovered, if you're doing a lot of validation then it can easily bloat up your controller.
How I deal with validation heavy controller methods is to export the validation to a service, say a static method called ValidateServer(serverToEdit).
Then inside this method, run all your various checks, and build up a Dictionary called errors, and add an error to this dictionary if the check fails.
Then you can pass this dictionary back to your controller, and add the errors to ModelState using a foreach. This then leaves you with just your exception handling.
For serving the user info on your DBUpdateException, you should be able to get information on why it occurred via the exceptions .InnerException property, which you could pass to the user as your error message. So you would write:
catch (DbEntityValidationException ex)
{
ModelState.AddModelError(string.Empty, "Error occurred:" + ex.InnerException);
}
Or something along those lines!

Don't mix validation with exception handling.
It makes more sense to handle the exception in one centralized place and log and display errors to the end users. That way, you make your code much more readable and maintainable. CodeProject has a great article on this subject.

I think you can add another tier that wraps the calls and get back the result with some state and the error if any, and use modelstate in case of failure with the returned message, in this way your controller would be more readable.

Related

ASP.NET return Http Response from function called outside controller

I just started working with asp.net mvc and am working on a legacy codebase with controllers that all have the same validation code at the front of every controller. (ie. multiple lines of the exact same code returning if the user id/key are not correct)
Is there any way to separate this out into an external function that can return an HTTP response immediately if validation fails?
Right now I can do something like this:
if (!validate()) {
return forbid("Your un or Password is incorrect");
}
or for a more specific message:
var errorMsg = validate();
if (errorMsg) {
return forbid(errorMsg);
}
but if I'm going to put this at the front of most of my controllers, I'd rather have a one-liner that I takes up as little room as possible. Is there an option for bypassing the rest of the controller function and returning an HTTP response from inside my validate() function? Or is there possibly a more appropriate way to do this?

Asp.Net MVC5 - Html.Action - Attribute Routing - Weird Behaviour causing Exceptions

Here is some weird behaviour that is consistent across different actions and views in my entire website:
Whenever I POST to some action method and Model.IsValid is false, I return the view. Whenever Html.Action() is called in the view that is returned I get this exception:
(System.Web.HttpException): No matching action was found on controller 'xyz'.
This can happen when a controller uses RouteAttribute for routing,
but no action on that controller matches the request.
I'm using Attribute Routing.
public class RouteConfig
{
// REGISTER ROUTES
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapMvcAttributeRoutes();
}
}
So even though the Html.Action call worked the first time in the GET action method return View(), Html.Action always throws this exception after POST return View(). This is a general pattern across my website.
Wtf? Any ideas what's gone wrong here? The only thing I can think of is that I added more routes over time and now it's confused. How would I fix or test that if that's the case?
It just occurred to me that I have many routes/action methods where the get and post versions of routes for action methods are identical except for the GET or POST attribute on the action method. I previously made sure every route was completely unique because I was getting some ambiguity but changed it back to the same routes for get and post action methods, the only difference being the get or post attribute... I'm becoming convinced it's a routing issue but I don't know what's wrong specifically. I have route attributes on hundreds of action methods.
I have never seen anything as subtle as this before and have no idea even how to start solving something like this. I have no idea if it's simple or complicated, if it's my code or the framework. Any help would be greatly appreciated.
UPDATE:
Some sample code, not sure it will help, because the same things happens as a pattern across many utterly different action methods and views, regardless of GET, POST, authorized, unauthorized, in a role or not, antiforgerytoken...
Standard Html.Action called from a view. Works fine most of the time. (Different overloads make no difference.)
#Html.Action("CategoryDropDowns", "Category")
Here is what gets called (exactly what gets returned makes no difference, could be a ViewResult, could be an int).
// GET: /category/category-drop-downs
[HttpGet]
[Route("category/category-drop-downs")]
public ViewResult CategoryDropDowns()
{
}
If validation fails the view is returned:
public ActionResult CreateListing(ListDetails listDetails)
{
if (ModelState.IsValid)
{
}
else
{
return View("List", model);
}
}
And upon debugging through the view that gets returned, the call to Html.Action that worked fine the first time throws the exception. Same thing happens as a pattern across my website. Return View(), hit the Html.Action, bang, exception. Every time.
Remove the [HttpGet] attribute from child actions!
The problem was that Html.Action() always seemed to hit an exception not after a GET, return View(), but a POST, return View().
Ages ago I went through my whole site and marked every action method that wasn't a post with the [HttpGet] attribute. I didn't realise this would cause a problem. Always test!
Removing the [HttpGet] attribute from action methods called from Html.Action() has solved the problem.

how to get which webservice is calling a method

I have a webservice 'mywebservice' and a web method 'mywebmethod' defined in it.
This web method calls a function 'callme()' which is defined in another class.
I want to get the service name which is calling this function and also the methodname. I want this in 'callme()' function.
--'mywebservice.asmx.cs'
[WebMethod]
public void mywebmethod
{
callme();
}
-- 'class1.cs'
public void callme()
{
// --- I want service name(mywebservice) & methodname(mywebmethod) here.
}
One possible way could be to use StackTrace class (see example section to get started) to walk back to call stack to get type name & method name - this will give you the names for class/method implementing the service.
Mind you that stack trace construction is an expensive operation - as such, I would recommend to pass necessary information as parameters to the method. Further, if you could state why you need this information (service & method name), you may get an better answer to solve your actual problem.

ASP.NET MVC 2: Avoiding loop when accessing 404 action directly

Like many people using ASP.NET MVC, I've implemented my own custom 404 error handling scheme using an approach similar to the one described here: How can I properly handle 404 in ASP.NET MVC?
(I actually discovered that post after implementing my own solution, but what I came up with is virtually identical.)
However, I ran into one issue I'm not sure how to properly handle. Here's what my 404 action in my ErrorController class looks like:
public ActionResult NotFound(string url)
{
url = (url ?? "");
if (Request.Url.OriginalString.Contains(url) &&
Request.Url.OriginalString != url)
{
url = Request.Url.OriginalString;
}
url = new Uri(url).AbsolutePath;
// Check URL to prevent 'retry loop'
if (url != "/Error/NotFound")
{
Response.StatusCode = (int)HttpStatusCode.NotFound;
// Log 404 error just in case something important really is
// missing from the web site...
Elmah.ErrorSignal.FromCurrentContext().Raise(
new HttpException(Response.StatusCode,
String.Format("Resource not found: {0}", url)));
}
return View();
}
The part that's different from the answer in the other StackOverflow question I referenced above is how the 'retry loop' is prevented. In other other answer, the code that prevents the retry loop simply sets properties on a ViewModel, which doesn't seem to actually prevent the loop. Since the action is sending back a response code of 404, then accessing the action directly (by typing "/Error/NotFound" in the browser) causes an infinite loop.
So here's my question: Did I miss another, more obvious way to handle the retry loop issue, or is my approach a decent way to do this?
you can handel erros by enabling the customErrors mode in the web.config file and set it to redirect errors to your controller when any errors occurs.
see an example here

Good error handling practice

What is a good error handling practice for an asp.net site? Examples? Thanks!
As with any .net project I find the best way is to only catch specific error types if they are may to happen on the given page.
For example you could catch Format Exceptions for a users given input (just incase JavaScript validation fails and you have not use tryparse) but always leave the catching of the top level Exception to the global error handler.
try
{
//Code that could error here
}
catch (FormatException ex)
{
//Code to tell user of their error
//all other errors will be handled
//by the global error handler
}
You can use the open source elmah (Error Logging Modules and Handlers) for ASP.Net to do this top level/global error catching for you if you want.
Using elmah it can create a log of errors that is viewable though a simple to configure web interface. You can also filter different types of errors and have custom error pages of your own for different error types.
One practice that I find to be especially useful is to create a generic error page, and then set your defaultRedirect on the customErrors node of the web.config to that error page.
Then setup your global.asax for logging all unhandled exceptions and then put them (the unhandled exceptions) in a static property on some class (I have a class called ErrorUtil with a static LastError property). Your error page can then look at this property to determine what to display to the user.
More details here: http://www.codeproject.com/KB/aspnet/JcGlobalErrorHandling.aspx
Well, that's pretty wide open, which is completely cool. I'll refer you to a word .doc you can download from Dot Net Spider, which is actually the basis for my small company's code standard. The standard includes some very useful error handling tips.
One such example for exceptions (I don't recall if this is original to the document or if we added it to the doc):
Never do a “catch exception and do nothing.” If you hide an exception, you will never know if the exception happened. You should always try to avoid exceptions by checking all the error conditions programmatically.
Example of what not to do:
try
{
...
}
catch{}
Very naughty unless you have a good reason for it.
You should make sure that you can catch most of the errors that are generated by your application and display a friendly message to the users. But of course you cannot catch all the errors for that you can use web.config and defaultRedirect by another user. Another very handy tool to log the errors is ELMAH. ELMAH will log all the errors generated by your application and show it to you in a very readable way. Plugging ELMAH in your application is as simple as adding few lines of code in web.config file and attaching the assembly. You should definitely give ELMAH a try it will literally save you hours and hours of pain.
http://code.google.com/p/elmah/
Code defensively within each page for exceptions that you expect could happen and deal with them appropriately, so not to disrupt the user every time an exception occurs.
Log all exceptions, with a reference.
Provide a generic error page, for any unhandled exceptions, which provides a reference to use for support (support can identify details from logs). Don't display the actual exception, as most users will not understand it but is a potential security risk as it exposes information about your system (potentially passwords etc).
Don't catch all exceptions and do nothing with them (as in the above answer). There is almost never a good reason to do this, occasionally you may want to catch a specific exception and not do any deliberately but this should be used wisely.
It is not always a good idea to redirect the user to a standard error page. If a user is working on a form, they may not want to be redirected away from the form they are working on. I put all code that could cause an exception inside a try/catch block, and inside the catch block I spit out an alert message alerting the user that an error has occurred as well as log the exception in a database including form input, query string, etc. I am developing an internal site, however, so most users just call me if they are having a problem. For a public site, you may wish to use something like elmah.
public string BookLesson(Customer_Info oCustomerInfo, CustLessonBook_Info oCustLessonBookInfo)
{
string authenticationID = string.Empty;
int customerID = 0;
string message = string.Empty;
DA_Customer oDACustomer = new DA_Customer();
using (TransactionScope scope = new TransactionScope())
{
if (oDACustomer.ValidateCustomerLoginName(oCustomerInfo.CustId, oCustomerInfo.CustLoginName) == "Y")
{
// if a new student
if (oCustomerInfo.CustId == 0)
{
oCustomerInfo.CustPassword = General.GeneratePassword(6, 8);
oCustomerInfo.CustPassword = new DA_InternalUser().GetPassword(oCustomerInfo.CustPassword, false);
authenticationID = oDACustomer.Register(oCustomerInfo, ref customerID);
oCustLessonBookInfo.CustId = customerID;
}
else // if existing student
{
oCustomerInfo.UpdatedByCustomer = "Y";
authenticationID = oDACustomer.CustomerUpdateProfile(oCustomerInfo);
}
message = authenticationID;
// insert lesson booking details
new DA_Lesson().BookLesson(oCustLessonBookInfo);
}
else
{
message = "login exists";
}
scope.Complete();
return message;
}
}

Resources