Is there any possibility to find function like Page_Load? I have MVC application and I need run some code every page is loaded, or reloaded, or I call some controller. One shared function for everything classes?
I try Application_Start, but this execute only for first time application run. I search some like BeginRequest, but this function have been call several times, I need only first, when I load page and I need end function, like constructor and destructor for whole project.
Here is sample code.
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
}
document.ready isn't my case. And call function every controller is last option. The code must be executed before any other function have been called. And before all end, i need run end function. For example, at first I need created mysql connector shared for all classes. And at end I need close mysql connection.
Make all your controllers inherit from a custom BaseController:
public class BaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
// your code here
}
}
public class HomeController : BaseController // instead of Controller
{
// ...
}
An update to Jan's answer. The onExecutingAction abstract method is public now not protected.
public virtual void OnActionExecuting(ActionExecutingContext context);
So, you can't use the protected access modifier when you override. Make it public instead.
public class BaseController : Controller
{
public override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
}
}
Related
I've added a generic handler (KeepSessionAlive.ashx) to the root of my mvc 4 project. The code in the handler is:
public class KeepSessionAlive : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
context.Session["KeepSessionAlive"] = DateTime.Now;
}
public bool IsReusable
{
get
{
return false;
}
}
}
Whenever I run my application and check while debugging, I don't see the Session["KeepSessionAlive"] being set. I tried adding a break point in the ProcessRequest method in the handler, but the break point is never hit as I'm surfing the site. Do I need to do anything else to get the application to pick up the handler?
We had done something like in a webforms project and I don't recall having to do anything else in there. Also I've updated my route to include:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{resource}.ashx/{*pathInfo}");
//other routes skipped
}
I added the .ashx in there in case that was the problem, but either way with or without that line the handler does not seem to get invoked.
You can override the OnActionExecuted method of the Controller.
public class BaseController : Controller
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.HttpContext.Session["KeepSessionAlive"] = DateTime.Now;
}
}
After this just derive your controller from this BaseController. This is a more 'MVC-way'.
Another approach is to create a custom ActionFilter and apply it globally, as mentioned by SLaks:
public class KeepSessionAliveAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.HttpContext.Session["KeepSessionAlive"] = DateTime.Now;
}
}
You need to remember to register it
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new KeepSessionAliveAttribute());
}
}
PS: You handler might not be working because you haven't registered it on your web.config
What I am asking my not even be possible (I am skeptical) but I have been tasked to do this exact thing so please if its not possible or dumb please explain why.
I have a base project that contains an ActionFilter attribute that overrides OnActionExecuting. It does nothing as it is supposed to be a base class to inherit from.
namespace mybaseproject
public class BaseActionAttribute : ActionFilterAttribute
{
public string ActionName {get;set;}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
}
}
I have a second project that references 'mybaseproject' and uses BaseActionAttribute.
namesapce mysecondproject
public class MyController : Controller
{
[BaseAction(ActionName="Index")]
public ActionResult Index()
{
//do stuff
}
}
I have a third project that references both 'mybaseproject' and 'mysecondproject'. It has an ActionFilterAttribute that inherits from the base one and has all of the real code to process.
using mybaseproject;
namespace mythirdproject
public class DerivedActionAttribute : BaseActionAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// do all the real stuff
base.OnActionExecuting(filterContext);
}
}
What the desired effect is for the BaseActionAttribute in mysecondproject to use the code in DerivedActionAttribute of mythirdproject. I don't see how this can work because mysecondproject has no reference to mythirdproject. They just reside in the solution. I have tried using Authorize attribute as well but my breakpoint never gets hit in the derived attribute when I call my action in the second project.
This was how I was told to tackle the problem. Either I misunderstood or am taking the wrong approach, or this is just not possible.
Which one? Thanks ahead for listening.
I'm using code first to develop my database for my MVC app. Here's the connection string:
<add name="OrtundWebConnectionString" connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=OrtundWeb; User Id=sa; Password=sa;" providerName="System.Data.SqlClient"/>
It uses SQL Authentication because for reasons I've yet to determine, Windows Auth doesn't allow me to do anything on the server...
Here's Application_Start():
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
OrtundDB.InitializeDB();
}
This class calls db.Database.Initialize(true); and runs a method I wrote to add some default information into the database
public static class OrtundDB
{
private static OrtundDBContext db = new OrtundDBContext();
public static void InitializeDB()
{
db.Database.Initialize(true);
db.InitializeDB();
}
}
Here's the DBContext class I wrote that's being used. This exists in another project which is referenced in the MVC project:
internal class OrtundDBContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// modelBuilder.Configuration.Adds()
}
public OrtundDBContext()
: base("OrtundWebConnectionString")
{
Database.SetInitializer<OrtundDBContext>(new DropCreateDatabaseAlways<OrtundDBContext>());
}
public void InitializeDB()
{
// inserts the default data - an admin user account and information for user roles
}
// DbSet calls here
}
I've previously built an MVC app with this same methodology, and that one works. This, however, doesn't even execute Application_Start() every time.
On the odd occasion where it has executed Application_Start, it went all the way through to execute db.Database.Initialize(true); at which point, it just never seemed to end. I got no errors, but the action didn't seem to complete.
I'm a bit of a novice when it comes to MVC so I have no idea what the problem could be or how to fix it.
Any assistance to fix the problem (and possibly explanation as to what might cause it) will be greatly appreciated.
Thanks in advance!
Perhaps the issues lies with the expectation you have on Application_Start.
Application_Start is called once for the application being loaded into the app pool on IIS.
Only when the app pool is recycled or IIS is restarted will it be called again.
Take 10-15mins to read IIS pipeline
It will help with what is going on.
I had a nasty bug due to my false expectations about threads and requests.
alternatives to Consider and test in debug to see if they suit you:
The INIT in Global.asax
public override void Init() {
base.Init();
// handlers managed by ASP.Net during Forms authentication
BeginRequest += new EventHandler(BeginRequestHandler);
// PostAuthorizeRequest += new EventHandler(PostAuthHandler);
EndRequest += new EventHandler(EndRequestHandler);
}
Better: A single baseController for all your controllers so as to control bootstrap each call.
public class SomeController : MyBaseMvcController{
// whatever as usual....
}
[System.Web.Mvc.Authorize]
[MyMVCFilter] // see the filter below. Get the MVC pipeline to call your code on Executing
public abstract class MyBaseMvcController : Controller
{
protected MyBaseMvcController () {
// a place to get a NEW uow or new Context ....
}
}
public class MyMVCFilter : System.Web.Mvc.ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext) {
// a useful bootstrap option when you need the httpContext for bootstrap.
BootStrapHttp(filterContext.HttpContext);
base.OnActionExecuting(filterContext);
}
}
i need to hit DB and load the settings file before every page loads. Am currently using MVC and am creating that call in constructor in All controllers.
Am not sure of what is the better way to handle this scenario ?? I read like we can use singleton class in this scenario.
Is it possible to have the data once and reuse across pages ? What is the best way ?
Some sample code snippets will help !
Option one: you can used Application_BeginRequest in Global.asax.cs:
protected void Application_BeginRequest(object sender, System.EventArgs e)
{
//something
}
Option two: create a global filter:
public class ActionLogFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext filterContext)
{
// do your stuff. This is run before control is passed to controller
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
// do stuff here - control here is passed after controller is done with the action execution
}
}
and then add controller to execution stack in Global.asax.cs:
FilterConfig.RegisterGlobalFilters(GlobalFilterCollection filters)
and FilterConfig is usually looks like this:
public static class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyFilter());
}
}
Option three: Create your global controller that overrides OnActionExecuting (see the filter example). Make your controllers to inherit from that global base controller.
I prefer option with filters. Favour composition over inheritance
Is it possible to extend the Controller type in Asp.net MVC to make a method available to all controller classes for application logging?
I've tried this:
public static class ControllerExtensions
{
public static ILog Log(this Controller controller)
{
log4net.Config.XmlConfigurator.Configure();
return log4net.LogManager.GetLogger(controller.GetType());
}
}
But, if I try to access the method as in:
Controller.Log.Info("hello");
It won't compile with the error message: 'System.Web.Mvc.Controller' does not contain a definition for 'Log'
I do have a using statement bringing the static class into scope.
Any help would be great.
Jacques
I would suggest to implement abstract base controller class for this purpose:
public abstract class BaseController : Controller
{
public ILog Log
{
get { return LogManager.GetLogger(GetType()); }
}
}
You can also achieve similar result using protected static log instance, here is an example with Serilog:
protected static readonly ILogger log = Log.ForContext(typeof(MyController));
Try
//inside a controller's method
this.Log().Info("hello");
You're not adding a property Log, you're adding an extension method Log().
There's no such thing as "extension properties".
How about creating a custom action filter?
create a class LogInfo inherited by ActionFilterattribute
public class LogInfo : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Logging operation code here
}
}
Controller:
[LogInfo]
public ActionResult Index()
{
return View();
}