What is the equivalent of Web Forms "Page_Load" in ASP.NET Core 5, so my code will run before any page loading? - asp.net-core

Is there a way to execute a code on every page load in ASP.NET Core 5, like there is in Web Forms? In Web Forms I used the Page_Load() event handler, but what is the equivalent in ASP.NET Core 5? So if I call any action in any controller, it will run my code first, then run the action execution.
I found this: How can I execute common code for every request?, But when I tried it I got errors.
Please someone provide me with clear solution.
Also, I need a solution to check the session from one place, instead of writing the "check session code" in each controller, I create the session after the login is succeed, but what is the best way to check the session in all controllers and if it is null then redirect to login page?

In asp.net core, you can use Action filters to replace the "Page_Load" method in
webform.
You can register the global scope of Action filters in the startup to ensure that the Action filters will be executed before each action is executed.
Add the following Action filter in your project :
public class MyActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
if (!context.HttpContext.Request.Path.ToString().Contains("Login"))
{
if (context.HttpContext.Session.GetString("user") == null)
{
context.Result = new RedirectToRouteResult(
new RouteValueDictionary { { "controller", "Login" }, { "action", "Index" } });
}
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
}
}
Then in startup.cs ConfigureServices method, add following code to apply it to all scope:
services.AddControllersWithViews(options =>
{
options.Filters.Add(typeof(MyActionFilter));
});

Related

How to modify ViewComponent result in ASP.NET Core 3.1

I want to modify the result of ViewComponent by using a filter as we do with MVC ActionFiltersAttribute. I've tried ActionFilterAttribute but it's not working with ViewComponent even it's not calling.
public class BeforeCheckoutCallFilter : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext context)
{
if (context.RouteData.Values["action"].ToString().Equals("ProductDetails_AttributeChange", StringComparison.InvariantCultureIgnoreCase))
{
//Business logic
}
return;
}
}
I'm registering this filter inside Startup.cs
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
services.Configure<MvcOptions>(options =>
{
options.Filters.Add<BeforeCheckoutCallFilter>();
}
}
Is there a way to get the ViewComponent result and modify it as we were used to doing with MVC filters?
Updated: I want to intercept the call after returning IViewComponentResult.
Note: I've got know that the ViewComponent does not take part in the controller lifecycle, which means we can’t use filters in a view component.
There is no support for direct interception of ViewComponents, as it does not take part of the request pipeline. From the official doc:
A view component class:
Doesn't take part in the controller lifecycle, which means you can't use filters in a view component
But you can do it indirectly by invoking the ViewComponent from an Action instead. Then decorate the Action with your Filter:
[BeforeCheckoutCall]
public IActionResult Checkout()
{
return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });
}

Audit.NET and Asp Net Core Razor Pages

I am using razor pages in my ASP.NET Core application. I need to enable logging with Audit.NET library, it works fine with ASP.NET MVC controllers, but it doesn't work with Razor pages.
Here is an example how I declare a PageModel class with Audit attribute:
[Audit(EventTypeName = "{area}/{Page} ({verb})",
IncludeResponseBody = true,
IncludeRequestBody = true,
IncludeHeaders = true,
IncludeModel = true)]
public class LoginIndexModel : PageModel
{
...
}
It throws NullReferenceException when AuditAttribute action filter is invoked.
Here is the method declared in AuditAttribute:
(As I understand actionDescriptor parameter cannot be casted to ControllerActionDescriptor)
private bool IsActionIgnored(ActionDescriptor actionDescriptor)
{
if (actionDescriptor == null)
return false;
return ((IEnumerable<object>)(actionDescriptor as ControllerActionDescriptor).ControllerTypeInfo
.GetCustomAttributes(typeof(AuditIgnoreAttribute), true)).Any<object>() ||
((IEnumerable<object>)(actionDescriptor as ControllerActionDescriptor).MethodInfo
.GetCustomAttributes(typeof(AuditIgnoreAttribute), true)).Any<object>();
}
So what can I do in this case?
Has anyone encountered a similar problem?
The audit mechanism for MVC was implemented with an action filter, but action filters are not supported on Razor Pages.
For razor pages, a Page Filter is provided instead, so you can configure the auditing.
Use the provided AuditPageFilter instead of the [Audit] attribute.
Basically you just need to add the filter to the collection on your startup logic, for example:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages()
.AddMvcOptions(options =>
{
options.Filters.Add(new Audit.Mvc.AuditPageFilter()
{
IncludeHeaders = true, ...
});
});
}
Check the readme here.

