diff --git a/src/Orchard.Web/Config/Sample.HostComponents.config b/src/Orchard.Web/Config/Sample.HostComponents.config
new file mode 100644
index 000000000..1ece073bc
--- /dev/null
+++ b/src/Orchard.Web/Config/Sample.HostComponents.config
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Orchard.Web/Orchard.Web.csproj b/src/Orchard.Web/Orchard.Web.csproj
index 006f9822c..d254af564 100644
--- a/src/Orchard.Web/Orchard.Web.csproj
+++ b/src/Orchard.Web/Orchard.Web.csproj
@@ -122,6 +122,9 @@
Global.asax
+
+ Designer
+
diff --git a/src/Orchard/Environment/HostComponentsConfigModule.cs b/src/Orchard/Environment/HostComponentsConfigModule.cs
new file mode 100644
index 000000000..6e7c014d4
--- /dev/null
+++ b/src/Orchard/Environment/HostComponentsConfigModule.cs
@@ -0,0 +1,137 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+using System.Xml.Linq;
+using Autofac;
+using Autofac.Core;
+using Module = Autofac.Module;
+
+namespace Orchard.Environment {
+ ///
+ /// Alter components instantiations by setting property values defined in a configuration file
+ ///
+ public class HostComponentsConfigModule : Module {
+ public static class XNames {
+ public const string Xmlns = "";
+ public static readonly XName HostComponents = XName.Get("HostComponents", Xmlns);
+ public static readonly XName Components = XName.Get("Components", Xmlns);
+ public static readonly XName Component = XName.Get("Component", Xmlns);
+ public static readonly XName Properties = XName.Get("Properties", Xmlns);
+ public static readonly XName Property = XName.Get("Property", Xmlns);
+ public static readonly XName Type = XName.Get("Type");
+ public static readonly XName Name = XName.Get("Name");
+ public static readonly XName Value = XName.Get("Value");
+ }
+
+ // component type name => list of [property name, property value]
+ public class PropertyEntry {
+ public string Name { get; set; }
+ public string Value { get; set; }
+ }
+
+ public readonly IDictionary> _config = new Dictionary>();
+
+ public HostComponentsConfigModule() {
+ // Called by the framework, as this class is a "Module"
+ }
+
+ public HostComponentsConfigModule(string fileName) {
+ var doc = XDocument.Load(fileName);
+ foreach (var component in doc.Elements(XNames.HostComponents).Elements(XNames.Components).Elements(XNames.Component)) {
+ var componentType = Attr(component, XNames.Type);
+ if (componentType == null)
+ continue;
+
+ var properties = component
+ .Elements(XNames.Properties)
+ .Elements(XNames.Property)
+ .Select(property => new PropertyEntry { Name = Attr(property, XNames.Name), Value = Attr(property, XNames.Value) })
+ .Where(t => !string.IsNullOrEmpty(t.Name) && !string.IsNullOrEmpty(t.Value))
+ .ToList();
+
+ if (!properties.Any())
+ continue;
+
+ _config.Add(componentType, properties);
+ }
+ }
+
+ private string Attr(XElement component, XName name) {
+ var attr = component.Attribute(name);
+ if (attr == null)
+ return null;
+ return attr.Value;
+ }
+
+ protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration) {
+ var implementationType = registration.Activator.LimitType;
+
+ IEnumerable properties;
+ if (!_config.TryGetValue(implementationType.FullName, out properties))
+ return;
+
+ // build an array of actions on this type to assign loggers to member properties
+ var injectors = BuildPropertiesInjectors(implementationType, properties).ToArray();
+
+ // if there are no logger properties, there's no reason to hook the activated event
+ if (!injectors.Any())
+ return;
+
+ // otherwise, whan an instance of this component is activated, inject the loggers on the instance
+ registration.Activated += (s, e) => {
+ foreach (var injector in injectors)
+ injector(e.Context, e.Instance);
+ };
+ }
+
+ private IEnumerable> BuildPropertiesInjectors(Type componentType, IEnumerable properties) {
+ // Look for settable properties with name in "properties"
+ var settableProperties = componentType
+ .GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance)
+ .Select(p => new {
+ PropertyInfo = p,
+ IndexParameters = p.GetIndexParameters(),
+ Accessors = p.GetAccessors(false),
+ PropertyEntry = properties.Where(t => t.Name == p.Name).FirstOrDefault()
+ })
+ .Where(x => x.PropertyEntry != null) // Must be present in "properties"
+ .Where(x => x.IndexParameters.Count() == 0) // must not be an indexer
+ .Where(x => x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)); //must have get/set, or only set
+
+ // Return an array of actions that assign the property value
+ foreach (var entry in settableProperties) {
+ var propertyInfo = entry.PropertyInfo;
+ var propertyEntry = entry.PropertyEntry;
+
+ yield return (ctx, instance) => {
+ object value;
+ if (ChangeToCompatibleType(propertyEntry.Value, propertyInfo.PropertyType, out value))
+ propertyInfo.SetValue(instance, value, null);
+ };
+ }
+ }
+
+ public static bool ChangeToCompatibleType(string value, Type destinationType, out object result) {
+ if (string.IsNullOrEmpty(value)) {
+ result = null;
+ return false;
+ }
+
+ if (destinationType.IsAssignableFrom(value.GetType())) {
+ result = value;
+ return true;
+ }
+
+ try {
+ result = TypeDescriptor.GetConverter(destinationType).ConvertFrom(value);
+ return true;
+ }
+ catch {
+ result = null;
+ return false;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Orchard/Environment/OrchardStarter.cs b/src/Orchard/Environment/OrchardStarter.cs
index 95110dc03..30988def7 100644
--- a/src/Orchard/Environment/OrchardStarter.cs
+++ b/src/Orchard/Environment/OrchardStarter.cs
@@ -108,6 +108,10 @@ namespace Orchard.Environment {
if (File.Exists(optionalHostConfig))
builder.RegisterModule(new ConfigurationSettingsReader(ConfigurationSettingsReader.DefaultSectionName, optionalHostConfig));
+ var optionalComponentsConfig = HostingEnvironment.MapPath("~/Config/HostComponents.config");
+ if (File.Exists(optionalComponentsConfig))
+ builder.RegisterModule(new HostComponentsConfigModule(optionalComponentsConfig));
+
var container = builder.Build();
diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj
index bd01f5099..f608e1d30 100644
--- a/src/Orchard/Orchard.Framework.csproj
+++ b/src/Orchard/Orchard.Framework.csproj
@@ -169,6 +169,7 @@
+