Usage of UseStatusCodePagesWithReExecute with a message not working as expected - asp.net-core

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

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

Related

ASP.NET Core custom route not working with web api 2.1

I'm new to ASP.NET Core Web API and trying to implement a custom route.
Here is my controller:
using ...
namespace FoodDeliveryServer.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class MenusController : ControllerBase
{
private readonly FoodDeliveryContext _context;
public MenusController(FoodDeliveryContext context)
{
_context = context;
}
// GET: api/Menus
[HttpGet]
public IEnumerable<Menu> GetMenu_1()
{
return _context.Menu;
}
// rest of the methods
// POST: api/Menus
[HttpPost]
public async Task<IActionResult> PostMenu([FromBody] Menu menu)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_context.Menu.Add(menu);
await _context.SaveChangesAsync();
return CreatedAtAction("GetMenu", new { id = menu.Id }, menu);
}
// POST: api/Menus/filter
[HttpPost("filter", Name = "Filtermenu")]
public async Task<IActionResult> FilterMenu([FromBody] bool isActive)
{
return Ok(_context.Menu.Where(m => m.IsActive == isActive));
}
private bool MenuExists(long id)
{
return _context.Menu.Any(e => e.Id == id);
}
}
}
Now, I'm trying to hit the filter route from POSTMAN and getting 404. Other standard routes are working fine.
POST
http://localhost:5000/api/Menus/filter
Body -> raw -> JSON
{
"isActive": true
}
Headers -> Accept -> application/json
Headers -> Content-Type -> application/json
What am I doing wrong here?
I looked at this link also but still having problems:
ASP.Net Core Web API custom route not working
You can use the [Route("")] decorator on your actions too. Otherwise it will create routes upon what you defined in StartUp.Configure.
// POST: api/Menus/filter
[Route("filter")]
[HttpPost("filter", Name = "Filtermenu")]
public async Task<IActionResult> FilterMenu([FromBody] bool isActive)
{
return Ok(_context.Menu.Where(m => m.IsActive == isActive));
}
Should work for you.
The '/api/Menus/' part will be inherited from your [Route("api/[controller]")] definition on controller level
I resolved the issue with the help of #Marius. Here is what I did:
// POST: api/Menus/filter
[HttpPost]
[Route("filter", Name = "Filtermenu")]
public async Task<IActionResult> FilterMenu([FromBody] Menu menu)
{
return Ok(_context.Menu.Where(m => m.IsActive == menu.IsActive));
}
Looks like, we need to provide a class to read FromBody

How to disable direct access to a view from url?

I have two views in my asp net core application. The first view is called customer and the second view is called payment. I want to disable that users can get direct acces by typing the url "https://mywebsite/Payment" in the browser.
I want the users to be redirected to view which is called customer If users are trying to get direct access to view called payment.
How can I do that. I don't have any idea.
You could create a filter as below :
public class NoDirectAccessAttribute:ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var canAccess = false;
//check the refer
var referer = context.HttpContext.Request.Headers["Referer"].ToString();
if(!string.IsNullOrEmpty(referer))
{
var request = context.HttpContext.Request;
var rUri = new System.UriBuilder(referer).Uri;
if(request.Host.Host==rUri.Host && request.Host.Port==rUri.Port && request.Scheme==rUri.Scheme)
{
canAccess = true;
}
}
// ... check other requirements
if (!canAccess)
{
context.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Home", action = "Index", area = "" }));
}
}
}
Then you can apply NoDirectAccess Attribute to specific Action
[NoDirectAccess]
public IActionResult Privacy()
{
return View();
}

Globally ModelState Validation In Asp.Net Core Mvc

