1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.MicroKernel
.Lifestyle
18 using System
.Collections
;
19 using System
.Configuration
;
23 /// Implements a Lifestyle Manager for Web Apps that
24 /// create at most one object per web request.
27 public class PerWebRequestLifestyleManager
: AbstractLifestyleManager
29 private string PerRequestObjectID
= "PerRequestLifestyleManager_" + Guid
.NewGuid().ToString();
31 #region ILifestyleManager Members
33 public override object Resolve(CreationContext context
)
35 HttpContext current
= HttpContext
.Current
;
38 throw new InvalidOperationException(
39 "HttpContext.Current is null. PerWebRequestLifestyle can only be used in ASP.Net");
41 if (current
.Items
[PerRequestObjectID
] == null)
43 if (!PerWebRequestLifestyleModule
.Initialized
)
45 string message
= "Looks like you forgot to register the http module " +
46 typeof(PerWebRequestLifestyleModule
).FullName
+
47 "\r\nAdd '<add name=\"PerRequestLifestyle\" type=\"Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.MicroKernel\" />' " +
48 "to the <httpModules> section on your web.config";
50 throw new ConfigurationErrorsException(message
);
53 object instance
= base.Resolve(context
);
54 current
.Items
[PerRequestObjectID
] = instance
;
55 PerWebRequestLifestyleModule
.RegisterForEviction(this, instance
);
58 return current
.Items
[PerRequestObjectID
];
61 public override void Release(object instance
)
63 // Since this method is called by the kernel when an external
64 // request to release the component is made, it must do nothing
65 // to ensure the component is available during the duration of
66 // the web request. An internal Evict method is provided to
67 // allow the actual releasing of the component at the end of
71 internal void Evict(object instance
)
73 base.Release(instance
);
76 public override void Dispose()
83 #region PerWebRequestLifestyleModule
85 public class PerWebRequestLifestyleModule
: IHttpModule
87 private static bool initialized
;
89 private const string PerRequestEvict
= "PerRequestLifestyleManager_Evict";
91 public void Init(HttpApplication context
)
94 context
.EndRequest
+= new EventHandler(Application_EndRequest
);
101 internal static void RegisterForEviction(PerWebRequestLifestyleManager manager
, object instance
)
103 HttpContext context
= HttpContext
.Current
;
105 IDictionary candidates
= (IDictionary
) context
.Items
[PerRequestEvict
];
107 if (candidates
== null)
109 candidates
= new Hashtable();
110 context
.Items
[PerRequestEvict
] = candidates
;
113 candidates
.Add(manager
, instance
);
116 protected void Application_EndRequest(Object sender
, EventArgs e
)
118 HttpApplication application
= (HttpApplication
) sender
;
119 IDictionary candidates
= (IDictionary
) application
.Context
.Items
[PerRequestEvict
];
121 if (candidates
!= null)
123 foreach(DictionaryEntry candidate
in candidates
)
125 PerWebRequestLifestyleManager manager
=
126 (PerWebRequestLifestyleManager
) candidate
.Key
;
127 manager
.Evict(candidate
.Value
);
130 application
.Context
.Items
.Remove(PerRequestEvict
);
134 internal static bool Initialized
136 get { return initialized; }