views:

248

answers:

2

First of all, it needs to create some codes that handle any error in my application like the following code.

public class HandleSomeErrorAttribute : HandleErrorAttribute
{
    public string ControllerName { get; set; }
    public string ActionName { get; set; }

    public override void OnException(ExceptionContext filterContext)
    {
        base.OnException(filterContext);

        if(filterContext.Result != null)
        {
            var viewResult = filterContext.Result as ViewResult;

            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(
                 new
                 {
                     controller = ControllerName,
                     action = ActionName,
                     errorInfo = "test"
                 }
            ));
        }
    }
}

Everything works fine if I send test as errorInfo value. In the other hand, if I send some errorInfo object as errorInfo value, action controller will not receive any errorInfo value. It always is null.

I know this behavior is designed to handle any values in form collection that is sent by web browser when user submits form. So, it always read only string value and parses it to object.

So, is it possible to do that?

Thanks,

A: 

Nope. A redirect returns a string to your browser, informing it of the page (and query parameters) it should fetch. You can (and should!) watch this in Fiddler. So whatever you put into a redirect has to be serializable to/from a string.

Craig Stuntz
A: 

After I search some related question in Stackoverflow, I just realize that any redirect action in ASP.NET sends HTTP 302 code to browser. After that, browser will create new request to fetch new URL (that can be found in HTTP 302 header).

Therefore, it is impossible to directly send any complex objects (without serialize it) to browser and order browser to send it back to server. Although, it is possible, but I think it is so silly to do that. Because you can use the following code to call another action without send HTTP 302 to browser.

public class TransferResult : ActionResult
{
    public TransferResult(string controllerName, string actionName, RouteValueDictionary routeValues = null)
    {
        RouteValues = routeValues ?? new RouteValueDictionary();

        if (!string.IsNullOrEmpty(controllerName))
        {
            RouteValues[MvcApplication.ControllerRouteKey] = controllerName;
        }

        if (!string.IsNullOrEmpty(actionName))
        {
            RouteValues[MvcApplication.ActionRouteKey] = actionName;
        }

        if(RouteValues[MvcApplication.ControllerRouteKey] == null)
        {
            throw new ArgumentException(Resources.ControllerNameIsNotFoundInRouteValueDictionary, "controllerName");
        }

        if (RouteValues[MvcApplication.ActionRouteKey] == null)
        {
            throw new ArgumentException(Resources.ActionNameIsNotFoundInRouteValueDictionary, "actionName");
        }
    }

    public TransferResult(RouteValueDictionary routeValues)
        : this(null, null, routeValues)
    {
    }

    public RouteValueDictionary RouteValues { get; set; }

    public override void ExecuteResult(ControllerContext context)
    {
        var routeData = new RouteData();

        foreach (var item in RouteValues)
        {
            routeData.Values.Add(item.Key, item.Value);   
        }

        var contextWrapper = new HttpContextWrapper(HttpContext.Current);
        var request = new RequestContext(contextWrapper, routeData);

        var controller = ControllerBuilder.Current.GetControllerFactory().CreateController(context.RequestContext, RouteValues[MvcApplication.ControllerRouteKey].ToString());
        controller.Execute(request); 
    }
} 

Next, I create some handle error for handling some error type and transfering it to another action controller.

public class SomeHandleErrorAttribute : HandleErrorAttribute
{
    public SomeHandleErrorAttribute (string controllerName, string actionName)
    {
        ExceptionType = typeof (EntityException);
        ControllerName = controllerName;
        ActionName = actionName;
    }

    public string ControllerName { get; set; }
    public string ActionName { get; set; }

    public override void OnException(ExceptionContext filterContext)
    {
        base.OnException(filterContext);

        if(filterContext.Result != null)
        {
            var routeValue = new RouteValueDictionary
             {
                 {"errorInfo", filterContext}
             };

            filterContext.Result = new TransferResult(ControllerName, ActionName, routeValue);
        }
    }
}

Finally, I create the action for handling this error.

public class ErrorController : Controller
{
    public string EntityError(ExceptionContext errorInfo)
    {
        return string.Format("Handle error for {0} ", errorInfo.Exception.Message);
    }
}
Soul_Master