I have a MVC3 application to which I've added a couple of simple cache variables as a property. I add my data in Application_Start and then later in a controller try to cast the HttpContext.ApplicationInstance back to my type to access it. But, the property is always null. Here's an example:
EDITED TO WORKING EXAMPLE
public interface IMyMvcApp
{
Hashtable Cache {get;set;}
}
public class MvcApplication: HttpApplication, IMyMvcApp
{
public Hashtable Cache
{
get { return Context.Cache["MyStuff"] as Hashtable; }
set { Context.Cache["MyStuff"] = value}
}
public void Application_Start()
{
Cache = new Hashtable();
Cache.Add("key", new object());
}
}
public class AController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext context)
{
var myApp = context.HttpContext.ApplicationInstance as IMyMvcApp;
Assert.IsNotNull(myApp.Cache);
}
}
There are multiple instances of the application created by the framework. To verify this add an empty constructor and put a breakpoint in it. You will see that this constructor will be hit multiple times whereas the Application_Start only once.
So instead of reinventing wheels you should use the Cache object that's already built into the framework:
protected void Application_Start()
{
...
Context.Cache["key"] = new object();
}
and then:
protected override void OnActionExecuting(ActionExecutingContext context)
{
var value = context.HttpContext.Cache["key"];
}
In addition to Darin's correct answer recommending the builtin cache, a note on Singletons in Asp.Net.
MvcApplication is NOT a singleton
Contrary to very widespread belief, MvcApplication is NOT a global singleton. The class is instantiated several times, one instance per "pipeline", so the performance counter "pipeline instance count" tells you how many instances of MvcApplication are currently consdidered alive. Add a default ctor and prove this yourself:
public MvcApplication()
{
Trace.WriteLine(this.GetHashCode());
}
Debug break the line or watch the various hash codes in DebugViewer. To force pipeline instance count going up create a method with Thread.Sleep(5000), Asp.Net will then fire up a new instance once you make another http request in parallel.
Solution - How to instantiate singletons in Asp.Net applications (MVC or WebForms)
If your MvcApplication class however has an Application_Start() method then this method is called in fact only once, process wide. This allows adding static fields to MvcApplication and access them.
These fields are then accessed by
MvcApplication.MySingleValue
obviously.
HttpApplication weirdness
The design of the HttpApplication class and its events is quite strange, which presumably has its reason in some loose sort of backwards design compatibility to very old COM based ASP pages. There the application object was in fact created only once, which is surely the origin of the wrong belief related to Asp.Net. An example of the HttpApplication strangeness:
protected void Application_Start()
{
}
Note that there is no override involved!
In summary, the application instances might be of minor interest most of the time, I can see no scenario were it could become relevant to hold state, as its state would be shared by an arbitrary subset of requests handled. So accessing it in the completely fine way as mentioned by Matt might not be required too often.
Related
I have been reading many books on NHibernate and have noticed how the Configure() is implemented. In the books that method is called every time the application is run in a console application. Most of the ASP.NET examples online call Configure() on every page request. I think this will have alot of overhead since NHibernate must be configured on every request. Does it matter if NHibernate is configured on every page request? If not, how would someone save the configuration - application wide in asp.net mvc?
NHibernate is designed to be configured once per application start. In the case of a console program, that's every time you run the program. In the case of an ASP.NET application, that's every time the application starts, firing the Application.Start event.
The SessionFactory NHibernate creates from Configure() is safe to be cached for the lifetime of the application and is thread-safe to create sessions repeatedly. There is no need to configure on every request.
In the most basic way, you can use a lazy-initialized static property to safely give you a singleton for your application to use:
public static class NHibernateSessions
{
private static readonly Lazy<SessionFactory> lazyFactory;
static NHibernateSessions
{
lazyFactory = new Lazy<SessionFactory >(
() => NHibernateSessions.CreateSessionFactory());
}
public static SessionFactory Factory
{
get
{
return NHibernateSessions.lazyFactory.Value;
}
}
public static void Initialize()
{
if(!NHibernateSessions.lazyFactory.IsValueCreated)
{
// Access the value to force initialization.
var factory = lazyFactory.Value;
}
}
private static SessionFactory CreateSessionFactory()
{
// Add code here to configure and create factory.
}
}
This code uses the Lazy<T> type, to ensure the initialization is thread-safe. You can then call NHibernateSessions.Factory to get the singleton factory with which to re-use throughout your application.
By default the factory is initialized on the first get of the Factory property. This means that for an ASP.NET application, the first request to attempt to use NHibernate will be a slow one. If this is a problem, you can force initialization when the application starts by calling the Initialize() method in an Application.Start event-handler.
I am experiencing memory leaks in an ASP.Net MVC 3 application and I suspect it may be an issue with the IoC container.
The MvcApplication creates a WindsorContainer object, populates it and then stores it in a static field like this:
public class MvcApplication : System.Web.HttpApplication, IContainerAccessor
{
private static WindsorContainer container;
protected void Application_Start()
{
ControllerBuilder.Current.SetControllerFactory(
new WindsorControllerFactory(container));
}
}
Is it correct here to hold on to the container in a static field? As far as I understand, the container itself only needs to live as long as the MVCApplication itself. Making it static would simply share it across multiple MVCApplication instances, so I wonder if it is being disposed incorrectly.
When using Castle Windsor it's important to follow the Register Resolve Release pattern, since the container itself might track disposable objects (in order to be able to dispose them).
For ASP.NET MVC this means that the ControllerFactory should invoke Release from ReleaseController. This answer contains more explanation: Explain the mysterious world of IoC and automatic Dispose
You may also want to dispose the container itself when the MvcApplication disposes...
Container can be created this way and stored in the application object as a static field. You can control the lifetime of objects create by the container (see this page). For a web application the usual lifetime is per request - example copied from the aforementioned page:
Kernel.Register(
Component.For<ISession>()
.UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession())
.LifestylePerWebRequest()
);
And in this case, you will never have to share it across multiple instances of MvcApplication class - there's usually one implementation of HttpApplication class in web application.
I want to inject an instance into structuremap on the fly (i.e. outside of a registry/configuration) that lives for the life of the request.
Currently I'm doing this in the HandleBeginRequest event of an IHttpModule:
container.Configure(x => x.For<IMyClass>()
.LifecycleIs(Lifecycles.GetLifecycle(InstanceScope.PerRequest))
.Use(new MyClass()));
However, if at some point in the application's life I do:
ObjectFactory.WhatDoIHave();
I see as many configured instances for IMyClass as there have been requests (or at least a significant amount).
Thinking about it, this sort of makes sense given the code I have.
Is there a better way to inject an instance into the container just for the life of the current request in a way that doesn't pollute the whole container?
Thanks
Your problem is that you're registering the type in the container once per request, which is building up on the registrations. Configuring the container should ideally be made once in the application's lifecycle - typically in the Application_Start event for web applications.
Structuremap allows you to specify a creational function that is invoked upon creating the object, which will let you configure advanced object creation steps.
Instead of your current call to Configure in the Begin_Request event, stick the following in the container configuration during Application_Start.
For<IMyClass>().HttpContextScoped().Use(() => new MyClass());
Notice the lambda in the Use method. The lambda can contain any logic needed in order to create the object and it will be invoked one per lifecycle (per request in the case of HttpContext lifecycle).
I went with this in the end
For<IRequestContextStorage>()
.HybridHttpOrThreadLocalScoped()
.Use<RequestContextStorage>();
For<MyClass>()
.Use(c => c.GetInstance<IRequestContextStorage>().Get<MyClass>());
...
public class RequestContextStorage : IRequestContextStorage
{
readonly IDictionary<Type, object> hash;
public RequestContextStorage()
{
this.hash = new Dictionary<Type, object>();
}
public T Get<T>() where T : class
{
if(this.hash.ContainsKey(typeof(T)))
return this.hash[typeof (T)] as T;
return null;
}
public void Set<T>(T instance)
{
this.hash[typeof (T)] = instance;
}
}
...
static void HandleBeginRequest(object sender, EventArgs e) {
ObjectFactory.Get<IRequestContextStore>().Set(new MyClass());
}
If you only have one container, and you have multiple requests, you will run into this problem. I would suggest managing the per request instances yourself by storing them in HttpContext.Items.
If you want to be able to access it through the container, create a gateway class that holds no state and pulls your per request dependency out of HttpContext for you. Register that in your container, and update dependencies on the per request object to you the gateway.
Update
I can't believe I overlooked this before, what you really want is to use HttpContextLifecycle, which will cache a given instance in the HttpContext.Items collection, where it will be available throughout your request. You will still have multiple instances active during concurrent requests, but StructureMap can figure out which one to return based on HttpContext.Current.
BIG EDIT: This problem is probably being caused by MEF!
I'm using a service oriented architecture and have all my MVC controllers perform actions through the services.
I have a base service that looks like this:
public abstract class BaseService
{
protected MyObjectModel context;
public BaseService()
{
context = new MyObjectModel();
}
}
I then have services that inherit
[Export(typeof(IEmployeeService))]
public class EmployeeService : BaseService, IEmployeeService
{
public void NewEmployee(Employee newEmployee)
{
context.Employees.AddObject(newEmployee);
context.SaveChanges();
}
}
I have my controllers also inheriting from a base class that provides access to all the required services so they can just call:
EmployeeService.AddEmployee(new Employee() { Name = "JohnDoe"});
This all worked wonderfully until I started seeing that the ObjectContext wasn't accurately reflecting the database upon construction.
I put a breakpoint in the BaseService constructor and using Sql Server's Profiler saw that the brand new MyObjectModel wasn't even hitting the DB but pulling the data out of some cache presumably?
I stumbled upon the MergeOption property of the collections in the context and changing that made sure the data was fresh, but now I need to use that everytime I create a new service method that returns entities!
EDIT:
I've been stumbling along until I realised that my issues were probably being caused by MEF.
I have overridden the default ControllerFactory and implemented one that uses MEF to instantiate the services. What I'm probably seeing is MEF keeping the objects alive between calls.
So
1) Where can I read more on this behaviour? And what can I do to stop it and force a fresh composition every time the object is called?
Thanks.
I solved this issue eventually after hours of pulling out my hair.
My implementation of ControllerFactory looked like this.
public class ControllerFactory : IControllerFactory
{
CompositionContainer container;
DefaultControllerFactory controllerFactory;
public ControllerFactory()
{
container = new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
controllerFactory = new DefaultControllerFactory();
}
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
var controller = controllerFactory.CreateController(requestContext, ControllerName);
container.ComposeParts(controller);
return controller;
}
public void ReleaseController(IController controller)
{
var disposable = controller as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
}
And I called this line in my Application Startup.
ControllerBuilder.Current.SetControllerFactory(new ControllerFactory());
What was happening was that the controller factory was only being initialised once per AppDomain cycle and therefore my composition container was as well. My service classes weren't marked specifically for Shared or Non Shared usage, so the container held onto a reference of each one. Every time the ControllerFactory created a new controller on each call it would populate the service properties with the references it still held from the last call, including the old ObjectContext which was resulting in the mismatch in data.
My entire problem was solved by adding
[PartCreationPolicy(CreationPolicy.NonShared)]
to each service enforcing a fresh version each time.
Now I'm left to wonder if MEF is STILL holding onto thos references, because that ObjectContext is not a small thing to hold onto. Is this a memory leak waiting to happen?
After looking at the .net on IIS7 application lifecycle:
http://msdn.microsoft.com/en-us/library/ms178473.aspx
For maximum performance, I want to find a way to get my code started as soon as the HttpContext object is created but before HttpApplication is. (it's easy to run code after the HttpApplication class is loaded but before any of it's event are triggered by using the contructor of an HTTP Module like this:
public class AuthModule : IHttpModule
{
public AuthModule()
{
HttpContext.Current.Response.Write("hello world");
HttpContext.Current.Response.End();
}
#region IHttpModule Members
public void Dispose()
{ }
public void Init(HttpApplication context)
{ }
#endregion
}
I know that i won't get access to the User object, but i won't need it.
You cannot ever be sure your code starts before the HttpApplication instance is created, since these instances may be reused.
Also, running code at this stage is beyond the scope of the pipeline. It should make you ask yourself whether it's really a sensible thing to do.
And what's this about performance? You really think the time to create an instance of HttpApplication is going to register in your performance?
Take a step back and reconsider.
Look at the life-cycle events on MSDN. You can consider using one of those events if you want something earlier than the normal page events.