Custom ErrorHandling action filter that catches only certain type of exceptions - asp.net-mvc-3

I have implemented the following action filter to handle ajax errors:
public class HandleAjaxCustomErrorAttribute : ActionFilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAjaxRequest()) return;
filterContext.Result = AjaxError(filterContext.Exception.Message, filterContext);
//Let the system know that the exception has been handled
filterContext.ExceptionHandled = true;
}
}
I want the filter to be able to catch only certain types of errors and use it like this in the controller action:
[HandleAjaxCustomErrorAttribute(typeof(CustomException))]
public ActionResult Index(){
// some code
}
How can this happen? Thanks!

I take it you're looking for this: http://msdn.microsoft.com/en-us/library/aa288454%28v=vs.71%29.aspx#vcwlkattributestutorialanchor1
To give the attribute a parameter you can either make a nonstatic property or have a constructor. In your case it'd look something like this:
public class HandleAjaxCustomErrorAttribute : ActionFilterAttribute, IExceptionFilter
{
private Type _exceptionType;
public void OnException(ExceptionContext filterContext)
{
if (filterContext.Exception.GetType() != _exceptionType) return;
if (!filterContext.HttpContext.Request.IsAjaxRequest()) return;
filterContext.Result = AjaxError(filterContext.Exception.Message, filterContext);
//Let the system know that the exception has been handled
filterContext.ExceptionHandled = true;
}
public HandleAjaxCustomErrorAttribute(Type exceptionType)
{
_exceptionType = exceptionType;
}
}

Related

How to develop action filter controller or action method specific

i was trying to develop a custom action filter which will check cookie is enable or not. if cookie is not enable then redirect use to a specific error page.here is my code.
public class CheckCookieAttribute : FilterAttribute, IActionFilter
{
public string prmAction{get;set;}
public string prmController{get;set;}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
if(filterContext.HttpContext.Request.Cookie["YourCookie"]==null)
{
filterContext.Result = controller.RedirectToAction(prmAction,prmController)
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
//The action filter logic - after
}
}
now i am using like
[CheckCookie(prmAction="MyAction",prmController="MyController")]
due to lack of good knowledge i am not being able to develop attribute driven check for cookie enable or disable.
i want to develop a code in such a way as a result i should not pass any controller name or action name. i like to use code like
[HttpPost]
[CheckCookieAttribute]
public ActionResult Save(Person oPerson)
{
return View();
}
[CheckCookieAttribute]
public class HomeController : Controller
{
public ActionResult Index()
{return View();}
public ActionResult About()
{return View();}
}
}
where i will not provide any name of controller or action name. just guide me what i need to change in my code. thanks
It seems that what you are trying to accomplish is already built into ASP.NET MVC.
I would use the [Authorize] attribute (http://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute(v=vs.108).aspx) where you want to check if the user has a cookie.
If you want to redirect the user to a specific controller/action when the user is not authorized, you can use the following attribute instead:
public class AuthorizeUserAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(
new
{
controller = "Error",
action = "Unauthorized"
})
);
}
}
See ASP.NET MVC 4 Custom Authorize Attribute with Permission Codes (without roles)
Then you would use it by using:
[HttpPost]
[AuthorizeUser]
public ActionResult Save(Person oPerson)
{
return View();
}
Or if you want exactly what you asked for you can do it this way:
public class CheckCookieAttribute : ActionFilterAttribute, IActionFilter
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.Cookies["YourCookie"] == null)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { {"controller", "MyController"}, {"action", "MyAction"}});
}
else
{
base.OnActionExecuting(filterContext);
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
//The action filter logic - after
}
}

Web API ReadFromStreamAsync not executed

I have a very dumb issue related to a custom formatter.
public class RequestHeaderJsonFormatter : MediaTypeFormatter
{
public RequestHeaderJsonFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
}
public override System.Threading.Tasks.Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
return base.ReadFromStreamAsync(type, readStream, content, formatterLogger);
}
public override bool CanReadType(Type type)
{
return true;
}
public override bool CanWriteType(Type type)
{
return true;
}
}
I register the formatter in Global.asax as it follows:
protected void Application_Start()
{
GlobalConfiguration.Configuration.Formatters.Insert(0, new RequestHeaderJsonFormatter());
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}
My issue is that ReadFromStreamAsync never gets called when executing the controller action.
public class HomeController : ApiController
{
public HttpResponseMessage GetString(string param)
{
var response = Request.CreateResponse(HttpStatusCode.OK, "ererrer");
return response;
}
}
What am I doing wrong...I can't figure it out. Any help would be much appreciated.
By default 'string' type action parameters are expected to be read from Uri, unless [FromBody] attribute is used to decorate it, in which case the formatters come into picture.
public HttpResponseMessage GetString(*[FromBody]*string param)