Inject validator in ASP.NET core filter

I have the following ASP.NET Core controller action:
public async Task<IActionResult> Post([FromBody]Model model) {
IValidator<Model> validator = new Validator<Model>();
if (!validator.IsValid)
return await validation.ToErrorResponse();
// Remaining code
}
I configured ASP.NET core to inject IValidator on Startup.
I would like to make the validation automatic using a filter:
public class ValidateAttribute : ActionFilterAttribute {
public overrideTask OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next) {
}
}
Inside the filter I need to request the correct Validator according to the Model being submitted and returning the errors.
How can I get the validator and the model being submitted inside the filter?

MVC 4 - getting a 404 on a certain area's controllers

My problem is regarding setting up my app's access for internal users and external users.
Based on MS TechKB: AREAS in ASP.NET I went with AREAS. I have an Areas/Internal and Areas/External. Areas/External has the actual functionality and controllers for the app. All Areas/Internal does is check server variables and sets your identity as your domain name if it checks out in active directory.
The problem is, I can get to the Areas/External controllers/pages just fine but when I try to browse to the Areas/Internal area controller I get a 404. My controller is named Intranet (excluding the "Controller" in the name) and this is what my InternalAreaRegistration.cs file looks like:
public override void RegisterArea(System.Web.Mvc.AreaRegistrationContext context)
{
context.MapRoute(
"Internal_default",
"Intranet/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional });
}
public override string AreaName
{
get
{
return "Internal";
}
}
Can anyone tell me why I would be getting a 404 on the internal controllers?
It seems you are missing controller segment after Area in the code you wrote above. It should be something like:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Internal_default",
"Intranet/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "Your Controller Namespace" }
);
}
A related question at below link is answered, hope that will help too:
Controller with same name as an area - Asp.Net MVC4

Routing GET and POST routes in ASP.NET MVC 4

I am trying to setup a Login form in an ASP.NET MVC 4 app. Currently, I have configured my view as shown here:
RouteConfig.cs
routes.MapRoute(
"DesktopLogin",
"{controller}/account/login",
new { controller = "My", action = "Login" }
);
MyController.cs
public ActionResult Login()
{
return View("~/Views/Account/Login.cshtml");
}
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model)
{
return View("~/Views/Account/Login.cshtml");
}
When I attempt to visit /account/login in the browser, I receive an error that says:
The current request for action 'Login' on controller type 'MyController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Login() on type MyApp.Web.Controllers.MyController
System.Web.Mvc.ActionResult Login(MyApp.Web.Models.LoginModel) on type MyApp.Web.Controllers.MyController
How do I setup a basic form in ASP.NET MVC 4? I've looked at the sample Internet App template in ASP.NET MVC 4. However, I can't seem to figure out how the routing is wired up. Thank you so much for your help.
I haven't tried this yet but can you try annotating your Login actions with the appropriate Http Verb - I'm assuming that you're using a GET for viewing the login page and a POST for processing the login.
By adding [HttpGet] for the first action and [HttpPost] for the second action the theory is that ASP.Net's routing will then know which Action method to call based upon which method has been used. Your code should then look something like this:
[HttpGet] // for viewing the login page
[ViewSettings(Minify = true)]
public ActionResult Login()
{
return View("~/Views/Account/Login.cshtml");
}
[HttpPost] // For processing the login
[ViewSettings(Minify = true)]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model)
{
return View("~/Views/Account/Login.cshtml");
}
If this doesn't work, consider having two routes and two differently named actions like below:
routes.MapRoute(
"DesktopLogin",
"{controller}/account/login",
new { controller = "My", action = "Login" }
);
routes.MapRoute(
"DesktopLogin",
"{controller}/account/login/do",
new { controller = "My", action = "ProcessLogin" }
);
There are other similar questions and answers on StackOverflow already, take a look at: How to route GET and DELETE for the same url and there is also the ASP.Net documentation which might also help.