3

I'd want to achieve something like this:

If exception was thrown in method that returns Json then return new Json(new { success = false, error = "unknown" });

but if method returns View then return Redirect

public async Task Invoke(HttpContext ctx)
{
    try
    {
        await next(ctx);
    }
    catch (Exception ex)
    {
        HandleException(ctx, ex);
    }
}

private static void HandleException(HttpContext context, Exception ex)
{
    // some logger
    LoggerService.Log(ex);

    context.Response.Redirect("/Error/ErrorPage");
}

How to determine where request was send? I mean how to get type of method which the request was sent to?

because I'd want to do something like typeof(targetMethod) to determine whether it is e.g JsonResult or not

Thomas Ayoub
  • 29,063
  • 15
  • 95
  • 142
Joelty
  • 1,751
  • 5
  • 22
  • 64

2 Answers2

4

Sounds like you're trying to handle exception thrown by Action method. If that's the case, the ASP.NET Core has a built-in IExceptionFilter, which is suitable for that:

A filter that runs after an action has thrown an Exception.

To achieve your goal, create a CustomExceptionFilter:

public class CustomExceptionFilter : IExceptionFilter
{
    private ILogger<CustomExceptionFilter> _logger;

    public CustomExceptionFilter(ILogger<CustomExceptionFilter> logger)
    {
        this._logger = logger;
    }

    public void OnException(ExceptionContext context)
    {
        var ex = context.Exception;
        var c = (ControllerActionDescriptor) context.ActionDescriptor;

        if(c == null){
            context.Result = new StatusCodeResult(500);
        } else if (typeof(JsonResult) == c.MethodInfo.ReturnType) {
            context.Result = new JsonResult(new { success = false, error = "unknown" });
        } else {
            // Redirect
            this._logger.LogCritical(ex,ex.Message);
            context.Result = new RedirectResult("/Error/ErrorPage");
        }
    }
}

and register this filter as below :

services.AddMvc(opts => {
    opts.Filters.Add(typeof(CustomExceptionFilter));
});

it works fine for me.

itminus
  • 23,772
  • 2
  • 53
  • 88
1

You'll need a bit of reflection here:

string methodName = ControllerContext.RouteData.Values["action"].ToString();
Assembly asm = Assembly.GetExecutingAssembly();

var methodInfo = asm.GetTypes()
    .Where(type => typeof(Controller).IsAssignableFrom(type)) //filter controllers
    .SelectMany(type => type.GetMethods())
    .Where(method => method.IsPublic)
    .Where(x => x.DeclaringType != null)
    .Where(x => x.Name == methodName)
    .SingleOrDefault();

if (methodInfo == null)
{
    return null; // Method wasn't found
}

if (typeof(JsonResult) == methodInfo.ReturnType)
{
    // Return JSON
}
else if (typeof(JsonResult) == methodInfo.ReturnType)
{
    // Redirect
}
else
{
    // Exception handling
}
Thomas Ayoub
  • 29,063
  • 15
  • 95
  • 142
  • How do you access ``ControllerContext`` in middleware? I injected it but almost everything's null inside – Joelty Apr 30 '19 at 08:52
  • My bad, you can't. Try with [How to get the URL of the current page in C#](https://stackoverflow.com/q/593709/2307070), you'll need to replace `HttpContext.Current` with `context` – Thomas Ayoub Apr 30 '19 at 08:55