// Copyright 2004-2009 Castle Project - http://www.castleproject.org/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #if (!SILVERLIGHT) namespace Castle.MicroKernel.Lifestyle { using System; using System.Collections.Generic; using System.Web; /// /// Implements a Lifestyle Manager for Web Apps that /// create at most one object per web request. /// [Serializable] public class PerWebRequestLifestyleManager : AbstractLifestyleManager { private string PerRequestObjectID = "PerRequestLifestyleManager_" + Guid.NewGuid(); #region ILifestyleManager Members public override object Resolve(CreationContext context) { HttpContext current = HttpContext.Current; if (current == null) throw new InvalidOperationException( "HttpContext.Current is null. PerWebRequestLifestyle can only be used in ASP.Net"); if (current.Items[PerRequestObjectID] == null) { if (!PerWebRequestLifestyleModule.Initialized) { string message = string.Format("Looks like you forgot to register the http module {0}{1}Add '' to the section on your web.config", typeof(PerWebRequestLifestyleModule).FullName, Environment.NewLine); throw new Exception(message); } object instance = base.Resolve(context); current.Items[PerRequestObjectID] = instance; PerWebRequestLifestyleModule.RegisterForEviction(this, instance); } return current.Items[PerRequestObjectID]; } public override bool Release(object instance) { // Since this method is called by the kernel when an external // request to release the component is made, it must do nothing // to ensure the component is available during the duration of // the web request. An internal Evict method is provided to // allow the actual releasing of the component at the end of // the web request. return false; } internal void Evict(object instance) { base.Release(instance); } public override void Dispose() { } #endregion } #region PerWebRequestLifestyleModule public class PerWebRequestLifestyleModule : IHttpModule { private static bool initialized; private const string PerRequestEvict = "PerRequestLifestyleManager_Evict"; public void Init(HttpApplication context) { initialized = true; context.EndRequest += new EventHandler(Application_EndRequest); } public void Dispose() { } internal static void RegisterForEviction(PerWebRequestLifestyleManager manager, object instance) { HttpContext context = HttpContext.Current; var candidates = (IDictionary)context.Items[PerRequestEvict]; if (candidates == null) { candidates = new Dictionary(); context.Items[PerRequestEvict] = candidates; } candidates.Add(manager, instance); } protected void Application_EndRequest(Object sender, EventArgs e) { HttpApplication application = (HttpApplication) sender; var candidates = (IDictionary)application.Context.Items[PerRequestEvict]; if (candidates != null) { foreach(KeyValuePair candidate in candidates) { PerWebRequestLifestyleManager manager = candidate.Key; manager.Evict(candidate.Value); } application.Context.Items.Remove(PerRequestEvict); } } internal static bool Initialized { get { return initialized; } } } #endregion } #endif