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();
}
Related
I am using asp.net web-api with controllers.
I want to do a user section where one can request the site's address with the username after it like example.com/username. The other, registered routes like about, support, etc. should have a higher priority, so if you enter example.com/about, the about page should go first and if no such about page exists, it checks whether a user with such name exists. I only have found a way for SPA fallback routing, however I do not use a SPA. Got it working manually in a middleware, however it is very complicated to change it.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
string[] internalRoutes = new string[] { "", "about", "support", "support/new-request", "login", "register" };
string[] userNames = new string[] { "username1", "username2", "username3" };
app.Use(async (context, next) =>
{
string path = context.Request.Path.ToString();
path = path.Remove(0, 1);
path = path.EndsWith("/") ? path[0..^1] : path;
foreach (string route in internalRoutes)
{
if (route == path)
{
await context.Response.WriteAsync($"Requested internal page '{path}'.");
return;
}
}
foreach (string userName in userNames)
{
if (userName == path)
{
await context.Response.WriteAsync($"Requested user profile '{path}'.");
return;
}
}
await context.Response.WriteAsync($"Requested unknown page '{path}'.");
return;
await next(context);
});
app.Run();
It's really straightforward with controllers and attribute routing.
First, add controller support with app.MapControllers(); (before app.Run()).
Then, declare your controller(s) with the appropriate routing. For simplicity, I added a single one that just returns simple strings.
public class MyController : ControllerBase
{
[HttpGet("/about")]
public IActionResult About()
{
return Ok("About");
}
[HttpGet("/support")]
public IActionResult Support()
{
return Ok("Support");
}
[HttpGet("/support/new-request")]
public IActionResult SupportNewRequest()
{
return Ok("New request support");
}
[HttpGet("/{username}")]
public IActionResult About([FromRoute] string username)
{
return Ok($"Hello, {username}");
}
}
The routing table will first check if there's an exact match (e.g. for /about or /support), and if not, if will try to find a route with matching parameters (e.g. /Métoule will match the /{username} route).
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)
}
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
I am working on ASP.NET MVC 4 application. I've created custom filter which purpose is to call page which display loader image. The filter looks like this:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var useLoader = filterContext.RouteData.Values["ul"] as string;
if (string.IsNullOrWhiteSpace(useLoader))
{
var view = new ViewResult()
{
ViewName = "DisplayLoader"
};
view.ViewData.Model = filterContext.HttpContext.Request.Url.PathAndQuery;
view.TempData["ul"] = "1";
filterContext.Result = view;
}
}
In the DisplayLoader view I just do this:
#model string
<script type="text/javascript">window.location = '#Html.Raw(Model)';</script>
but the problem is that after the redirect the useLoader value is always null. Is there way to persist this data?
When I tried redirect to action, the parameter is always null when I received ? I don't know why this happening like these.
ActionResult action1() {
if(ModelState.IsValid) {
// Here user object with updated data
redirectToAction("action2", new{ user = user });
}
return view(Model);
}
ActionResult action2(User user) {
// user object here always null when control comes to action 2
return view(user);
}
And with this I've another doubt. when I accessed action with route, i can get values only by RouteData.Values["Id"]. the values routed doesn't send to parameter.
<a href="#Url.RouteUrl("RouteToAction", new { Id = "454" }> </a>
Here Am I miss any configure ? or anything I miss.
ActionResult tempAction(Id) {
// Here Id always null or empty..
// I can get data only by RouteData.Values["Id"]
}
You cannot pass complex objects in an url like that. You will have to send its constituent parts:
public ActionResult Action1()
{
if (ModelState.IsValid)
{
// Here user object with updated data
return RedirectToAction("action2", new {
id = user.Id,
firstName = user.FirstName,
lastName = user.LastName,
...
});
}
return view(Model);
}
Also notice that I have added the return RedirectToAction instead of only calling RedirectToAction as shown in your code.
But a much better approach is to send only the id of the user:
public ActionResult Action1()
{
if (ModelState.IsValid)
{
// Here user object with updated data
return RedirectToAction("action2", new {
id = user.Id,
});
}
return view(Model);
}
and in your target action use this id to retrieve the user from wherever this user is stored (could be database or something):
public ActionResult Action2(int id)
{
User user = GetUserFromSomeWhere(id);
return view(user);
}
Some alternative approaches (but one I don't recommend or use) is to persist the object in TempData:
public ActionResult Action1()
{
if(ModelState.IsValid)
{
TempData["user"] = user;
// Here user object with updated data
return RedirectToAction("action2");
}
return view(Model);
}
and in your target action:
public ActionResult Action2()
{
User user = (User)TempData["user"];
return View(user);
}