How to Can I create a custom Action Filter which will check if the ModelState is valid, and if not, it returns ModelState Errors To the Same View ?
I want to write a Custom Action Filter, which, Before all POST requests, Ensure that ModelState is valid and if ModelState is not valid,it will return the ModelState Errors to the same View.
This is my sample code. But I really don't know how to return ModelState Errors to the same view.
namespace Site.Web.Infrastructures.CustomValidationAttribute
{
public class GlobalMvcValidateModelStateAttribute : ActionFilterAttribute
{
public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
if (!context.ModelState.IsValid)
{
List<string> list = (from modelState in context.ModelState.Values from error in modelState.Errors select error.ErrorMessage).ToList();
//Also add exceptions.
list.AddRange(from modelState in context.ModelState.Values from error in modelState.Errors select error.Exception.ToString());
context.Result = new BadRequestObjectResult(list);
}
return base.OnActionExecutionAsync(context, next);
}
}
}
Here's what you need to add global ModelState validation for Views :
public class GlobalModelStateValidatorAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
Controller controller = context.Controller as Controller;
object model = context.ActionArguments.Any()
? context.ActionArguments.First().Value
: null;
context.Result = (IActionResult)controller?.View(model)
?? new BadRequestResult();
}
base.OnActionExecuting(context);
}
}
Then you need to register this Filter in your application:
services.AddMvc(opt =>
{
opt.Filters.Add(typeof(GlobalModelStateValidatorAttribute));
});
And here's the code sample: https://github.com/MoienTajik/AspNetCoreGlobalModelStateValidator

Redirecting to a response view with a model does not keep model properties

I have a form view that submits form data to the post action on a controler and then redirects to another view that uses logic to display either a success or failure, but the new view just shows blank values for model properties. Here is the post action:
[HttpPost]
public ActionResult ContactUs(TTT.Models.ContactUsModel model)
{
logger.Info(model.URL + "Contact Us Form submitted");
var userkey = model.ValidationKey;
var sessionkey = Session["ContactUsKey"];
var lastsubmission = Session["ContactUsTime"];
model.Response = "success";
//first check if honeypot was populated via a bot and if so send it to the success page without doing anything
if (model.WorkAddress != "")
{
logger.Info("honeypot triggered");
return View("ContactUsResponse", model);
}
I'll leave out the remainder of the controler, but
And here is the view it's redirecting to:
#using TTT.Models
#using Sitecore.Mvc
#model ContactUsModel
<h1>#Model.Title</h1>
<div>#Model.Body</div>
<div>
#if (#Model.Response == "fail")
{
#Model.Failure;
} else
{
#Model.Success;
}
</div>
Instead of returning a new view, call RedirectToAction and return new view from that controller.
[HttpPost]
public ActionResult ContactUs(TTT.Models.ContactUsModel model)
{
//--- Code omitted for brevity
if (model.WorkAddress != "")
{
logger.Info("honeypot triggered");
return RedirectToAction("ContactUsResponse", new { response = model });
}
}
public ActionResult ContactUsResponse(TTT.Models.ContactUsModel response)
{
return View(model)
}

Post web method not firing + asp.net core webapi

I am implementing CRUD operations using EF7 and storedprocudures in asp.net core web api project. I have finished implementing the get methods and left with the insert method. I am using Postman to test the web methods. I have written the implementation for Create but unable the post the information via postman isn't hitting the Create web method in the controller. Could somebody let me know what the problem could be. The route of the get and post is the same except the method signature is different.
Controller
public class MoviesController : Controller
{
private readonly IMoviesRepository _moviesRepository;
public MoviesController(IMoviesRepository moviesRepository)
{
_moviesRepository = moviesRepository;
}
[HttpGet]
[Route("api/Movies")]
public async Task<IActionResult> GetMovies()
{
var movies = await _moviesRepository.GetMovies();
var results = Mapper.Map<IEnumerable<MoviesDto>>(movies);
return Ok(results);
}
[HttpGet]
[Route("api/Movies/{ID}")]
public async Task<IActionResult> GetMovie(int ID)
{
var movie = await _moviesRepository.GetMovie(ID);
var results = Mapper.Map<IEnumerable<MoviesDto>>(movie);
return Ok(results);
}
[HttpPost]
[ValidateAntiForgeryToken]
[Route("api/Movies")]
public IActionResult CreateMovie([FromBody] MoviesDto movies)
{
if (movies == null)
{
return BadRequest();
}
// Check if movie exists
var movie = _moviesRepository.GetMovie(movies.MovieId);
if (movie == null)
{
return NotFound();
}
var results = Mapper.Map<Movies>(movies);
if (ModelState.IsValid)
{
_moviesRepository.AddMovie(results);
}
return Ok(results);
}
}
Postman
This issue has been fixed. I had to remove the anti-forgery token