Global handler for model state errors - c#

We are creating MVC3 applications. We are using default editors and model state validation. We need to log application errors, but we prefer to make it by some kind of a global handler. We have a handler for unhandled exceptions, but we also want to log model state errors.
The question is: Where can we attach our logger to log such errors? Can we somehow override ModelState or detect situation when model served to view has model errors?

Global filters will most likely be your best way to go.
More from SO here: asp.net mvc 3 handleerror global filter always shows IIS status 500 page
Or checkout the msdn doc here:
http://msdn.microsoft.com/en-us/library/gg416513(v=vs.98).aspx

Create a attribute to handle error and register it in the controller,
public class ErrorHandlerAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext exceptionContext)
{
LogManager.GetLogger("somelogger").Error(exceptionContext.Exception.Message,exceptionContext.Exception);
base.OnException(exceptionContext);
}
}
register it in the controller like this,
[EwmsErrorHandler(ExceptionType = typeof(base type of exception to handle), View = view to redirect)]
public class MyController : Controller
{
<controller code>
}

Related

Using the ValidateModelAttribute with an MVC View in ASP.NET Core 2.1

Previously in WebAPI projects I used the ValidateModelAttribute to avoid repeating if (!ModelState.IsValid) statements in each of my controllers.
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(context.ModelState);
}
}
}
When I try to use the same attribute on an action in a MVC controller (ASP.NET Core 2.1) I receive a 400 status code and the page simply displays the JSON representation of the error e.g. {"Description":["Description is required"]}.
Is there a similar attribute I can use in my MVC controllers to forward the ModelState errors to my view in the same way as using
if (!ModelState.IsValid)
{
return View(command);
}
Not really. The problem with returning a ViewResult is that you need to return the "model" with it, in order for everything to bind up properly to refill the form fields and display validation error messages. That model is some param on your action, but it will be different from action to action and may exist with other params, making it difficult if not impossible to discern which is the "model" that should be returned. In short, it's easy for you to do something like return View(model); it would be difficult if not impossible to instruct an automated process to do it correctly in every instance.
In APIs, you get to sidestep all this because you're just returning simple JSON and you can use ModelState to get all the info you need to return an object with a list of validation errors. What "model" was posted is entirely inconsequential.
Also, for what it's worth, in ASP.NET Core 2.1, you don't even need your custom attribute for this. All you have to do is decorate your controller with [ApiController]. ASP.NET Core, then, will automatically return an BadRequestObjectResult (400) composed from ModelState if there's any validation errors.

Capture User last request timestamp in ASP NET Web API

I'm looking for a good place in the ASP.NET Web API lifecycle To update a property in my User entity that is purposed to store the date and time the User last made a request. Obviously, I could just add the code to each of my Controller methods but I would prefer doing this in one place outside of my controllers.
Ideally I would have access to the User principal and could use its Identity property to get the user's ID so that I could retrieve and update my User entity using Entity Framework.
I am currently looking at using a DelegatingHandler implementation.
Can anyone suggest the place in the lifecycle where I should carry this out? A code example would be appreciated.
Create an ActionFilter:
public class LogActionFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
// Do your work
}
}
Yes, but wouldn't I have to add the ActionFilter to each and every controller method?
No, you can apply it to the controller or to actions.
Alternatively, you can do the following and you will not have to apply it to every controller (sort of like a global filter):
[LogActionFilter ]
public class LogableApiController : ApiController
{
...
}
Then inherit that wherever you want.
And lastly, another option is to add to global filters by finding the App_Start/FilterConfig.cs and add:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new LogActionFilter());
}
So I have shown you how to apply it to action level, controller level, one or more controllers but not all controllers and then how to apply it to all controllers (global).
I would create an Attribute for your Controller to execute the update on your User Entity with an ActionFilter.
This example explain how to create an attribute for a controller method, it is the same way to do it: Custom Attribute above a controller function
b.e, your controller would be like this:
[SaveUserRequest]
public class HomeController : ApiController

Dealing with Session timeout in ASP.NET MVC

