added SPRNET-711, SPRNET-713 - MappingHandlerFactory for configuring custom IHttpHandler and IHttpHandlerFactory instances
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
using System.Web;
|
||||
|
||||
/// <summary>
|
||||
/// Summary description for NoOpHandler
|
||||
/// </summary>
|
||||
public class MyCustomHttpHandler : IHttpHandler
|
||||
{
|
||||
public string MessageText = "<unconfigured>";
|
||||
|
||||
public void ProcessRequest(HttpContext context)
|
||||
{
|
||||
context.Response.ContentType = "text/plain";
|
||||
context.Response.Write(@"Response from MyCustomHttpHandler:" + MessageText);
|
||||
}
|
||||
|
||||
public bool IsReusable
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<%@ Page Language="C#" %>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" >
|
||||
<head runat="server">
|
||||
<title><%=Title%></title>
|
||||
</head>
|
||||
<body>
|
||||
<h2><a href="../../Default.aspx">Welcome to Spring.NET Web Framework Quick Start Guide</a></h2>
|
||||
<h2><a href="../Default.aspx">Dependency Injection</a></h2>
|
||||
<div>
|
||||
<form id="form1" runat="server">
|
||||
<p>
|
||||
The links below demonstrate dependency injection on custom handlers using <b>MappingHandlerFactory</b>.
|
||||
The example code shows, how to map all url requests to spring and let MappingHandlerFactory resolve urls to
|
||||
container-managed IHttpHandlerFactory or IHttpHandler objects.
|
||||
</p>
|
||||
<pre>
|
||||
// web.config
|
||||
|
||||
<httpHandlers>
|
||||
<!-- map all requests to spring (just for demo - don't do this at home!) -->
|
||||
<add verb="*" path="*.*" type="Spring.Web.Support.MappingHandlerFactory, Spring.Web" />
|
||||
</httpHandlers>
|
||||
|
||||
// spring-objects.config
|
||||
|
||||
<object type="Spring.Web.Support.MappingHandlerFactoryConfigurer, Spring.Web">
|
||||
<property name="HandlerMap">
|
||||
<dictionary>
|
||||
<entry key="\.ashx$" value="standardHandlerFactory" />
|
||||
<!-- map any request ending with *.whatever to standardHandlerFactory -->
|
||||
<entry key="\.whatever$" value="specialHandlerFactory" />
|
||||
</dictionary>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
<object name="standardHandlerFactory" type="Spring.Web.Support.DefaultHandlerFactory, Spring.Web" />
|
||||
|
||||
<object name="specialHandlerFactory" type="MySpecialHandlerFactoryImpl" />
|
||||
</pre>
|
||||
<ul>
|
||||
<li><a href="DemoHandler.ashx">DemoHandler.ashx</a></li>
|
||||
<li><a href="AnotherCustomHandler.whatever">AnotherCustomHandler.whatever</a></li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,17 @@
|
||||
<%@ Page Language="C#" %>
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" >
|
||||
<head runat="server">
|
||||
<title>Untitled Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<form id="form1" runat="server">
|
||||
<div>
|
||||
<a href="DemoHandler.ashx">DemoHandler.ashx</a><br/>
|
||||
<a href="AnotherCustomHandler.whatever">AnotherCustomHandler.whatever</a><br/>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,30 @@
|
||||
<%@ WebHandler Language="C#" Class="DemoHandler" %>
|
||||
|
||||
using System;
|
||||
using System.Web;
|
||||
|
||||
public class DemoHandler : IHttpHandler
|
||||
{
|
||||
private string _outputText;
|
||||
|
||||
public string OutputText
|
||||
{
|
||||
get { return _outputText; }
|
||||
set { _outputText = value; }
|
||||
}
|
||||
|
||||
public void ProcessRequest(HttpContext context)
|
||||
{
|
||||
context.Response.ContentType = "text/plain";
|
||||
context.Response.Write("injected text:" + _outputText);
|
||||
}
|
||||
|
||||
public bool IsReusable
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
<!--
|
||||
the lines below map *any* request ending with *.ashx or *.whatever to the global(!) MappingHandlerFactory. Further "specialication"
|
||||
of which handler to map to is done within MappingHandlerFactory's configuration - use MappingHandlerFactoryConfigurer for this (see below)
|
||||
-->
|
||||
<add verb="*" path="*.ashx" type="Spring.Web.Support.MappingHandlerFactory, Spring.Web" validate="true"/>
|
||||
<add verb="*" path="*.whatever" type="Spring.Web.Support.MappingHandlerFactory, Spring.Web" validate="false"/>
|
||||
</httpHandlers>
|
||||
</system.web>
|
||||
|
||||
<spring>
|
||||
<context>
|
||||
<resource uri="config://spring/objects" />
|
||||
</context>
|
||||
<objects xmlns="http://www.springframework.net">
|
||||
|
||||
<!-- configures the global GenericHandlerFactory instance -->
|
||||
<object name="mappingHandlerFactoryConfigurer" type="Spring.Web.Support.MappingHandlerFactoryConfigurer, Spring.Web">
|
||||
<property name="HandlerMap">
|
||||
<dictionary>
|
||||
<!-- map any request ending with *.whatever to NoOpHandler -->
|
||||
<entry key="\.whatever$" value="myCustomHandler" />
|
||||
<entry key="\.ashx$" value="standardHandlerFactory" />
|
||||
</dictionary>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
<!--
|
||||
uses the original System.Web.UI.SimpleHandlerFactory to create handler instances
|
||||
and configures each handler using objectdefinitions matching the requestl url's filename
|
||||
-->
|
||||
<object name="standardHandlerFactory" type="Spring.Web.Support.DefaultHandlerFactory, Spring.Web" />
|
||||
|
||||
<!-- defines a standard singleton that will handle *.whatever requests -->
|
||||
<object name="myCustomHandler" type="MyCustomHttpHandler, App_Code">
|
||||
<property name="MessageText" value="This text is injected via Spring" />
|
||||
</object>
|
||||
|
||||
<!--
|
||||
used for configuring ~/DemoHandler.ashx custom handler
|
||||
note, that this is an abstract definition because 'type' is not specified
|
||||
-->
|
||||
<object name="DemoHandler.ashx">
|
||||
<property name="OutputText">
|
||||
<value>This text is injected via Spring</value>
|
||||
</property>
|
||||
</object>
|
||||
</objects>
|
||||
</spring>
|
||||
</configuration>
|
||||
@@ -17,6 +17,8 @@
|
||||
<p>The inevitable "Hello World!" example demonstrates DI for pages, usercontrols and webcontrols</p>
|
||||
<h3><a href="NestedContexts/Default.aspx">Nested Contexts</a></h3>
|
||||
<p>This sample shows, how contexts are nested in webapplications</p>
|
||||
<h3><a href="CustomHandlers/Default.aspx">Custom HTTP Handlers</a></h3>
|
||||
<p>This sample shows, how to configure your custom IHttpHandler and IHttpHandlerFactory implementations</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -120,12 +120,13 @@ namespace Spring.Web.Script.Services
|
||||
/// <summary>
|
||||
/// Create a handler instance for the given URL.
|
||||
/// </summary>
|
||||
/// <param name="appContext">the application context corresponding to the current request</param>
|
||||
/// <param name="context">The <see cref="HttpContext"/> instance for this request.</param>
|
||||
/// <param name="requestType">The HTTP data transfer method (GET, POST, ...)</param>
|
||||
/// <param name="url">The requested <see cref="HttpRequest.RawUrl"/>.</param>
|
||||
/// <param name="rawUrl">The requested <see cref="HttpRequest.RawUrl"/>.</param>
|
||||
/// <param name="physicalPath">The physical path of the requested resource.</param>
|
||||
/// <returns>A handler instance for the current request.</returns>
|
||||
protected override IHttpHandler CreateHandlerInstance( HttpContext context, string requestType, string url, string physicalPath )
|
||||
protected override IHttpHandler CreateHandlerInstance( IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath )
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
@@ -88,28 +88,28 @@ namespace Spring.Context.Support
|
||||
/// </summary>
|
||||
static WebSupportModule()
|
||||
{
|
||||
s_log = LogManager.GetLogger( typeof( WebSupportModule ) );
|
||||
s_log = LogManager.GetLogger(typeof(WebSupportModule));
|
||||
|
||||
// register additional resource handler
|
||||
ResourceHandlerRegistry.RegisterResourceHandler( WebUtils.DEFAULT_RESOURCE_PROTOCOL, typeof( WebResource ) );
|
||||
ResourceHandlerRegistry.RegisterResourceHandler(WebUtils.DEFAULT_RESOURCE_PROTOCOL, typeof(WebResource));
|
||||
// replace default IResource converter
|
||||
TypeConverterRegistry.RegisterConverter( typeof( IResource ),
|
||||
TypeConverterRegistry.RegisterConverter(typeof(IResource),
|
||||
new ResourceConverter(
|
||||
new ConfigurableResourceLoader( WebUtils.DEFAULT_RESOURCE_PROTOCOL ) ) );
|
||||
new ConfigurableResourceLoader(WebUtils.DEFAULT_RESOURCE_PROTOCOL)));
|
||||
// default to hybrid thread storage implementation
|
||||
LogicalThreadContext.SetStorage( new HybridContextStorage() );
|
||||
LogicalThreadContext.SetStorage(new HybridContextStorage());
|
||||
|
||||
s_log.Debug( "Set default resource protocol to 'web' and installed HttpContext-aware HybridContextStorage" );
|
||||
s_log.Debug("Set default resource protocol to 'web' and installed HttpContext-aware HybridContextStorage");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers this module for all events required by the Spring.Web framework
|
||||
/// </summary>
|
||||
public virtual void Init( HttpApplication app )
|
||||
public virtual void Init(HttpApplication app)
|
||||
{
|
||||
lock (typeof( WebSupportModule ))
|
||||
lock (typeof(WebSupportModule))
|
||||
{
|
||||
s_log.Debug( "Initializing Application instance" );
|
||||
s_log.Debug("Initializing Application instance");
|
||||
if (!s_isInitialized)
|
||||
{
|
||||
HttpModuleCollection modules = app.Modules;
|
||||
@@ -118,7 +118,7 @@ namespace Spring.Context.Support
|
||||
if (modules[moduleKey] is SessionStateModule)
|
||||
{
|
||||
#if !NET_1_1
|
||||
HookSessionEvent( (SessionStateModule)modules[moduleKey] );
|
||||
HookSessionEvent((SessionStateModule)modules[moduleKey]);
|
||||
#else
|
||||
HookSessionEvent11();
|
||||
#endif
|
||||
@@ -132,57 +132,92 @@ namespace Spring.Context.Support
|
||||
VirtualEnvironment.SetInitialized();
|
||||
}
|
||||
|
||||
app.PreRequestHandlerExecute += new EventHandler( OnPreRequestHandlerExecute );
|
||||
app.EndRequest += new EventHandler( VirtualEnvironment.RaiseEndRequest );
|
||||
app.PreRequestHandlerExecute += new EventHandler(OnConfigureHandler);
|
||||
app.EndRequest += new EventHandler(VirtualEnvironment.RaiseEndRequest);
|
||||
|
||||
// ensure context is instantiated
|
||||
IConfigurableApplicationContext appContext = WebApplicationContext.GetRootContext() as IConfigurableApplicationContext;
|
||||
// configure this app + it's module instances
|
||||
if (appContext == null)
|
||||
{
|
||||
throw new InvalidOperationException( "Implementations of IApplicationContext must also implement IConfigurableApplicationContext" );
|
||||
throw new InvalidOperationException("Implementations of IApplicationContext must also implement IConfigurableApplicationContext");
|
||||
}
|
||||
HttpApplicationConfigurer.Configure( appContext, app );
|
||||
HttpApplicationConfigurer.Configure(appContext, app);
|
||||
}
|
||||
|
||||
#region IHttpHandler configuration
|
||||
|
||||
///<summary>
|
||||
/// Configures the current IHttpHandler as specified by <see cref="Spring.Web.Support.PageHandlerFactory"/>.
|
||||
///</summary>
|
||||
private void OnPreRequestHandlerExecute( object sender, EventArgs e )
|
||||
private void OnConfigureHandler(object sender, EventArgs e)
|
||||
{
|
||||
HandlerConfigurationMetaData hCfg = (HandlerConfigurationMetaData)LogicalThreadContext.GetData( CURRENTHANDLER_OBJECTDEFINITION );
|
||||
HandlerConfigurationMetaData hCfg = (HandlerConfigurationMetaData)LogicalThreadContext.GetData(CURRENTHANDLER_OBJECTDEFINITION);
|
||||
if (hCfg != null)
|
||||
{
|
||||
HttpApplication app = (HttpApplication)sender;
|
||||
//app.Context.Handler =
|
||||
ConfigureHandler( app.Context.Handler, hCfg.ApplicationContext, hCfg.ObjectDefinitionName, hCfg.IsContainerManaged );
|
||||
// app.Context.Handler = // TODO: check, if this makes sense (EE)
|
||||
ConfigureHandlerNow(app.Context.Handler, hCfg.ApplicationContext, hCfg.ObjectDefinitionName, hCfg.IsContainerManaged);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the specified handler instance using the object definition <paramref name="name"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// TODO
|
||||
/// </remarks>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="handler"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="isContainerManaged"></param>
|
||||
/// <returns></returns>
|
||||
public static IHttpHandler ConfigureHandler(HttpContext context, IHttpHandler handler, IConfigurableApplicationContext applicationContext, string name, bool isContainerManaged)
|
||||
{
|
||||
if (context.Handler != null)
|
||||
{
|
||||
s_log.Debug(string.Format("previous handler is present - configuring handler now using application context '{0}' and name '{1}'", applicationContext, name));
|
||||
// this is a Server.Execute() or Server.Transfer() request -> configure immediately
|
||||
return ConfigureHandlerNow(handler, applicationContext, name, isContainerManaged);
|
||||
}
|
||||
else
|
||||
{
|
||||
// remember the resolved object definition name for applying it during PreRequestHandlerExecute
|
||||
s_log.Debug(string.Format("no previous handler is present - defer handler configuration using application context '{0}' and name '{1}'", applicationContext, name));
|
||||
SetCurrentHandlerConfiguration(applicationContext, name, isContainerManaged);
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
||||
///<summary>
|
||||
/// TODO
|
||||
///</summary>
|
||||
///<param name="applicationContext"></param>
|
||||
///<param name="name"></param>
|
||||
///<param name="isContainerManaged"></param>
|
||||
public static void SetCurrentHandlerConfiguration( IConfigurableApplicationContext applicationContext, string name, bool isContainerManaged )
|
||||
private static void SetCurrentHandlerConfiguration(IConfigurableApplicationContext applicationContext, string name, bool isContainerManaged)
|
||||
{
|
||||
LogicalThreadContext.SetData( CURRENTHANDLER_OBJECTDEFINITION, new HandlerConfigurationMetaData(applicationContext, name, isContainerManaged) );
|
||||
LogicalThreadContext.SetData(CURRENTHANDLER_OBJECTDEFINITION, new HandlerConfigurationMetaData(applicationContext, name, isContainerManaged));
|
||||
}
|
||||
|
||||
///<summary>
|
||||
/// TODO
|
||||
///</summary>
|
||||
///<param name="handler"></param>
|
||||
///<param name="applicationContext"></param>
|
||||
///<param name="name"></param>
|
||||
///<param name="isContainerManaged"></param>
|
||||
public static IHttpHandler ConfigureHandler( IHttpHandler handler, IConfigurableApplicationContext applicationContext, string name, bool isContainerManaged)
|
||||
private static IHttpHandler ConfigureHandlerNow(IHttpHandler handler, IConfigurableApplicationContext applicationContext, string name, bool isContainerManaged)
|
||||
{
|
||||
if (isContainerManaged)
|
||||
{
|
||||
handler = (IHttpHandler)applicationContext.ObjectFactory.ConfigureObject( handler, name );
|
||||
s_log.Debug(string.Format("configuring managed handler using application context '{0}' and name '{1}'", applicationContext, name));
|
||||
handler = (IHttpHandler)applicationContext.ObjectFactory.ConfigureObject(handler, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
s_log.Debug(string.Format("configuring unmanaged handler using application context '{0}' and name '{1}'", applicationContext, name));
|
||||
// at a minimum we'll apply ObjectPostProcessors
|
||||
handler = (IHttpHandler)applicationContext.ObjectFactory.ApplyObjectPostProcessorsBeforeInitialization(handler, name);
|
||||
handler = (IHttpHandler)applicationContext.ObjectFactory.ApplyObjectPostProcessorsAfterInitialization(handler, name);
|
||||
@@ -191,6 +226,8 @@ namespace Spring.Context.Support
|
||||
return handler;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Disposes this instance
|
||||
/// </summary>
|
||||
@@ -201,15 +238,15 @@ namespace Spring.Context.Support
|
||||
|
||||
#region Session Handling Stuff
|
||||
|
||||
private static void OnCacheItemRemoved( string key, object value, CacheItemRemovedReason reason )
|
||||
private static void OnCacheItemRemoved(string key, object value, CacheItemRemovedReason reason)
|
||||
{
|
||||
s_log.Debug( "end session " + key + " because of " + reason );
|
||||
s_log.Debug("end session " + key + " because of " + reason);
|
||||
|
||||
try
|
||||
{
|
||||
HttpSessionState ss = CreateSessionState( key, value );
|
||||
HttpSessionState ss = CreateSessionState(key, value);
|
||||
|
||||
VirtualEnvironment.RaiseEndSession( ss, reason );
|
||||
VirtualEnvironment.RaiseEndSession(ss, reason);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -217,51 +254,51 @@ namespace Spring.Context.Support
|
||||
// are we on a current request?
|
||||
if (HttpContext.Current != null)
|
||||
{
|
||||
s_log.Error( msg, ex );
|
||||
s_log.Error(msg, ex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is an async session timout - log as fatal since this is the thread's exit point!
|
||||
s_log.Fatal( msg, ex );
|
||||
s_log.Fatal(msg, ex);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (s_originalCallback != null)
|
||||
{
|
||||
s_originalCallback( key, value, reason );
|
||||
s_originalCallback(key, value, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !NET_1_1
|
||||
private static void HookSessionEvent( SessionStateModule sessionStateModule )
|
||||
private static void HookSessionEvent(SessionStateModule sessionStateModule)
|
||||
{
|
||||
// Hook only into InProcState - all others ignore SessionEnd anyway
|
||||
object store = ExpressionEvaluator.GetValue( sessionStateModule, "_store" );
|
||||
object store = ExpressionEvaluator.GetValue(sessionStateModule, "_store");
|
||||
if ((store != null) && store.GetType().Name == "InProcSessionStateStore")
|
||||
{
|
||||
s_log.Debug( "attaching to InProcSessionStateStore" );
|
||||
s_originalCallback = (CacheItemRemovedCallback)ExpressionEvaluator.GetValue( store, "_callback" );
|
||||
ExpressionEvaluator.SetValue( store, "_callback", new CacheItemRemovedCallback( OnCacheItemRemoved ) );
|
||||
s_log.Debug("attaching to InProcSessionStateStore");
|
||||
s_originalCallback = (CacheItemRemovedCallback)ExpressionEvaluator.GetValue(store, "_callback");
|
||||
ExpressionEvaluator.SetValue(store, "_callback", new CacheItemRemovedCallback(OnCacheItemRemoved));
|
||||
|
||||
CACHEKEYPREFIXLENGTH = (int)ExpressionEvaluator.GetValue( store, "CACHEKEYPREFIXLENGTH" );
|
||||
CACHEKEYPREFIXLENGTH = (int)ExpressionEvaluator.GetValue(store, "CACHEKEYPREFIXLENGTH");
|
||||
}
|
||||
}
|
||||
|
||||
private static HttpSessionState CreateSessionState( string key, object state )
|
||||
private static HttpSessionState CreateSessionState(string key, object state)
|
||||
{
|
||||
string id = key.Substring( CACHEKEYPREFIXLENGTH );
|
||||
string id = key.Substring(CACHEKEYPREFIXLENGTH);
|
||||
ISessionStateItemCollection sessionItems =
|
||||
(ISessionStateItemCollection)ExpressionEvaluator.GetValue( state, "_sessionItems" );
|
||||
(ISessionStateItemCollection)ExpressionEvaluator.GetValue(state, "_sessionItems");
|
||||
HttpStaticObjectsCollection staticObjects =
|
||||
(HttpStaticObjectsCollection)ExpressionEvaluator.GetValue( state, "_staticObjects" );
|
||||
int timeout = (int)ExpressionEvaluator.GetValue( state, "_timeout" );
|
||||
TypeRegistry.RegisterType( "SessionStateModule", typeof( SessionStateModule ) );
|
||||
(HttpStaticObjectsCollection)ExpressionEvaluator.GetValue(state, "_staticObjects");
|
||||
int timeout = (int)ExpressionEvaluator.GetValue(state, "_timeout");
|
||||
TypeRegistry.RegisterType("SessionStateModule", typeof(SessionStateModule));
|
||||
HttpCookieMode cookieMode =
|
||||
(HttpCookieMode)ExpressionEvaluator.GetValue( null, "SessionStateModule.s_configCookieless" );
|
||||
(HttpCookieMode)ExpressionEvaluator.GetValue(null, "SessionStateModule.s_configCookieless");
|
||||
SessionStateMode stateMode =
|
||||
(SessionStateMode)ExpressionEvaluator.GetValue( null, "SessionStateModule.s_configMode" );
|
||||
(SessionStateMode)ExpressionEvaluator.GetValue(null, "SessionStateModule.s_configMode");
|
||||
HttpSessionStateContainer container = new HttpSessionStateContainer(
|
||||
id
|
||||
, sessionItems
|
||||
@@ -274,7 +311,7 @@ namespace Spring.Context.Support
|
||||
);
|
||||
|
||||
return (HttpSessionState)Activator.CreateInstance(
|
||||
typeof( HttpSessionState )
|
||||
typeof(HttpSessionState)
|
||||
, BindingFlags.Instance | BindingFlags.NonPublic
|
||||
, null
|
||||
, new object[] { container }
|
||||
|
||||
@@ -125,6 +125,10 @@
|
||||
<Compile Include="Util\ISessionState.cs" />
|
||||
<Compile Include="Web\Support\DefaultResultFactory.cs" />
|
||||
<Compile Include="Web\Support\DefaultResultWebNavigator.cs" />
|
||||
<Compile Include="Web\Support\MappingHandlerFactory.cs" />
|
||||
<Compile Include="Web\Support\MappingHandlerFactoryConfigurer.cs" />
|
||||
<Compile Include="Web\Support\HandlerMap.cs" />
|
||||
<Compile Include="Web\Support\HandlerMapEntry.cs" />
|
||||
<Compile Include="Web\Support\IHierarchicalWebNavigator.cs" />
|
||||
<Compile Include="Web\Support\IResult.cs" />
|
||||
<Compile Include="Web\Support\IResultFactory.cs" />
|
||||
@@ -132,7 +136,9 @@
|
||||
<Compile Include="Web\Support\IWebNavigable.cs" />
|
||||
<Compile Include="Web\Support\IWebNavigator.cs" />
|
||||
<Compile Include="Web\Support\ResultFactoryRegistry.cs" />
|
||||
<Compile Include="Web\Support\DefaultHandlerFactory.cs" />
|
||||
<Compile Include="Web\Support\WebFormsResultWebNavigator.cs" />
|
||||
<Compile Include="Web\Support\WebNavigableWebNavigatorAdapter.cs" />
|
||||
<Compile Include="Web\UI\IValidationContainer.cs" />
|
||||
<Compile Include="Web\Support\MimeMediaType.cs" />
|
||||
<Compile Include="Web\Support\SharedStateResourceCache.cs">
|
||||
|
||||
@@ -124,9 +124,14 @@
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Util\ISessionState.cs" />
|
||||
<Compile Include="Web\Support\DefaultHandlerFactory.cs" />
|
||||
<Compile Include="Web\Support\DefaultResultFactory.cs" />
|
||||
<Compile Include="Web\Support\HandlerMap.cs" />
|
||||
<Compile Include="Web\Support\HandlerMapEntry.cs" />
|
||||
<Compile Include="Web\Support\IResult.cs" />
|
||||
<Compile Include="Web\Support\IResultFactory.cs" />
|
||||
<Compile Include="Web\Support\MappingHandlerFactory.cs" />
|
||||
<Compile Include="Web\Support\MappingHandlerFactoryConfigurer.cs" />
|
||||
<Compile Include="Web\Support\ResultFactoryRegistry.cs" />
|
||||
<Compile Include="Web\Support\WebFormsResultWebNavigator.cs" />
|
||||
<Compile Include="Web\Support\IHierarchicalWebNavigator.cs" />
|
||||
|
||||
@@ -24,6 +24,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using Common.Logging;
|
||||
using Spring.Collections;
|
||||
using Spring.Context;
|
||||
@@ -90,6 +91,32 @@ namespace Spring.Web.Support
|
||||
/// </summary>
|
||||
private readonly IDictionary _reusableHandlerCache = new CaseInsensitiveHashtable();
|
||||
|
||||
/// <summary>
|
||||
/// Holds an instance of the instrinsic System.Web.UI.SimpleHandlerFactory
|
||||
/// </summary>
|
||||
private static IHttpHandlerFactory s_simpleHandlerFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Get the global instance of System.Web.UI.SimpleHandlerFactory
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This factory is a plaform version agnostic way to instantiate
|
||||
/// arbitrary handlers without the need for additional reflection.
|
||||
/// </remarks>
|
||||
public static IHttpHandlerFactory SimpleHandlerFactory
|
||||
{
|
||||
get
|
||||
{
|
||||
// instantiate lazy to avoid security exceptions in restricted reflection environments
|
||||
if (s_simpleHandlerFactory == null)
|
||||
{
|
||||
Type simpleHandlerFactoryType = typeof(IHttpHandler).Assembly.GetType("System.Web.UI.SimpleHandlerFactory");
|
||||
s_simpleHandlerFactory = (IHttpHandlerFactory)Activator.CreateInstance(simpleHandlerFactoryType, true);
|
||||
}
|
||||
return s_simpleHandlerFactory;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the shared logger for all factories.
|
||||
/// </summary>
|
||||
@@ -158,7 +185,11 @@ namespace Spring.Web.Support
|
||||
handler = (IHttpHandler)_reusableHandlerCache[url];
|
||||
if (handler == null)
|
||||
{
|
||||
handler = CreateHandlerInstance( context, requestType, url, physicalPath );
|
||||
IConfigurableApplicationContext appContext = GetCheckedApplicationContext(url);
|
||||
|
||||
handler = CreateHandlerInstance( appContext, context, requestType, url, physicalPath );
|
||||
|
||||
ApplyDependencyInjectionInfrastructure(handler, appContext);
|
||||
|
||||
if (handler.IsReusable)
|
||||
{
|
||||
@@ -182,12 +213,13 @@ namespace Spring.Web.Support
|
||||
/// <summary>
|
||||
/// Create a handler instance for the given URL.
|
||||
/// </summary>
|
||||
/// <param name="appContext">the application context corresponding to the current request</param>
|
||||
/// <param name="context">The <see cref="HttpContext"/> instance for this request.</param>
|
||||
/// <param name="requestType">The HTTP data transfer method (GET, POST, ...)</param>
|
||||
/// <param name="url">The requested <see cref="HttpRequest.RawUrl"/>.</param>
|
||||
/// <param name="rawUrl">The requested <see cref="HttpRequest.RawUrl"/>.</param>
|
||||
/// <param name="physicalPath">The physical path of the requested resource.</param>
|
||||
/// <returns>A handler instance for processing the current request.</returns>
|
||||
protected abstract IHttpHandler CreateHandlerInstance( HttpContext context, string requestType, string url, string physicalPath );
|
||||
protected abstract IHttpHandler CreateHandlerInstance( IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath );
|
||||
|
||||
/// <summary>
|
||||
/// Get the application context instance corresponding to the given absolute url and checks
|
||||
@@ -292,5 +324,26 @@ namespace Spring.Web.Support
|
||||
|
||||
return (pageDefinition == null) ? (NamedObjectDefinition)null : new NamedObjectDefinition( objectDefinitionName, pageDefinition );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply dependency injection stuff on the handler.
|
||||
/// </summary>
|
||||
/// <param name="handler">the handler to be intercepted</param>
|
||||
/// <param name="applicationContext">the context responsible for configuring this handler</param>
|
||||
private static void ApplyDependencyInjectionInfrastructure(IHttpHandler handler, IApplicationContext applicationContext)
|
||||
{
|
||||
if (handler is Control)
|
||||
{
|
||||
ControlInterceptor.EnsureControlIntercepted(applicationContext, (Control)handler);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (handler is ISupportsWebDependencyInjection)
|
||||
&& (((ISupportsWebDependencyInjection)handler).DefaultApplicationContext == null) )
|
||||
{
|
||||
((ISupportsWebDependencyInjection)handler).DefaultApplicationContext = applicationContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
104
src/Spring/Spring.Web/Web/Support/DefaultHandlerFactory.cs
Normal file
104
src/Spring/Spring.Web/Web/Support/DefaultHandlerFactory.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright <20> 2002-2008 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region Imports
|
||||
|
||||
using System;
|
||||
using System.Web;
|
||||
using Spring.Context;
|
||||
using Spring.Context.Support;
|
||||
using Spring.Util;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Spring.Web.Support
|
||||
{
|
||||
/// <summary>
|
||||
/// SimpleHandlerFactory is used to wrap any arbitrary <see cref="IHttpHandlerFactory"/> to make it "Spring-aware".
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default, an instance of <see cref="System.Web.UI.SimpleHandlerFactory"/> is used as underlying factory.
|
||||
/// </remarks>
|
||||
/// <author>Erich Eichinger</author>
|
||||
public class DefaultHandlerFactory : AbstractHandlerFactory
|
||||
{
|
||||
private readonly IHttpHandlerFactory _innerFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance, using a <see cref="System.Web.UI.SimpleHandlerFactory"/> as underlying factory.
|
||||
/// </summary>
|
||||
public DefaultHandlerFactory()
|
||||
: this(SimpleHandlerFactory)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance, using an instance of <paramref name="innerFactoryType"/> as underlying factory.
|
||||
/// </summary>
|
||||
/// <param name="innerFactoryType">a type that implements <see cref="IHttpHandlerFactory"/></param>
|
||||
public DefaultHandlerFactory(Type innerFactoryType)
|
||||
: this((IHttpHandlerFactory)Activator.CreateInstance(innerFactoryType, true))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance, using <paramref name="innerFactory"/> as underlying factory.
|
||||
/// </summary>
|
||||
/// <param name="innerFactory">the factory to be wrapped.</param>
|
||||
public DefaultHandlerFactory(IHttpHandlerFactory innerFactory)
|
||||
{
|
||||
AssertUtils.ArgumentNotNull(innerFactory, "innerFactory");
|
||||
_innerFactory = innerFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a handler instance for the given URL.
|
||||
/// </summary>
|
||||
/// <param name="appContext">the application context corresponding to the current request</param>
|
||||
/// <param name="context">The <see cref="HttpContext"/> instance for this request.</param>
|
||||
/// <param name="requestType">The HTTP data transfer method (GET, POST, ...)</param>
|
||||
/// <param name="rawUrl">The requested <see cref="HttpRequest.RawUrl"/>.</param>
|
||||
/// <param name="physicalPath">The physical path of the requested resource.</param>
|
||||
/// <returns>A handler instance for processing the current request.</returns>
|
||||
protected override IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath)
|
||||
{
|
||||
IHttpHandler handler = _innerFactory.GetHandler(context, requestType, rawUrl, physicalPath);
|
||||
|
||||
// find a matching object definition
|
||||
string appRelativeVirtualPath = WebUtils.GetAppRelativePath(rawUrl);
|
||||
NamedObjectDefinition nod = FindWebObjectDefinition(appRelativeVirtualPath, appContext.ObjectFactory);
|
||||
string objectDefinitionName = (nod != null) ? nod.Name : rawUrl;
|
||||
|
||||
handler = WebSupportModule.ConfigureHandler(context, handler, appContext, objectDefinitionName, (nod != null));
|
||||
return handler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables a factory to release an existing
|
||||
/// <see cref="System.Web.IHttpHandler"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="handler">
|
||||
/// The <see cref="System.Web.IHttpHandler"/> object to release.
|
||||
/// </param>
|
||||
public override void ReleaseHandler(IHttpHandler handler)
|
||||
{
|
||||
_innerFactory.ReleaseHandler(handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
238
src/Spring/Spring.Web/Web/Support/HandlerMap.cs
Normal file
238
src/Spring/Spring.Web/Web/Support/HandlerMap.cs
Normal file
@@ -0,0 +1,238 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright <20> 2002-2008 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region Imports
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using Common.Logging;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Spring.Web.Support
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds a list of url <see cref="Regex"/> expressions and their corresponding names of responsible <see cref="IHttpHandlerFactory"/>
|
||||
/// or <see cref="IHttpHandler"/> objects managed by the container.
|
||||
/// </summary>
|
||||
/// <author>Erich Eichinger</author>
|
||||
public class HandlerMap : IDictionary
|
||||
{
|
||||
private readonly ILog Log = LogManager.GetLogger(typeof(HandlerMap));
|
||||
|
||||
private ArrayList _internalTable = new ArrayList();
|
||||
|
||||
/// <summary>
|
||||
/// Maps the specified url pattern expression to an object name denoting a <see cref="IHttpHandlerFactory"/> or <see cref="IHttpHandler"/> object.
|
||||
/// </summary>
|
||||
/// <param name="urlPattern">the string pattern (see conform to <see cref="Regex"/> syntax)</param>
|
||||
/// <param name="handlerObjectName">an object name denoting the spring-managed handler definition</param>
|
||||
public void Add(string urlPattern, string handlerObjectName)
|
||||
{
|
||||
this._internalTable.Add( new HandlerMapEntry(urlPattern, handlerObjectName) );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps the specified url pattern expression to an object name denoting a <see cref="IHttpHandlerFactory"/> or <see cref="IHttpHandler"/> object.
|
||||
/// </summary>
|
||||
/// <param name="urlPattern">the url pattern</param>
|
||||
/// <param name="handlerObjectName">an object name denoting the spring-managed handler definition</param>
|
||||
public void Add(Regex urlPattern, string handlerObjectName)
|
||||
{
|
||||
this._internalTable.Add( new HandlerMapEntry(urlPattern, handlerObjectName) );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps the <paramref name="virtualPath"/> to a handler object name by matching against all registered patterns.
|
||||
/// </summary>
|
||||
/// <param name="virtualPath">the virtual path</param>
|
||||
/// <returns>the object name</returns>
|
||||
public HandlerMapEntry MapPath( string virtualPath )
|
||||
{
|
||||
if(Log.IsDebugEnabled) Log.Debug( string.Format( "looking up mapping for url '{0}'", virtualPath ) );
|
||||
for(int i=0;i<this._internalTable.Count;i++)
|
||||
{
|
||||
HandlerMapEntry handlerMapEntry = (HandlerMapEntry)this._internalTable[i];
|
||||
if ( handlerMapEntry.UrlPattern.IsMatch( virtualPath ) )
|
||||
{
|
||||
if (Log.IsDebugEnabled) Log.Debug(string.Format("found mapping '{0}' for url '{1}'", handlerMapEntry, virtualPath));
|
||||
return handlerMapEntry;
|
||||
}
|
||||
}
|
||||
|
||||
if (Log.IsDebugEnabled) Log.Debug(string.Format("no mapping found for url '{0}'", virtualPath));
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a new mapping
|
||||
/// </summary>
|
||||
/// <param name="key">an url pattern string</param>
|
||||
/// <param name="value">a handler object name string</param>
|
||||
void IDictionary.Add(object key, object value)
|
||||
{
|
||||
this.Add((string) key, (string) value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add or replace a mapping
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Getter will throw a <see cref="NotSupportedException"/>!
|
||||
/// </remarks>
|
||||
/// <param name="key">an url pattern string</param>
|
||||
object IDictionary.this[object key]
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
set
|
||||
{
|
||||
this.Add( (string)key,(string)value );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear the mapping table.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
this._internalTable.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Always returns false.
|
||||
/// </summary>
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
// return this._internalTable.IsReadOnly;
|
||||
}
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Gets a value indicating whether the <see cref="T:System.Collections.IDictionary"></see> object has a fixed size.
|
||||
///</summary>
|
||||
///
|
||||
///<returns>
|
||||
///true if the <see cref="T:System.Collections.IDictionary"></see> object has a fixed size; otherwise, false.
|
||||
///</returns>
|
||||
///<filterpriority>2</filterpriority>
|
||||
public bool IsFixedSize
|
||||
{
|
||||
get { return false; /*return this._internalTable.IsFixedSize;*/ }
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Copies all <see cref="HandlerMapEntry"/> entries to the specified array.
|
||||
///</summary>
|
||||
public void CopyTo(Array array, int index)
|
||||
{
|
||||
this._internalTable.CopyTo(array, index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of registered mappings.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get { return this._internalTable.Count; }
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Gets an object that can be used to synchronize access.
|
||||
///</summary>
|
||||
public object SyncRoot
|
||||
{
|
||||
get { return this._internalTable.SyncRoot; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Always returns false.
|
||||
/// </summary>
|
||||
public bool IsSynchronized
|
||||
{
|
||||
get { return false; /*return this._internalTable.IsSynchronized;*/ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an enumerator for iterating over the list of registered mappings.
|
||||
/// </summary>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable) this._internalTable).GetEnumerator();
|
||||
}
|
||||
|
||||
#region Unsupported methods
|
||||
|
||||
/// <summary>
|
||||
/// Not supported by this implementation.
|
||||
/// </summary>
|
||||
bool IDictionary.Contains(object key)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not supported by this implementation.
|
||||
/// </summary>
|
||||
IDictionaryEnumerator IDictionary.GetEnumerator()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not supported by this implementation.
|
||||
/// </summary>
|
||||
void IDictionary.Remove(object key)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not supported by this implementation.
|
||||
/// </summary>
|
||||
ICollection IDictionary.Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not supported by this implementation.
|
||||
/// </summary>
|
||||
ICollection IDictionary.Values
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
92
src/Spring/Spring.Web/Web/Support/HandlerMapEntry.cs
Normal file
92
src/Spring/Spring.Web/Web/Support/HandlerMapEntry.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright <20> 2002-2008 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region Imports
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
using Spring.Util;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Spring.Web.Support
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds pairs of (url pattern, handler object name).
|
||||
/// </summary>
|
||||
/// <seealso cref="HandlerMap"/>
|
||||
/// <seealso cref="MappingHandlerFactory"/>
|
||||
/// <seealso cref="MappingHandlerFactoryConfigurer"/>
|
||||
/// <author>Erich Eichinger</author>
|
||||
public class HandlerMapEntry
|
||||
{
|
||||
private Regex _urlPattern;
|
||||
private string _handlerObjectName;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance.
|
||||
/// </summary>
|
||||
/// <param name="urlPattern"></param>
|
||||
/// <param name="handlerObjectName"></param>
|
||||
public HandlerMapEntry(string urlPattern, string handlerObjectName)
|
||||
{
|
||||
AssertUtils.ArgumentNotNull(urlPattern, "urlPattern");
|
||||
AssertUtils.ArgumentNotNull(handlerObjectName, "handlerObjectName");
|
||||
this._urlPattern = new Regex(urlPattern, RegexOptions.Compiled|RegexOptions.ECMAScript|RegexOptions.CultureInvariant|RegexOptions.IgnoreCase);
|
||||
this._handlerObjectName = handlerObjectName;
|
||||
}
|
||||
|
||||
///<summary>
|
||||
/// Create a new instance
|
||||
///</summary>
|
||||
///<param name="urlPattern"></param>
|
||||
///<param name="handlerObjectName"></param>
|
||||
public HandlerMapEntry(Regex urlPattern, string handlerObjectName)
|
||||
{
|
||||
AssertUtils.ArgumentNotNull(urlPattern, "urlPattern");
|
||||
AssertUtils.ArgumentNotNull(handlerObjectName, "handlerObjectName");
|
||||
this._urlPattern = urlPattern;
|
||||
this._handlerObjectName = handlerObjectName;
|
||||
}
|
||||
|
||||
///<summary>
|
||||
/// Get the url pattern
|
||||
///</summary>
|
||||
public Regex UrlPattern
|
||||
{
|
||||
get { return this._urlPattern; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the handler object name
|
||||
/// </summary>
|
||||
public string HandlerObjectName
|
||||
{
|
||||
get { return this._handlerObjectName; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a string representation of this entry.
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("HandlerMapEntry['{0}','{1}']", _urlPattern, _handlerObjectName);
|
||||
}
|
||||
}
|
||||
}
|
||||
175
src/Spring/Spring.Web/Web/Support/MappingHandlerFactory.cs
Normal file
175
src/Spring/Spring.Web/Web/Support/MappingHandlerFactory.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright <20> 2002-2008 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region Imports
|
||||
|
||||
using System.Collections;
|
||||
using System.Net;
|
||||
using System.Web;
|
||||
using Spring.Context;
|
||||
using Spring.Context.Support;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Spring.Web.Support
|
||||
{
|
||||
/// <summary>
|
||||
/// MappingHandleryFactory allows for full Spring-managed <httpHandlers> configuration.
|
||||
/// It uses regular expressions for url matching.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <example>
|
||||
/// The example below shows, how to map all url requests to spring and let
|
||||
/// <see cref="MappingHandlerFactory"/> resolve urls to container-managed <see cref="IHttpHandlerFactory"/> or <see cref="IHttpHandler"/> objects.
|
||||
/// <code>
|
||||
/// // web.config
|
||||
///
|
||||
/// <httpHandlers>
|
||||
/// <!-- map all requests to spring (just for demo - don't do this at home!) -->
|
||||
/// <add verb="*" path="*.*" type="Spring.Web.Support.MappingHandlerFactory, Spring.Web" />
|
||||
/// </httpHandlers>
|
||||
///
|
||||
/// // spring-objects.config
|
||||
///
|
||||
/// <object type="Spring.Web.Support.MappingHandlerFactoryConfigurer, Spring.Web">
|
||||
/// <property name="HandlerMap">
|
||||
/// <dictionary>
|
||||
/// <entry key="\.ashx$" value="standardHandlerFactory" />
|
||||
/// <!-- map any request ending with *.whatever to standardHandlerFactory -->
|
||||
/// <entry key="\.whatever$" value="specialHandlerFactory" />
|
||||
/// </dictionary>
|
||||
/// </property>
|
||||
/// </object>
|
||||
///
|
||||
/// <object name="standardHandlerFactory" type="Spring.Web.Support.DefaultHandlerFactory, Spring.Web" />
|
||||
///
|
||||
/// <object name="specialHandlerFactory" type="MySpecialHandlerFactoryImpl" />
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
/// <seealso cref="IHttpHandlerFactory"/>
|
||||
/// <seealso cref="IHttpHandler"/>
|
||||
/// <seealso cref="HandlerMap"/>
|
||||
/// <seealso cref="MappingHandlerFactoryConfigurer"/>
|
||||
/// <author>Erich Eichinger</author>
|
||||
public class MappingHandlerFactory : AbstractHandlerFactory
|
||||
{
|
||||
private static readonly HandlerMap s_handlerMap = new HandlerMap();
|
||||
|
||||
/// <summary>
|
||||
/// Holds the global list of mappings from url patterns to handler names.
|
||||
/// </summary>
|
||||
public static HandlerMap HandlerMap
|
||||
{
|
||||
get { return s_handlerMap; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the cache of handler/factory pairs handed out by this factory. This is required
|
||||
/// for proper handling of <see cref="IHttpHandlerFactory.ReleaseHandler"/>.
|
||||
/// </summary>
|
||||
private readonly Hashtable _handlerWithFactoryTable = new Hashtable();
|
||||
|
||||
/// <summary>
|
||||
/// Create a handler instance for the given URL. Will try to find a match of <paramref name="rawUrl"/> onto patterns in <see cref="HandlerMap"/>.
|
||||
/// If a match is found, delegates the call to the matching <see cref="IHttpHandlerFactory.GetHandler"/> method.
|
||||
/// </summary>
|
||||
/// <param name="appContext">the application context corresponding to the current request</param>
|
||||
/// <param name="context">The <see cref="HttpContext"/> instance for this request.</param>
|
||||
/// <param name="requestType">The HTTP data transfer method (GET, POST, ...)</param>
|
||||
/// <param name="rawUrl">The requested <see cref="HttpRequest.RawUrl"/>.</param>
|
||||
/// <param name="physicalPath">The physical path of the requested resource.</param>
|
||||
/// <returns>A handler instance for processing the current request.</returns>
|
||||
protected override IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath)
|
||||
{
|
||||
return MapHandlerInstance(appContext, context, requestType, rawUrl, physicalPath, s_handlerMap, _handlerWithFactoryTable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains a handler by mapping <paramref name="rawUrl"/> to the list of patterns in <paramref name="handlerMappings"/>.
|
||||
/// </summary>
|
||||
/// <param name="appContext">the application context corresponding to the current request</param>
|
||||
/// <param name="context">The <see cref="HttpContext"/> instance for this request.</param>
|
||||
/// <param name="requestType">The HTTP data transfer method (GET, POST, ...)</param>
|
||||
/// <param name="rawUrl">The requested <see cref="HttpRequest.RawUrl"/>.</param>
|
||||
/// <param name="physicalPath">The physical path of the requested resource.</param>
|
||||
/// <param name="handlerMappings"></param>
|
||||
/// <param name="handlerWithFactoryTable"></param>
|
||||
/// <returns>A handler instance for processing the current request.</returns>
|
||||
protected IHttpHandler MapHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath, HandlerMap handlerMappings, IDictionary handlerWithFactoryTable)
|
||||
{
|
||||
// resolve handler instance by mapping the url to the list of patterns
|
||||
HandlerMapEntry handlerMapEntry = handlerMappings.MapPath(rawUrl);
|
||||
if (handlerMapEntry == null)
|
||||
{
|
||||
throw new HttpException(404, HttpStatusCode.NotFound.ToString());
|
||||
}
|
||||
object handlerObject = appContext.GetObject(handlerMapEntry.HandlerObjectName);
|
||||
|
||||
if (handlerObject is IHttpHandler)
|
||||
{
|
||||
return (IHttpHandler) handlerObject;
|
||||
}
|
||||
else if (handlerObject is IHttpHandlerFactory)
|
||||
{
|
||||
// keep a reference to the issuing factory for later ReleaseHandler call
|
||||
IHttpHandlerFactory factory = (IHttpHandlerFactory) handlerObject;
|
||||
IHttpHandler handler = factory.GetHandler(context, requestType, rawUrl, physicalPath);
|
||||
lock(handlerWithFactoryTable.SyncRoot)
|
||||
{
|
||||
handlerWithFactoryTable.Add(handler, factory);
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
|
||||
throw new HttpException((int)HttpStatusCode.NotFound, HttpStatusCode.NotFound.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables a factory to release an existing
|
||||
/// <see cref="System.Web.IHttpHandler"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="handler">
|
||||
/// The <see cref="System.Web.IHttpHandler"/> object to release.
|
||||
/// </param>
|
||||
public override void ReleaseHandler(IHttpHandler handler)
|
||||
{
|
||||
ReleaseHandler(handler, this._handlerWithFactoryTable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the handler from the handler/factory dictionary and releases the handler.
|
||||
/// </summary>
|
||||
/// <param name="handler">the handler to be released</param>
|
||||
/// <param name="_handlerWithFactoryTable">a dictionary containing (<see cref="IHttpHandler"/>, <see cref="IHttpHandlerFactory"/>) entries.</param>
|
||||
protected void ReleaseHandler( IHttpHandler handler, IDictionary _handlerWithFactoryTable )
|
||||
{
|
||||
lock (_handlerWithFactoryTable.SyncRoot)
|
||||
{
|
||||
IHttpHandlerFactory factory = _handlerWithFactoryTable[handler] as IHttpHandlerFactory;
|
||||
if (factory != null)
|
||||
{
|
||||
_handlerWithFactoryTable.Remove(handler);
|
||||
factory.ReleaseHandler(handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright <20> 2002-2008 the original author or authors.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region Imports
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Spring.Web.Support
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures <see cref="MappingHandlerFactory"/>.
|
||||
/// </summary>
|
||||
/// <author>Erich Eichinger</author>
|
||||
public class MappingHandlerFactoryConfigurer
|
||||
// : Spring.Objects.Factory.Config.IObjectPostProcessor // just a trick to have
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains mappings of url patterns to handler objects.
|
||||
/// </summary>
|
||||
public HandlerMap HandlerMap
|
||||
{
|
||||
get
|
||||
{
|
||||
return MappingHandlerFactory.HandlerMap;
|
||||
}
|
||||
// set
|
||||
// {
|
||||
// AssertUtils.ArgumentNotNull(value, "HandlerMap");
|
||||
// foreach(HandlerMapEntry mapEntry in value)
|
||||
// {
|
||||
// GenericHandlerFactory.HandlerMap[mapEntry.UrlPattern] = mapEntry;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
#region IObjectPostProcessor implementation
|
||||
|
||||
// object IObjectPostProcessor.PostProcessBeforeInitialization(object instance, string name)
|
||||
// {
|
||||
// return instance;
|
||||
// }
|
||||
//
|
||||
// object IObjectPostProcessor.PostProcessAfterInitialization(object instance, string objectName)
|
||||
// {
|
||||
// return instance;
|
||||
// }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -82,22 +82,17 @@ namespace Spring.Web.Support
|
||||
/// <summary>
|
||||
/// Create a handler instance for the given URL.
|
||||
/// </summary>
|
||||
/// <param name="appContext">the application context corresponding to the current request</param>
|
||||
/// <param name="context">The <see cref="HttpContext"/> instance for this request.</param>
|
||||
/// <param name="requestType">The HTTP data transfer method (GET, POST, ...)</param>
|
||||
/// <param name="url">The requested <see cref="HttpRequest.RawUrl"/>.</param>
|
||||
/// <param name="rawUrl">The requested <see cref="HttpRequest.RawUrl"/>.</param>
|
||||
/// <param name="physicalPath">The physical path of the requested resource.</param>
|
||||
/// <returns>A handler instance for the current request.</returns>
|
||||
protected override IHttpHandler CreateHandlerInstance(HttpContext context, string requestType, string url, string physicalPath)
|
||||
protected override IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string rawUrl, string physicalPath)
|
||||
{
|
||||
IHttpHandler handler;
|
||||
IConfigurableApplicationContext appContext = GetCheckedApplicationContext(url);
|
||||
|
||||
if (appContext == null)
|
||||
{
|
||||
throw new InvalidOperationException("PageHandlerFactory requires an IConfigurableApplicationContext");
|
||||
}
|
||||
|
||||
string appRelativeVirtualPath = WebUtils.GetAppRelativePath(url);
|
||||
string appRelativeVirtualPath = WebUtils.GetAppRelativePath(rawUrl);
|
||||
NamedObjectDefinition namedPageDefinition = FindWebObjectDefinition(appRelativeVirtualPath, appContext.ObjectFactory);
|
||||
|
||||
if (namedPageDefinition != null)
|
||||
@@ -113,50 +108,17 @@ namespace Spring.Web.Support
|
||||
// execution pipeline "entry-point" - create page instance only
|
||||
// and defer configuration to PreRequestHandlerExecute step
|
||||
handler = (IHttpHandler)appContext.CreateObject(namedPageDefinition.Name, typeof(IHttpHandler), null);
|
||||
WebSupportModule.ConfigureHandler(context, handler, appContext, namedPageDefinition.Name, true);
|
||||
}
|
||||
WebSupportModule.SetCurrentHandlerConfiguration(appContext, namedPageDefinition.Name, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
handler = WebObjectUtils.CreateHandler(context, url);
|
||||
|
||||
// is this a nested call (HttpServerUtility.Transfer() or HttpServerUtility.Execute())?
|
||||
if (context.Handler != null)
|
||||
{
|
||||
// apply ObjectPostProcessors now
|
||||
handler = WebSupportModule.ConfigureHandler(handler, appContext, url, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// execution pipeline "entry-point" - create page instance only
|
||||
// and defer configuration to PreRequestHandlerExecute step
|
||||
WebSupportModule.SetCurrentHandlerConfiguration(appContext, url, false);
|
||||
}
|
||||
handler = WebObjectUtils.CreateHandler(context, rawUrl);
|
||||
// let WebSupportModule handle configuration
|
||||
handler = WebSupportModule.ConfigureHandler(context, handler, appContext, rawUrl, false);
|
||||
}
|
||||
|
||||
ApplyDependencyInjectionInfrastructure(handler, appContext);
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply dependency injection stuff on the handler.
|
||||
/// </summary>
|
||||
/// <param name="handler">the handler to be intercepted</param>
|
||||
/// <param name="applicationContext">the context responsible for configuring this handler</param>
|
||||
private static void ApplyDependencyInjectionInfrastructure(IHttpHandler handler, IApplicationContext applicationContext)
|
||||
{
|
||||
if (handler is Control)
|
||||
{
|
||||
ControlInterceptor.EnsureControlIntercepted(applicationContext, (Control)handler);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (handler is ISupportsWebDependencyInjection)
|
||||
{
|
||||
((ISupportsWebDependencyInjection)handler).DefaultApplicationContext = applicationContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace Spring.Web.Support
|
||||
|
||||
#region AbstractHandlerFactory implementations
|
||||
|
||||
protected override IHttpHandler CreateHandlerInstance( HttpContext context, string requestType, string url, string physicalPath )
|
||||
protected override IHttpHandler CreateHandlerInstance( IConfigurableApplicationContext appContext, HttpContext context, string requestType, string url, string physicalPath )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -105,12 +105,12 @@ namespace Spring.Web.Support
|
||||
return base.GetCheckedApplicationContext(virtualPath);
|
||||
}
|
||||
|
||||
protected override IHttpHandler CreateHandlerInstance(HttpContext context, string requestType, string url, string physicalPath )
|
||||
protected override IHttpHandler CreateHandlerInstance(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string url, string physicalPath )
|
||||
{
|
||||
return CreateHandlerInstanceStub(context, requestType, url, physicalPath);
|
||||
return CreateHandlerInstanceStub(appContext, context, requestType, url, physicalPath);
|
||||
}
|
||||
|
||||
public virtual IHttpHandler CreateHandlerInstanceStub(HttpContext context, string requestType, string url, string physicalPath)
|
||||
public virtual IHttpHandler CreateHandlerInstanceStub(IConfigurableApplicationContext appContext, HttpContext context, string requestType, string url, string physicalPath)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -178,7 +178,7 @@ namespace Spring.Web.Support
|
||||
using(Record(mocks))
|
||||
{
|
||||
Expect.Call(reusableHandler.IsReusable).Return(true);
|
||||
Expect.Call(f.CreateHandlerInstanceStub(null, null, "reusable", null)).Return(reusableHandler);
|
||||
Expect.Call(f.CreateHandlerInstanceStub(null, null, null, "reusable", null)).Return(reusableHandler);
|
||||
}
|
||||
using (Playback(mocks))
|
||||
{
|
||||
@@ -201,8 +201,8 @@ namespace Spring.Web.Support
|
||||
// - CreateHandlerInstance() is called for each request
|
||||
using(Record(mocks))
|
||||
{
|
||||
Expect.Call(f.CreateHandlerInstanceStub(null, null, "notreusable", null)).Return(nonReusableHandler);
|
||||
Expect.Call(f.CreateHandlerInstanceStub(null, null, "notreusable", null)).Return(nonReusableHandler2);
|
||||
Expect.Call(f.CreateHandlerInstanceStub(null, null, null, "notreusable", null)).Return(nonReusableHandler);
|
||||
Expect.Call(f.CreateHandlerInstanceStub(null, null, null, "notreusable", null)).Return(nonReusableHandler2);
|
||||
}
|
||||
using (Playback(mocks))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user