Dave
Dave

Reputation: 531

Usage of UseStatusCodePagesWithReExecute with a message not working as expected

I'm using UseStatusCodePagesWithReExecute in my .NET Core 2.1 web app as follows

app.UseStatusCodePagesWithReExecute("/Error/{0}");

and in my Controller I point to 1 of 2 views, a 404.cshtml view and a generic error.cshtml view

public class ErrorController : Controller
{
    [HttpGet("[controller]/{statusCode:int}")]
    public IActionResult Error(int? statusCode = null)
    {
        if (statusCode.HasValue)
        {
            if (statusCode == (int)HttpStatusCode.NotFound)
            {
                return View(statusCode.ToString());
            }
        }

        return View();
    }
}

Now in my page controller I can do the following and it works as expected. It will show error.cshtml

public IActionResult SomePage()
{
    return BadRequest();
}

Now if I change the above to the following, my ErrorController does get hit but by the time it does a blank view showing just "Some details" has been loaded in the browser.

public IActionResult SomePage()
{
    return BadRequest("Some details");
}

Any ideas why? I want it to load error.cshtml

Upvotes: 1

Views: 2535

Answers (1)

Nan Yu
Nan Yu

Reputation: 27538

As @Kirk Larkin said , UseStatusCodePagesWithReExecute middleware won't work and it will only handle the status code .

You can use Result filters to write your custom logic to filter that and return a ViewResult :

public class StatusCodeResultFilter : IAsyncResultFilter
{
    public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
    {
        // retrieve a typed controller, so we can reuse its data
        if (context.Controller is Controller controller)
        {
            // intercept the NotFoundObjectResult
            if (context.Result is BadRequestObjectResult badRequestObject)
            {
                // set the model, or other view data
                controller.ViewData.Model = badRequestObject.Value;

                // replace the result by a view result
                context.Result = new ViewResult()
                {
                    StatusCode = 400,
                    ViewName = "Views/Error/status400.cshtml",
                    ViewData = controller.ViewData,
                    TempData = controller.TempData,

                };
            }

        }

        await next();
    }
}

Register the filter :

 services.AddMvc(config =>
        {
            config.Filters.Add(new StatusCodeResultFilter());

        }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

In your view , you can directly get the detail message by :

@Model

Reference : https://stackoverflow.com/a/51800917/5751404

Upvotes: 1

Related Questions