From 0bc32b2efe163314dc5f98c9f2575aba7db8a439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20V=C3=A1clavek?= Date: Sat, 19 Jan 2019 12:13:34 +0100 Subject: [PATCH 1/3] Add Havit.CastleWindsor.WebForms --- .../ContainerServiceProvider.cs | 103 +++++++++++++ .../DependencyInjectionWebFormsHelper.cs | 135 ++++++++++++++++++ .../Havit.CastleWindsor.WebForms.csproj | 28 ++++ .../HttpApplicationExtensions.cs | 36 +++++ .../InjectAttribute.cs | 12 ++ .../InjectOverrideAttribute.cs | 36 +++++ .../InjectableWebServiceBase.cs | 31 ++++ .../WindsorContainerAdapter.cs | 44 ++++++ 8 files changed, 425 insertions(+) create mode 100644 src/Havit.CastleWindsor.WebForms/ContainerServiceProvider.cs create mode 100644 src/Havit.CastleWindsor.WebForms/DependencyInjectionWebFormsHelper.cs create mode 100644 src/Havit.CastleWindsor.WebForms/Havit.CastleWindsor.WebForms.csproj create mode 100644 src/Havit.CastleWindsor.WebForms/HttpApplicationExtensions.cs create mode 100644 src/Havit.CastleWindsor.WebForms/InjectAttribute.cs create mode 100644 src/Havit.CastleWindsor.WebForms/InjectOverrideAttribute.cs create mode 100644 src/Havit.CastleWindsor.WebForms/InjectableWebServiceBase.cs create mode 100644 src/Havit.CastleWindsor.WebForms/WindsorContainerAdapter.cs diff --git a/src/Havit.CastleWindsor.WebForms/ContainerServiceProvider.cs b/src/Havit.CastleWindsor.WebForms/ContainerServiceProvider.cs new file mode 100644 index 0000000..a7649e9 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms/ContainerServiceProvider.cs @@ -0,0 +1,103 @@ +using Castle.MicroKernel.Registration; +using Castle.Windsor; +using System; +using System.Collections.Concurrent; +using System.Reflection; +using System.Web; +using System.Web.Hosting; +using System.Web.UI; + +namespace Havit.CastleWindsor.WebForms +{ + /// + /// The Castle Windsor adapter for WebObjectActivator. + /// + internal class ContainerServiceProvider : IServiceProvider, IRegisteredObject + { + public IWindsorContainer Container { get; } = new WindsorContainer(); + + internal IServiceProvider NextServiceProvider { get; } + + private const int TypesCannotResolveCacheCap = 100000; + private readonly ConcurrentDictionary _typesCannotResolve = new ConcurrentDictionary(); // there is no ConcurrentHashSet in .NET FW. + + public ContainerServiceProvider(IServiceProvider next) + { + NextServiceProvider = next; + HostingEnvironment.RegisterObject(this); + } + + /// + /// Implementation of IServiceProvider. Asp.net will call this method to + /// create the instances of Page/UserControl/HttpModule etc. + /// Unfortunatelly not WebServices (.asmx) + /// + public object GetService(Type serviceType) + { + // Try unresolvable types - we cache them + if (_typesCannotResolve.ContainsKey(serviceType)) + { + return DefaultCreateInstance(serviceType); + } + + // Try the container + object result = null; + + // We must register dynamically compiled resources (pages, controls, master pages, handlers ...) + if ((typeof(UserControl).IsAssignableFrom(serviceType) || // User controls (.ascx) and event Master Pages (.master) inherit from UserControl + typeof(IHttpHandler).IsAssignableFrom(serviceType)) && // Geneirc handlers (.ashx) and also pages (.aspx) inherit from IHttpHandler + !Container.Kernel.HasComponent(serviceType)) + { + // Lifestyle is *Transient* + // If it would be PerWebRequest, we couldn't use the same control on one page twice - resolved would be only the first, and the second would be reused) + // And because transient, we must release component on end request - else we would make memory leaks + Container.Register(Component.For(serviceType).ImplementedBy(serviceType).LifestyleTransient()); + HttpContext.Current.AddOnRequestCompleted(_ => Container.Release(result)); // release objektu na konci requestu, abychom předešli memory-leaks + } + + // If we have component registered, we will resolve the service + if (Container.Kernel.HasComponent(serviceType)) + { + result = Container.Resolve(serviceType); + } + + // Try the next provider if we don't have result + if (result == null) + { + result = NextServiceProvider?.GetService(serviceType); + } + + // Default activation + if (result == null && (result = DefaultCreateInstance(serviceType)) != null) + { + // Cache it + if (_typesCannotResolve.Count < TypesCannotResolveCacheCap) + { + _typesCannotResolve.TryAdd(serviceType, true); + } + } + + return result; + } + + /// + /// Stop of registration. + /// + public void Stop(bool immediate) + { + HostingEnvironment.UnregisterObject(this); + + Container.Dispose(); + } + + private object DefaultCreateInstance(Type type) + { + return Activator.CreateInstance( + type, + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance, + null, + null, + null); + } + } +} diff --git a/src/Havit.CastleWindsor.WebForms/DependencyInjectionWebFormsHelper.cs b/src/Havit.CastleWindsor.WebForms/DependencyInjectionWebFormsHelper.cs new file mode 100644 index 0000000..77b7b0f --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms/DependencyInjectionWebFormsHelper.cs @@ -0,0 +1,135 @@ +using Castle.Windsor; +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Havit.CastleWindsor.WebForms +{ + /// + /// Helper class for resolving dependencies with injection to existing object + /// It wors a little bit like service locator for WindsorContainer O:-) + /// + internal static class DependencyInjectionWebFormsHelper + { + private static readonly ConcurrentDictionary cachedProperties = new ConcurrentDictionary(); + + /// + /// Initializes the instance (Only the instance itself without child controls!). + /// + internal static bool InitializeInstance(object control) + { + IWindsorContainer resolver = WindsorContainerAdapter.GetWindsorContainer(); + PropertyInfo[] props = GetInjectableProperties(control); + + // inject the values to properties + foreach (PropertyInfo prop in props) + { + IEnumerable overrideAttribs = prop.GetCustomAttributes(typeof(InjectOverrideAttribute), false).Cast(); + Dictionary resolvedSubdependencies = overrideAttribs + .ToDictionary(x => x.PropertyName, x => resolver.Resolve(x.DependencyKey, x.DependencyServiceType, null)); + try + { + object value; + Type enumerableType = GetEnumerableType(prop.PropertyType); + if (enumerableType != null) + { + value = resolvedSubdependencies.Count > 0 ? resolver.ResolveAll(enumerableType, resolvedSubdependencies) : resolver.ResolveAll(enumerableType); + } + else + { + value = resolvedSubdependencies.Count > 0 ? resolver.Resolve(prop.PropertyType, resolvedSubdependencies) : resolver.Resolve(prop.PropertyType); + } + prop.SetValue(control, value, null); + } + catch (Exception e) + { + throw new ApplicationException($"Error in resolving dependency {prop.Name}.", e); + } + } + + return props.Length > 0; + } + + /// + /// Retrns a collection of injectable properties for the control + /// + private static PropertyInfo[] GetInjectableProperties(object instance) + { + PropertyInfo[] props = cachedProperties.GetOrAdd(instance.GetType(), type => + { + PropertyInfo[] nonPublicInstanceProperties = type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy) + .Where(p => p.GetCustomAttributes(typeof(InjectAttribute), false).Length == 1).ToArray(); + + if (nonPublicInstanceProperties.Length > 0) + { + throw new NotSupportedException(String.Format("InjectAttribute cannot be used on a non public property. It is used on property {0} in {1}.", + nonPublicInstanceProperties.First().Name, nonPublicInstanceProperties.First().DeclaringType.FullName)); + } + + PropertyInfo[] staticProperties = type.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy) + .Where(p => p.GetCustomAttributes(typeof(InjectAttribute), false).Length == 1).ToArray(); + + if (staticProperties.Length > 0) + { + throw new NotSupportedException(String.Format("InjectAttribute cannot be used on a static property. It is used on property {0} in {1}.", + staticProperties.First().Name, staticProperties.First().DeclaringType.FullName)); + } + + return type.GetProperties(BindingFlags.Instance | BindingFlags.Public) + .Where(p => p.GetCustomAttributes(typeof(InjectAttribute), false).Length == 1).ToArray(); + }); + return props; + } + + /// + /// Releases all dependencies of the instance (which is being released) + /// + internal static void ReleaseDependencies(object control) + { + IWindsorContainer resolver = WindsorContainerAdapter.GetWindsorContainer(); + PropertyInfo[] props = GetInjectableProperties(control); + + foreach (PropertyInfo propertyInfo in props) + { + object dependencyInstance = propertyInfo.GetValue(control); + Type enumerableType = GetEnumerableType(propertyInfo.PropertyType); + + if ((enumerableType != null) && (dependencyInstance != null)) + { + IEnumerable dependencyInstanceEnumerable = (IEnumerable)dependencyInstance; + foreach (var dependencyInstanceItem in dependencyInstanceEnumerable) + { + resolver.Release(dependencyInstanceItem); + } + } + else if (dependencyInstance != null) + { + resolver.Release(dependencyInstance); + } + + propertyInfo.SetValue(control, null); + } + } + + /// + /// Gets enumerated type if interface of input type is IEnumerable<TEntity> or an array. + /// + private static Type GetEnumerableType(Type type) + { + if ((type != null) && type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(IEnumerable<>))) + { + return type.GetGenericArguments().FirstOrDefault(); + } + + if ((type != null) && type.IsArray && type.HasElementType && (type.GetArrayRank() == 1)) + { + return type.GetElementType(); + } + + return null; + } + } +} \ No newline at end of file diff --git a/src/Havit.CastleWindsor.WebForms/Havit.CastleWindsor.WebForms.csproj b/src/Havit.CastleWindsor.WebForms/Havit.CastleWindsor.WebForms.csproj new file mode 100644 index 0000000..c113ae7 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms/Havit.CastleWindsor.WebForms.csproj @@ -0,0 +1,28 @@ + + + + net472 + true + + + + + false + 1.8.2 + true + HAVIT .NET Framework Extensions - Castle Windsor support for WebForms + + content + HAVIT + HAVIT + + + + + + + + + + + diff --git a/src/Havit.CastleWindsor.WebForms/HttpApplicationExtensions.cs b/src/Havit.CastleWindsor.WebForms/HttpApplicationExtensions.cs new file mode 100644 index 0000000..992b68a --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms/HttpApplicationExtensions.cs @@ -0,0 +1,36 @@ +using Castle.Windsor; +using System; +using System.Web; + +namespace Havit.CastleWindsor.WebForms +{ + /// + /// Extension methods of HttpApplication that help use Castle Windsor container. + /// + public static class HttpApplicationExtensions + { + /// + /// Register Castle Windsor Container to HttpRuntime.WebObjectActivator and return its instance. + /// If Castle Windsor Container is currently registered, returns the registered Castle Windsor Container instance. + /// + public static IWindsorContainer AddWindsorContainer(this HttpApplication application) + { + // ...(this HttpApplication application) - just to be able to use it as extension method + + if (application == null) + { + throw new ArgumentNullException(nameof(application)); + } + + return WindsorContainerAdapter.AddWindsorContainer(); + } + + /// + /// Get registered Castle Windsor Container instance (or null if not registered). + /// + public static IWindsorContainer GetWindsorContainer() + { + return WindsorContainerAdapter.GetWindsorContainer(); + } + } +} diff --git a/src/Havit.CastleWindsor.WebForms/InjectAttribute.cs b/src/Havit.CastleWindsor.WebForms/InjectAttribute.cs new file mode 100644 index 0000000..b8cd5a6 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms/InjectAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Havit.CastleWindsor.WebForms +{ + /// + /// Marks properties that shall be injected in Web Services + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] + public class InjectAttribute : Attribute + { + } +} diff --git a/src/Havit.CastleWindsor.WebForms/InjectOverrideAttribute.cs b/src/Havit.CastleWindsor.WebForms/InjectOverrideAttribute.cs new file mode 100644 index 0000000..43f5db7 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms/InjectOverrideAttribute.cs @@ -0,0 +1,36 @@ +using System; + +namespace Havit.CastleWindsor.WebForms +{ + /// + /// Controls behavior of sub-dependcies resolving by specifing specific names of implementations to resolve + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] + public class InjectOverrideAttribute : Attribute + { + /// + /// Name of the property (subdependency) to resolve + /// + public string PropertyName { get; set; } + + /// + /// The Windsor key of the implementation + /// + public string DependencyKey { get; set; } + + /// + /// Type of the property (subdependency) to resolve + /// + public Type DependencyServiceType { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public InjectOverrideAttribute(string propertyName, string dependencyKey, Type dependencyServiceType) + { + PropertyName = propertyName; + DependencyKey = dependencyKey; + DependencyServiceType = dependencyServiceType; + } + } +} diff --git a/src/Havit.CastleWindsor.WebForms/InjectableWebServiceBase.cs b/src/Havit.CastleWindsor.WebForms/InjectableWebServiceBase.cs new file mode 100644 index 0000000..7e696e9 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms/InjectableWebServiceBase.cs @@ -0,0 +1,31 @@ +using System.Web.Services; + +namespace Havit.CastleWindsor.WebForms +{ + /// + /// Abstract base class for ASMX Web Services. It can have injected properties throght [Inject] attribute + /// + public abstract class InjectableWebServiceBase : WebService + { + /// + /// Constructor takes care of resolving Web Service dependencies + /// + protected InjectableWebServiceBase() + { + DependencyInjectionWebFormsHelper.InitializeInstance(this); + } + + /// + /// We must release Web Service dependencies + /// + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + { + DependencyInjectionWebFormsHelper.ReleaseDependencies(this); + } + } + } +} \ No newline at end of file diff --git a/src/Havit.CastleWindsor.WebForms/WindsorContainerAdapter.cs b/src/Havit.CastleWindsor.WebForms/WindsorContainerAdapter.cs new file mode 100644 index 0000000..c15318b --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms/WindsorContainerAdapter.cs @@ -0,0 +1,44 @@ +using Castle.Windsor; +using System.Web; + +namespace Havit.CastleWindsor.WebForms +{ + /// + /// Extension methods of HttpApplication that help use Castle Windsor Container. + /// + public static class WindsorContainerAdapter + { + private static object _lock = new object(); + + /// + /// Add a new Castle Windsor Container in ASP.NET application. If there is WebObjectActivator already registered, + /// it will return the registered isntance. When the new WebObjectActivator can't resolve the type, the previous WebObjectActivator + /// will be used. If the previous WebObjectActivator can't resolve it either, DefaultCreateInstance will be used + /// which creates instance through none public default constructor based on reflection. + /// + public static IWindsorContainer AddWindsorContainer() + { + lock (_lock) + { + var registeredWindsorContainer = GetWindsorContainer(); + if (registeredWindsorContainer != null) + { + return registeredWindsorContainer; + } + + var provider = new ContainerServiceProvider(HttpRuntime.WebObjectActivator); + HttpRuntime.WebObjectActivator = provider; + + return provider.Container; + } + } + + /// + /// Get most recent added Unity container + /// + public static IWindsorContainer GetWindsorContainer() + { + return (HttpRuntime.WebObjectActivator as ContainerServiceProvider)?.Container; + } + } +} \ No newline at end of file From cc605502d5cbc8a65399374b463134ef244f3f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20V=C3=A1clavek?= Date: Sat, 19 Jan 2019 12:14:00 +0100 Subject: [PATCH 2/3] Add Example application --- Havit.CastleWindsor.WebForms.sln | 36 ++++ .../Default.aspx | 10 + .../Default.aspx.cs | 22 ++ .../Default.aspx.designer.cs | 24 +++ .../Global.asax | 1 + .../Global.asax.cs | 15 ++ ...avit.CastleWindsor.WebForms.Example.csproj | 193 ++++++++++++++++++ .../IMyDependecy.cs | 7 + .../MyDependency.cs | 10 + .../Properties/AssemblyInfo.cs | 35 ++++ .../Web.Debug.config | 30 +++ .../Web.Release.config | 31 +++ .../Web.config | 51 +++++ .../packages.config | 23 +++ 14 files changed, 488 insertions(+) create mode 100644 Havit.CastleWindsor.WebForms.sln create mode 100644 src/Havit.CastleWindsor.WebForms.Example/Default.aspx create mode 100644 src/Havit.CastleWindsor.WebForms.Example/Default.aspx.cs create mode 100644 src/Havit.CastleWindsor.WebForms.Example/Default.aspx.designer.cs create mode 100644 src/Havit.CastleWindsor.WebForms.Example/Global.asax create mode 100644 src/Havit.CastleWindsor.WebForms.Example/Global.asax.cs create mode 100644 src/Havit.CastleWindsor.WebForms.Example/Havit.CastleWindsor.WebForms.Example.csproj create mode 100644 src/Havit.CastleWindsor.WebForms.Example/IMyDependecy.cs create mode 100644 src/Havit.CastleWindsor.WebForms.Example/MyDependency.cs create mode 100644 src/Havit.CastleWindsor.WebForms.Example/Properties/AssemblyInfo.cs create mode 100644 src/Havit.CastleWindsor.WebForms.Example/Web.Debug.config create mode 100644 src/Havit.CastleWindsor.WebForms.Example/Web.Release.config create mode 100644 src/Havit.CastleWindsor.WebForms.Example/Web.config create mode 100644 src/Havit.CastleWindsor.WebForms.Example/packages.config diff --git a/Havit.CastleWindsor.WebForms.sln b/Havit.CastleWindsor.WebForms.sln new file mode 100644 index 0000000..cb911d4 --- /dev/null +++ b/Havit.CastleWindsor.WebForms.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.271 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Havit.CastleWindsor.WebForms", "src\Havit.CastleWindsor.WebForms\Havit.CastleWindsor.WebForms.csproj", "{328EC034-9DC8-4D18-B889-BE91E0F1F768}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Havit.CastleWindsor.WebForms.Example", "src\Havit.CastleWindsor.WebForms.Example\Havit.CastleWindsor.WebForms.Example.csproj", "{656D9D65-D7FB-4027-A865-9566882519C8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D30F96B3-FAE3-4BB2-AB6D-20B5B29653F5}" + ProjectSection(SolutionItems) = preProject + README.md = README.md + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {328EC034-9DC8-4D18-B889-BE91E0F1F768}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {328EC034-9DC8-4D18-B889-BE91E0F1F768}.Debug|Any CPU.Build.0 = Debug|Any CPU + {328EC034-9DC8-4D18-B889-BE91E0F1F768}.Release|Any CPU.ActiveCfg = Release|Any CPU + {328EC034-9DC8-4D18-B889-BE91E0F1F768}.Release|Any CPU.Build.0 = Release|Any CPU + {656D9D65-D7FB-4027-A865-9566882519C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {656D9D65-D7FB-4027-A865-9566882519C8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {656D9D65-D7FB-4027-A865-9566882519C8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {656D9D65-D7FB-4027-A865-9566882519C8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6844D2A0-A9D8-4A2D-8223-CAC76E4FFA6F} + EndGlobalSection +EndGlobal diff --git a/src/Havit.CastleWindsor.WebForms.Example/Default.aspx b/src/Havit.CastleWindsor.WebForms.Example/Default.aspx new file mode 100644 index 0000000..b5e55e8 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms.Example/Default.aspx @@ -0,0 +1,10 @@ +<%@ Page Language="C#" AutoEventWireup="false" CodeBehind="Default.aspx.cs" Inherits="Havit.CastleWindsor.WebForms.Example._Default" %> + + + + Hello Havit.CastleWindsor.WebForms! + + + + + diff --git a/src/Havit.CastleWindsor.WebForms.Example/Default.aspx.cs b/src/Havit.CastleWindsor.WebForms.Example/Default.aspx.cs new file mode 100644 index 0000000..eb6a720 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms.Example/Default.aspx.cs @@ -0,0 +1,22 @@ +using System; +using System.Web.UI; + +namespace Havit.CastleWindsor.WebForms.Example +{ + public partial class _Default : Page + { + private readonly IMyDependecy myDependecy; + + public _Default(IMyDependecy myDependecy) + { + this.myDependecy = myDependecy; + } + + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + + litHello.Text = myDependecy.MyMethod(); + } + } +} \ No newline at end of file diff --git a/src/Havit.CastleWindsor.WebForms.Example/Default.aspx.designer.cs b/src/Havit.CastleWindsor.WebForms.Example/Default.aspx.designer.cs new file mode 100644 index 0000000..ff3a7b7 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms.Example/Default.aspx.designer.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Havit.CastleWindsor.WebForms.Example { + + + public partial class _Default { + + /// + /// litHello control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Literal litHello; + } +} diff --git a/src/Havit.CastleWindsor.WebForms.Example/Global.asax b/src/Havit.CastleWindsor.WebForms.Example/Global.asax new file mode 100644 index 0000000..dd45ab4 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms.Example/Global.asax @@ -0,0 +1 @@ +<%@ Application Codebehind="Global.asax.cs" Inherits="Havit.CastleWindsor.WebForms.Example.Global" Language="C#" %> diff --git a/src/Havit.CastleWindsor.WebForms.Example/Global.asax.cs b/src/Havit.CastleWindsor.WebForms.Example/Global.asax.cs new file mode 100644 index 0000000..723cddd --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms.Example/Global.asax.cs @@ -0,0 +1,15 @@ +using Castle.MicroKernel.Registration; +using System; +using System.Web; + +namespace Havit.CastleWindsor.WebForms.Example +{ + public class Global : HttpApplication + { + public void Application_Start(object sender, EventArgs e) + { + var container = this.AddWindsorContainer(); + container.Register(Component.For().ImplementedBy()); + } + } +} \ No newline at end of file diff --git a/src/Havit.CastleWindsor.WebForms.Example/Havit.CastleWindsor.WebForms.Example.csproj b/src/Havit.CastleWindsor.WebForms.Example/Havit.CastleWindsor.WebForms.Example.csproj new file mode 100644 index 0000000..d277049 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms.Example/Havit.CastleWindsor.WebForms.Example.csproj @@ -0,0 +1,193 @@ + + + + + + Debug + AnyCPU + + + 2.0 + {656D9D65-D7FB-4027-A865-9566882519C8} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Havit.CastleWindsor.WebForms.Example + Havit.CastleWindsor.WebForms.Example + v4.7.2 + true + + + + + + + + + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + + + true + pdbonly + true + bin\ + TRACE + prompt + 4 + + + + ..\..\packages\Castle.Core.4.2.0\lib\net45\Castle.Core.dll + + + ..\..\packages\Castle.Windsor.4.1.1\lib\net45\Castle.Windsor.dll + + + + + + + + + + + + + + + + + + + + + True + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + ..\..\packages\AspNet.ScriptManager.bootstrap.3.3.7\lib\net45\AspNet.ScriptManager.bootstrap.dll + + + ..\..\packages\AspNet.ScriptManager.jQuery.3.3.1\lib\net45\AspNet.ScriptManager.jQuery.dll + + + ..\..\packages\Microsoft.AspNet.ScriptManager.MSAjax.5.0.0\lib\net45\Microsoft.ScriptManager.MSAjax.dll + + + ..\..\packages\Microsoft.AspNet.ScriptManager.WebForms.5.0.0\lib\net45\Microsoft.ScriptManager.WebForms.dll + + + ..\..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll + + + ..\..\packages\Newtonsoft.Json.11.0.1\lib\net45\Newtonsoft.Json.dll + + + True + ..\..\packages\WebGrease.1.6.0\lib\WebGrease.dll + + + True + ..\..\packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll + + + True + ..\..\packages\Microsoft.AspNet.Web.Optimization.WebForms.1.1.3\lib\net45\Microsoft.AspNet.Web.Optimization.WebForms.dll + + + ..\..\packages\Microsoft.AspNet.FriendlyUrls.Core.1.0.2\lib\net45\Microsoft.AspNet.FriendlyUrls.dll + + + + + ..\..\packages\System.Diagnostics.DiagnosticSource.4.4.1\lib\net46\System.Diagnostics.DiagnosticSource.dll + + + ..\..\packages\Microsoft.AspNet.TelemetryCorrelation.1.0.0\lib\net45\Microsoft.AspNet.TelemetryCorrelation.dll + + + ..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.2.0.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + + + + + + + + + + Default.aspx + ASPXCodeBehind + + + Default.aspx + + + Global.asax + + + + + + + + {328ec034-9dc8-4d18-b889-be91e0f1f768} + Havit.CastleWindsor.WebForms + + + + + + Web.config + + + Web.config + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + True + True + 23853 + / + http://localhost:23853/ + False + False + + + False + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/src/Havit.CastleWindsor.WebForms.Example/IMyDependecy.cs b/src/Havit.CastleWindsor.WebForms.Example/IMyDependecy.cs new file mode 100644 index 0000000..7375af3 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms.Example/IMyDependecy.cs @@ -0,0 +1,7 @@ +namespace Havit.CastleWindsor.WebForms.Example +{ + public interface IMyDependecy + { + string MyMethod(); + } +} diff --git a/src/Havit.CastleWindsor.WebForms.Example/MyDependency.cs b/src/Havit.CastleWindsor.WebForms.Example/MyDependency.cs new file mode 100644 index 0000000..a23dcf0 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms.Example/MyDependency.cs @@ -0,0 +1,10 @@ +namespace Havit.CastleWindsor.WebForms.Example +{ + public class MyDependency : IMyDependecy + { + public string MyMethod() + { + return "Hello from dependency!"; + } + } +} diff --git a/src/Havit.CastleWindsor.WebForms.Example/Properties/AssemblyInfo.cs b/src/Havit.CastleWindsor.WebForms.Example/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7ce8427 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms.Example/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Havit.CastleWindsor.WebForms.Example")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Havit.CastleWindsor.WebForms.Example")] +[assembly: AssemblyCopyright("Copyright © HAVIT 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("656d9d65-d7fb-4027-a865-9566882519c8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Havit.CastleWindsor.WebForms.Example/Web.Debug.config b/src/Havit.CastleWindsor.WebForms.Example/Web.Debug.config new file mode 100644 index 0000000..fae9cfe --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms.Example/Web.Debug.config @@ -0,0 +1,30 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/Havit.CastleWindsor.WebForms.Example/Web.Release.config b/src/Havit.CastleWindsor.WebForms.Example/Web.Release.config new file mode 100644 index 0000000..da6e960 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms.Example/Web.Release.config @@ -0,0 +1,31 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/Havit.CastleWindsor.WebForms.Example/Web.config b/src/Havit.CastleWindsor.WebForms.Example/Web.config new file mode 100644 index 0000000..4f7db47 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms.Example/Web.config @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Havit.CastleWindsor.WebForms.Example/packages.config b/src/Havit.CastleWindsor.WebForms.Example/packages.config new file mode 100644 index 0000000..e0e4aa8 --- /dev/null +++ b/src/Havit.CastleWindsor.WebForms.Example/packages.config @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 0f25aa9d3df61c5757d7ea4930f379f31b59f02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20V=C3=A1clavek?= Date: Sat, 19 Jan 2019 12:21:08 +0100 Subject: [PATCH 3/3] Add documentation --- README.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a3d7ee0..2ad6a00 100644 --- a/README.md +++ b/README.md @@ -1 +1,59 @@ -# Havit.CastleWindsor.WebForms \ No newline at end of file +# Havit.CastleWindsor.WebForms + +Implementation of Castle Windsor DI container to ASP.NET WebForms 4.7.2. In previous versions there is no direct support due to mising extensibility point **HttpRuntime.WebObjectActivator**. You can find more details in [news article](https://blogs.msdn.microsoft.com/dotnet/2018/04/30/announcing-the-net-framework-4-7-2/). + +## Instalation to existing project + +1. First you must switch *Target framework* for your project to .NET Framework 4.7.2. If you don't have installed .NET Framework 4.7.2 developer pack. You can download it from [here](https://www.microsoft.com/net/download/thank-you/net472-developer-pack). + +Check web.config and targetFramework in httpRuntime section. Both must be set to 4.7.2. + +```xml + + + + +``` + +2. Add nuget package **Havit.CastleWindsor.WebForms**. *Don't forget to reinstall other nuget packges, if you changed Target framework in previous step.* +3. Install nuget packge **Castle.Windsor**. +4. Add this initiaizing code to **Application_Start** method in **Global.asax**. Extension method AddWindsorContainer will initialize new container and will use it for resolving dependencies. +```c-sharp +IWindsorContainer container = this.AddWindsorContainer(); +``` +5. Also add using to the header of global.asax +```c-sharp +using Havit.CastleWindsor.WebForms; +``` + +## Working areas +There are many areas you can use Dependency Injection in WebForms applications now. Here is a complete list: + +- Pages and controls + - WebForms page + - User control + - Custom control +- IHttpHandler and IHttpHandlerFactory +- IHttpModule +- Providers + - BuildProvider + - ResourceProviderFactory + - Health monitoring provider + - Any ProviderBase based provider created by System.Web.Configuration.ProvidersHelper.InstantiateProvider. e.g. custom sessionstate provider + +## Known limitations +Because it is not possible to use Dependency Injection through WebOjectActivator in Web Services (*.asmx), we added a workaround for this case, so you can injection to web services via proerties. + +### How to inject to Web Services +1. Web Service must inherit from abstract class **Havit.CastleWindsor.WebForms.InjectableWebServiceBase** +2. Every property, you want to inject must be marked with attribute **Havit.CastleWindsor.WebForms.InjectAttribute]** +3. Every property, you want to inject must have a **public getter and setter** + +## Example +We have prepared a simple example appliction with one page, where is used Dependency Injection. See Havit.CastleWindsor.WebForms.Example appliction. + +## Troubleshooting +1. If you hit error saying page (or user control) cannot be created because of missing contructor with zero arguments, check if you switched you project to .NET FW 4.7.2. + +## Licence +MIT \ No newline at end of file