From 6622f0ed4dbfca58ead7825ce3add4317d42db4d Mon Sep 17 00:00:00 2001 From: eeichinger Date: Fri, 11 Jul 2008 17:08:01 +0000 Subject: [PATCH] preparational changes for adding configurable control and response caching (SPRNET-972) --- src/Spring/Spring.Web/Util/ControlAccessor.cs | 9 ++++- .../Web/Support/ControlInterceptor.cs | 32 ++++++++++++++++-- .../InterceptControlCollectionStrategy.cs | 4 +-- ...ortsWebDependencyInjectionMethodBuilder.cs | 17 +++++++++- ...upportsWebDependencyInjectionOwnerProxy.cs | 9 +++-- .../Support/WebDependencyInjectionUtils.cs | 25 +++++++++----- .../Spring.Web/Web/UI/Controls/Panel.cs | 4 +-- src/Spring/Spring.Web/Web/UI/MasterPage.cs | 12 +++---- src/Spring/Spring.Web/Web/UI/Page.cs | 12 +++---- src/Spring/Spring.Web/Web/UI/UserControl.cs | 10 +++--- .../Util/ControlInterceptionTests.cs | 33 ++++++++++++++++++- 11 files changed, 128 insertions(+), 39 deletions(-) diff --git a/src/Spring/Spring.Web/Util/ControlAccessor.cs b/src/Spring/Spring.Web/Util/ControlAccessor.cs index 9e710bbf..de6b5534 100644 --- a/src/Spring/Spring.Web/Util/ControlAccessor.cs +++ b/src/Spring/Spring.Web/Util/ControlAccessor.cs @@ -187,6 +187,13 @@ namespace Spring.Util } } + private static readonly SafeField ControlsArrayField = new SafeField(typeof(ControlCollection).GetField("_controls", BindingFlags.Instance|BindingFlags.NonPublic)); + public void SetControlAt(Control control, int index) + { + Control[] controls = (Control[]) ControlsArrayField.GetValue(this.Controls); + controls[index] = control; + } + #if NET_2_0 private delegate ControlCollection GetControlsDelegate(Control target); private delegate void SetControlsDelegate(Control target, ControlCollection controls); @@ -297,4 +304,4 @@ namespace Spring.Util } #endif } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Web/Web/Support/ControlInterceptor.cs b/src/Spring/Spring.Web/Web/Support/ControlInterceptor.cs index 2d738bd1..43ad6cf9 100644 --- a/src/Spring/Spring.Web/Web/Support/ControlInterceptor.cs +++ b/src/Spring/Spring.Web/Web/Support/ControlInterceptor.cs @@ -18,8 +18,10 @@ #region Imports +using System; using System.Collections; using System.Web.UI; +using Common.Logging; using Spring.Context; using Spring.Util; @@ -33,6 +35,17 @@ namespace Spring.Web.Support /// Erich Eichinger internal sealed class ControlInterceptor { + private class NoOpInterceptionStrategy : IInterceptionStrategy + { + private ILog Log = LogManager.GetLogger(typeof(NoOpInterceptionStrategy)); + + public bool Intercept(IApplicationContext defaultApplicationContext, ControlAccessor ctlAccessor, + ControlCollectionAccessor ctlColAccessor) + { + return true; + } + } + /// /// Holds all available interception strategies /// @@ -41,7 +54,12 @@ namespace Spring.Web.Support new InterceptControlCollectionStrategy() , new InterceptControlCollectionOwnerStrategy() }; - + + /// + /// The last resort interception strategy... + /// + private static readonly IInterceptionStrategy s_noopInterceptionStrategy = new NoOpInterceptionStrategy(); + /// /// Holds a control.GetType()->IInterceptionStrategy table. /// @@ -102,12 +120,20 @@ namespace Spring.Web.Support else { // probe for a strategy + bool bOk = false; for(int i=0;i /// Holds a reference to the static(!) callback-method to be used during generation of intercepted ControlCollection-Types /// - private delegate void InjectDependenciesCallbackHandler(IApplicationContext defaultApplicationContext, Control control); + private delegate Control InjectDependenciesCallbackHandler(IApplicationContext defaultApplicationContext, Control control); /// /// The list of methods to be intercepted for a ControlCollection @@ -216,4 +216,4 @@ namespace Spring.Web.Support return interceptedCollectionType; } } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionMethodBuilder.cs b/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionMethodBuilder.cs index 16a9ff4f..6ed9a1a1 100644 --- a/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionMethodBuilder.cs +++ b/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionMethodBuilder.cs @@ -18,6 +18,7 @@ #region Imports +using System; using System.Reflection; using System.Reflection.Emit; using Spring.Proxy; @@ -73,10 +74,19 @@ namespace Spring.Web.Support ParameterInfo[] callbackParams = _callbackMethod.GetParameters(); ParameterInfo[] paramArray = method.GetParameters(); + Type returnType = _callbackMethod.ReturnType; + int replaceArgumentIndex = -1; + for (int j = 1; j < callbackParams.Length; j++) { for (int i = 0; i < paramArray.Length; i++) { + // remember the parameter to assign the value returned from the callback to + if (paramArray[i].ParameterType == returnType) + { + replaceArgumentIndex = i; + } + if (paramArray[i].ParameterType == callbackParams[j].ParameterType) { il.Emit(OpCodes.Ldarg_S, i + 1); @@ -87,7 +97,12 @@ namespace Spring.Web.Support // invoke static(!) callback il.EmitCall(OpCodes.Call, _callbackMethod, null); + // if callback has a result, store the result back into the first matching argument + if (replaceArgumentIndex > -1) + { + il.Emit(OpCodes.Starg_S, (byte)replaceArgumentIndex+1); + } return; } } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionOwnerProxy.cs b/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionOwnerProxy.cs index f3ea2bf3..661162bf 100644 --- a/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionOwnerProxy.cs +++ b/src/Spring/Spring.Web/Web/Support/SupportsWebDependencyInjectionOwnerProxy.cs @@ -63,8 +63,11 @@ namespace Spring.Web.Support protected override void AddedControl(Control control, int index) { // do DI - WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, control); - + Control configuredControl = WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, control); + if (configuredControl != control) + { + _targetControl.SetControlAt( configuredControl, index ); + } _targetControl.AddedControl(control, index); } @@ -77,4 +80,4 @@ namespace Spring.Web.Support _targetControl.RemovedControl(control); } } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Web/Web/Support/WebDependencyInjectionUtils.cs b/src/Spring/Spring.Web/Web/Support/WebDependencyInjectionUtils.cs index cea2a1cb..1b86b6c2 100644 --- a/src/Spring/Spring.Web/Web/Support/WebDependencyInjectionUtils.cs +++ b/src/Spring/Spring.Web/Web/Support/WebDependencyInjectionUtils.cs @@ -36,22 +36,23 @@ namespace Spring.Web.Support /// /// ApplicationContext to be used /// Control to inject dependencies into. - public static void InjectDependenciesRecursive(IApplicationContext applicationContext, Control control) + public static Control InjectDependenciesRecursive(IApplicationContext applicationContext, Control control) { if (applicationContext != null) { - InjectDependenciesRecursiveInternal(applicationContext, control); + control = InjectDependenciesRecursiveInternal(applicationContext, control); } + return control; } - private static void InjectDependenciesRecursiveInternal(IApplicationContext appContext, Control control) + private static Control InjectDependenciesRecursiveInternal(IApplicationContext appContext, Control control) { - if (control is LiteralControl) return; // nothing to do + if (control is LiteralControl) return control; // nothing to do ISupportsWebDependencyInjection diControl = control as ISupportsWebDependencyInjection; if (diControl != null && diControl.DefaultApplicationContext != null) { - return; // nothing to do anymore - control cares for its children + return control; // nothing to do anymore - control cares for itself and its children } // "intercept" Control to make it DI-aware @@ -72,7 +73,7 @@ namespace Spring.Web.Support } // inject dependencies using control's context - appContextToUse.ConfigureObject(control, control.GetType().FullName); + control = (Control)appContextToUse.ConfigureObject(control, control.GetType().FullName); // and now go for control's children if (control.HasControls()) @@ -82,12 +83,18 @@ namespace Spring.Web.Support for (int i = 0; i < childCount; i++) { Control c = childControls[i]; - if (!(c is LiteralControl)) + if (c is LiteralControl) continue; + + Control configuredControl = InjectDependenciesRecursiveInternal(appContext, c); + if (configuredControl != c) { - InjectDependenciesRecursiveInternal(appContext, c); + ControlAccessor ac = new ControlAccessor(c.Parent); + ac.SetControlAt(configuredControl, i); } } } + + return control; } /// @@ -109,4 +116,4 @@ namespace Spring.Web.Support } } } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Web/Web/UI/Controls/Panel.cs b/src/Spring/Spring.Web/Web/UI/Controls/Panel.cs index de2e2b10..edbd3746 100644 --- a/src/Spring/Spring.Web/Web/UI/Controls/Panel.cs +++ b/src/Spring/Spring.Web/Web/UI/Controls/Panel.cs @@ -161,7 +161,7 @@ namespace Spring.Web.UI.Controls if (!_suppressDependencyInjection && _defaultApplicationContext != null) { - WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, control); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, control); } base.AddedControl(control, index); } @@ -187,4 +187,4 @@ namespace Spring.Web.UI.Controls #endregion Dependency Injection Support } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Web/Web/UI/MasterPage.cs b/src/Spring/Spring.Web/Web/UI/MasterPage.cs index 22d65b02..249a74ff 100644 --- a/src/Spring/Spring.Web/Web/UI/MasterPage.cs +++ b/src/Spring/Spring.Web/Web/UI/MasterPage.cs @@ -178,10 +178,10 @@ namespace Spring.Web.UI /// /// Returns the specified object, with dependencies injected. /// - protected new Control LoadControl(string virtualPath) + protected virtual new Control LoadControl(string virtualPath) { Control control = base.LoadControl(virtualPath); - WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext,control); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext,control); return control; } @@ -194,10 +194,10 @@ namespace Spring.Web.UI /// /// Returns the specified object, with dependencies injected. /// - protected new Control LoadControl( Type t, params object[] parameters) + protected virtual new Control LoadControl( Type t, params object[] parameters) { Control control = base.LoadControl( t, parameters ); - WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext,control); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext,control); return control; } @@ -498,7 +498,7 @@ namespace Spring.Web.UI /// protected override void AddedControl(Control control,int index) { - WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext,control); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext,control); base.AddedControl(control,index); } @@ -508,4 +508,4 @@ namespace Spring.Web.UI #endregion #endif -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Web/Web/UI/Page.cs b/src/Spring/Spring.Web/Web/UI/Page.cs index 9e039cd8..d4bdea23 100644 --- a/src/Spring/Spring.Web/Web/UI/Page.cs +++ b/src/Spring/Spring.Web/Web/UI/Page.cs @@ -540,10 +540,10 @@ namespace Spring.Web.UI /// /// Returns the specified object, with dependencies injected. /// - protected new Control LoadControl(string virtualPath) + protected virtual new Control LoadControl(string virtualPath) { Control control = base.LoadControl(virtualPath); - WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); return control; } @@ -557,10 +557,10 @@ namespace Spring.Web.UI /// /// Returns the specified object, with dependencies injected. /// - protected new Control LoadControl(Type t, params object[] parameters) + protected virtual new Control LoadControl(Type t, params object[] parameters) { Control control = base.LoadControl(t, parameters); - WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); return control; } #endif @@ -1656,11 +1656,11 @@ namespace Spring.Web.UI /// protected override void AddedControl(Control control, int index) { - WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); base.AddedControl(control, index); } #endregion Dependency Injection Support } -} \ No newline at end of file +} diff --git a/src/Spring/Spring.Web/Web/UI/UserControl.cs b/src/Spring/Spring.Web/Web/UI/UserControl.cs index a61aa6a6..c63fa430 100644 --- a/src/Spring/Spring.Web/Web/UI/UserControl.cs +++ b/src/Spring/Spring.Web/Web/UI/UserControl.cs @@ -280,10 +280,10 @@ namespace Spring.Web.UI /// /// Returns the specified object, with dependencies injected. /// - protected new Control LoadControl(string virtualPath) + protected virtual new Control LoadControl(string virtualPath) { Control control = base.LoadControl(virtualPath); - WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); return control; } @@ -297,10 +297,10 @@ namespace Spring.Web.UI /// /// Returns the specified object, with dependencies injected. /// - protected new Control LoadControl( Type t, params object[] parameters) + protected virtual new Control LoadControl( Type t, params object[] parameters) { Control control = base.LoadControl( t, parameters ); - WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); return control; } #endif @@ -1062,4 +1062,4 @@ namespace Spring.Web.UI #endregion Dependency Injection Support } -} \ No newline at end of file +} diff --git a/test/Spring/Spring.Web.Tests/Util/ControlInterceptionTests.cs b/test/Spring/Spring.Web.Tests/Util/ControlInterceptionTests.cs index 6428021e..1fb06a93 100644 --- a/test/Spring/Spring.Web.Tests/Util/ControlInterceptionTests.cs +++ b/test/Spring/Spring.Web.Tests/Util/ControlInterceptionTests.cs @@ -292,4 +292,35 @@ namespace Spring.Util } #endregion Test Support Classes -} \ No newline at end of file + + #region DI Templates // look at them using reflector + + internal class DIControlCollection : ControlCollection, ISupportsWebDependencyInjection + { + private IApplicationContext _defaultApplicationContext; + + public DIControlCollection(Control owner) : base(owner) + { + } + + IApplicationContext ISupportsWebDependencyInjection.DefaultApplicationContext + { + get { return _defaultApplicationContext; } + set { _defaultApplicationContext = value; } + } + + public override void Add(Control child) + { + child = WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, child); + base.Add(child); + } + + public override void AddAt(int index, Control child) + { + child = WebDependencyInjectionUtils.InjectDependenciesRecursive(_defaultApplicationContext, child); + base.AddAt(index, child); + } + } + + #endregion +}