I am working on a MVC application and I have a requirement of dealing with errors and session timeouts by redirecting the user to different error pages based on few parameters in the query string.
The issue I am facing is that i tried to implement this by saving the required parameters from querystring into a session and then redirecting to error pages. But before every HttpGet and Post action in my controllers I am checking if session is active.
So in case of a situation where session values are lost and not able to read them.
How can I implement this thing in any other way?
You need to check whether the session exists, has the fields you expect and is active. If the session does not exist or does not have a fields you expect, then handle the case when the session does not exist yet/expired. If it is not active, then handle the case when the session is no longer active. If everything is ok, then handle the request normally. If the session expired, then handle it as expired.
to check about session, you can use an ActionFilter like this:
public class SessionActiveFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var activeSession = Session["user"];
if (activeSession == null)
//Here, do a redirect
base.OnActionExecuting(filterContext);
}
}
Also, you can use a third option to save the session, like Redis Cache http://blogs.msdn.com/b/webdev/archive/2014/05/12/announcing-asp-net-session-state-provider-for-redis-preview-release.aspx
I know this is a dead story now. But I post this answer for the new comers. Please see the nice tutorial in codeproject about how to check session values in Action Filters.
In a dynamic web application, the session is crucial to hold the information of current logged in user identity/data. So someone without authentication cannot have access to some Page or any ActionResult, to implement this kind of functionality, we need to check session exists (is not null) in every action which required authentication.So, the general method is as follows:
[HttpGet]
public ActionResult Home()
{
if(Session["ID"] == null)
return RedirectToAction("Login","Home");
}
We have to check the above 2 statements each time and in each ActionResult, but it may cause 2 problems.
Repeat Things: As per the good programming stranded, we don't have to repeat the things. Create a module of common code and access it multiple times/repeatedly
Code missing: We have to write code multiple times so it might happen some time we forget to write code in some method or we missed it.
How To Avoid?
The ASP.NET MVC provides a very great mechanism i.e., Action Filters. An action filter is an attribute. You can apply most action filters to either an individual controller action or an entire controller.
If you want to know more about action filter, please click here.
So we will create a custom Action Filter that handles session expiration and if session is null, redirect to Login Action.
Create a new class in your project and copy the following code:
namespace YourNameSpace
{
public class SessionTimeoutAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext ctx = HttpContext.Current;
if (HttpContext.Current.Session["ID"] == null)
{
filterContext.Result = new RedirectResult("~/Home/Login");
return;
}
base.OnActionExecuting(filterContext);
}
}
}
Now our Action Filter is created and we are ready to use it. The following code will show you how we can apply attribute to Action or to complete controller.
Apply to Action
[HttpGet]
[SessionTimeout]
public ActionResult MyProfile()
{
return View();
}
Apply to Controller
[SessionTimeout]
public class HomeController : Controller
{
}
Now all actions of Home Controller will check for session when hit with the help of Action Filter. So we have reduced the code and repetitive things. This is the benefits of Action Filters.

MVC 5 c# reporting errors back to the database

we have an MVC application , what is the best way to record errors generated (by users) back to our support database? users should only see "this error has been reported" error message
all the details should be written to to a database
please help!
I suggest you either make use of External library like Log4Net or create you own library class which will do logging for you.
One more suggestion is make use of ExceptionFilter which is avaiable in MVC file and write code of logging in that filter. I am suggesting becuase it will not cause you to write code again and again it follows DRY principle.
Example :
public class CustomExceptionFilter: FilterAttribute,
IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (!filterContext.ExceptionHandled)
{
//log error here
Logger.LogException(filterContext.Exception);
//this will redirect to error page and show use logging is done
filterContext.Result = new
RedirectResult("customErrorPage.html");
filterContext.ExceptionHandled = true;
}
}
}
than you can do like this
//Over controller
[CustomExceptionFilter]
public class HomeController:Controller
{
//......
}
//Over the Action
[CustomExceptionFilter]
public ActionResult Index()
{
//.......
}
Check this for log4net : log4net Tutorial

controller specific iis logging with ASP.NET MVC in IIS

I want to log visits only for some controllers (or routes) as it was possible with classic ASP.NET pages by checking/unchecking the 'log visits' checkbox in IIS.
Does anyone know if this is possible somehow? A solution without a custom logging component would be fantastic! Please share your knowledge, if you know how ;)
Thanks in advance
Create a BaseController which the controllers that you want to record data for inherit from. Then create an ActionFilter which overrides the OnActionExecuted method and apply it to the base controller. Something like this..
public class ActionExecutedFilter : System.Web.Mvc.ActionFilterAttribute
{
UnitOfWork unitOfWork= new UnitOfWork();
public override void OnActionExecuted(ActionExecutedContext filter)
{
Transaction tran = new Transaction();
tran.Controller = filter.ActionDescriptor.ControllerDescriptor.ControllerName;
tran.ActionName = filter.ActionDescriptor.ActionName;
tran.User = HttpContext.Current.User.Identity.Name;
tran.Date = DateTime.Now;
unitOfWork.TransactionRepository.Insert(tran);
unitOfWork.Save();
}
}
This will save to a database table called Transactions information for every time a action method is called on that controller, recording the user, controller and action method name. Obviously I just typed in the UnitOfWork method of saving to the database, you can just plug in whichever method you like. I usually keep these methods in a filters folder, add a using statement then add it to the controller like so;
[ActionExecutedFilter]
public class BaseController : Controller
{
}
Again, just make all the controller you wish to record data from inherit the BaseController.
You could also use something like Log4Net, but I find just doing it this way gets what I need. Whatever you think yourself.
http://dotnetdarren.wordpress.com/2010/07/29/logging-in-mvc-part-4-log4net/
A solution without a custom logging component would be fantastic!
Apart from basic IIS diagnostic logs, I cannot think of any ASP.Net MVC specific Logging features in IIS.
One simple solution what I want to offer is to write a HttpModule. In the HttpModule you can log the requests. Also if you want to have control on what to log and what not to, then based on Routes you can make that happen in HttpModule. Advantage with HttpModule is it is easy to plug in and also easy to remove.
Make HttpModule work only on certain routes
When it comes to logging itself, you can have your own custom logic to database or to log file. But you can opt for ELMAH or Log4Net or Enterprise Logging Application Block

Categories

Resources