Why would a custom MVC3 action filter work on one controller action but not on another?

Here's the situation. I've got a single action filter that I'm using in two different controllers. The action filter is defined as:
public class ValidSubmissionAttribute : FilterAttribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext filterContext)
{
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
var controller = filterContext.Controller;
var session = filterContext.HttpContext.Session;
var isValid = controller.TempData["IsValid"];
if (isValid == null || !(bool)isValid)
{
SharedUtilities.LogOutUser(session, controller.ViewData.ModelState);
filterContext.Result = SharedUtilities.GetThankYouRedirect();
}
}
}
When I invoke the Attribute in one controller, like this:
[HttpPost]
public ActionResult DoSomething(string button, Model data)
{
try
{
if (ModelState.IsValid)
{
TempData["IsValid"] =
Request.Form["ValidRequest"] == Session.SessionID;
Session["VerifyDoingSomethingData"] = data;
return RedirectToAction("VerifyDoingSomething");
}
}
catch (Exception ex)
{
}
}
[ValidSubmission]
public ActionResult VerifyDoingSomething()
{
ViewData.Model = Session["VerifyDoingSomethingData"];
return View("VerifyDoingSomething");
}
it functions as expected. However, when I call it from a different controller, like this:
[HttpPost]
public ActionResult Index(string button, Model data)
{
try
{
if (ModelState.IsValid)
{
TempData["IsValid"] =
Request.Form["ValidRequest"] == Session.SessionID;
Session["ViewModel"] = data;
return RedirectToAction("VerifyCancellation");
}
}
catch (Exception ex)
{
}
}
[ValidSubmission]
public ActionResult VerifyCancellation()
{
ViewData.Model = Session["ViewModel"];
return View("VerifyCancellation");
}
the attribute doesn't run at all. My breakpoint in the OnActionExecuting method doesn't get hit.
If I had to guess, I'd say there was some difference in the controllers or in the action methods, but they appear to be functionally similar. Any insights? Why would I be seeing such different behavior?
Aaaaand, I'm a schmuck.
Turns out there's a completely different execution path that I'd forgotten about. That path didn't have the TempData information to use in the ValidSubmisionAttribute. Everything is functioning correctly now.

Best way to populate a base viewmodel

I know there are two ways to populate a base modelview:
First way, using OnActionExecuted method:
public abstract class BaseController : Controller
{
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
var result = filterContext.Result as ViewResultBase;
if (result != null)
{
var model = filterContext.Controller.ViewData.Model as BaseViewModel;
if (model != null)
{
model.CurrentUser = HttpContext.Current.Request.Cookies["CurrentUser"].Value;
}
}
}
Second way, property get accessor:
public abstract class BaseViewModel
{
public string CurrentUser
{
get
{
return HttpContext.Current.Request.Cookies["CurrentUser"].Value;
}
}
}
Which way is better? any pros/cons I'm missing?
I'd do it the second way, as it'd be a little more clearer as to what the model value of CurrentUser is, without having to go poking around in the controllers.

How to create custom JsonAuthorize Attribute to secure actions which returns JsonResults?

I was thinking how to correctly secure JsonResult action with custom attribute instead of doing kind of this on each action like saying here ASP.NET MVC JsonResult and AuthorizeAttribute
if (!User.Identity.IsAuthenticated)
return Json("Need to login");
But the question is how could i create such attribute which would return Json.
So i've started from that:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class JsonAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
IPrincipal user = httpContext.User;
if (!user.Identity.IsAuthenticated)
{
//?
}
//Need to return json somehow ?
}
}
Bot how i may return json result from such attribute? any ideas?
You can use an ActionFilterAttribute which allows you to return a result without using the httpcontext.response.write or anything.
public class JsonActionFilterAttribute : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if (!HttpContext.Current.User.Identity.IsAuthenticated) {
filterContext.Result = new JsonResult() { Data = "Need to login." };
}
base.OnActionExecuting(filterContext);
}
}
1 way is to override AuthorizeAttribute.HandleUnauthorizedRequest
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
throw new CustomUnauthorizedException();
}
... And then in your Global.asax:
protected void Application_Error(object sender, EventArgs e)
{
Exception error = Server.GetLastError();
if (error is CustomUnauthorizedException) {
if (AjaxRequest(Request)) {
... return Json response.
} else {
... redirect
}
}
}
So you can throw the exception anywhere in your codebase and you've centralized the handling of that exception in Global.asax
Try this.. it works for me
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
dynamic ResponseObj = new JObject();
ResponseObj.Message = "Authorization has been denied for this request.";
string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(ResponseObj);
actionContext.Response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.Unauthorized,
Content = new StringContent(jsonString, System.Text.Encoding.UTF8,"application/json")
};
}

Resources