Ich fand tatsächlich eine nette Lösung, wo ich xml-Dateien für Überschreibungen kombinieren und flüssige Registrierungen für Standardwerte verwenden.
Die fluent-API verwendet den vollständigen Namen eines impl als Standardschlüssel. Im laufenden Betrieb überschreibe ich die IDs von xml-config, um die Schlüsselkonventionen der fluent-API zu imitieren.
Dann registriere ich die Xml-Config, während ich Kernel.ComponentRegistered
höre.
Danach habe ich nur Dienste von der Code-Config, wo die XML noch nicht den Dienst definiert.
(es ist eine Weile her und ich nur den Code kopieren kleistert. Hoffentlich bekommen Sie daran zu arbeiten. Ich werde Änderungen tun, wenn Sie irgendwelche Probleme finden)
IList<Type> unnamedServices = new List<Type>();
IDictionary<string, Type> namedServices = new Dictionary<string, Type>();
ComponentDataDelegate registered = captureRegistrations(unnamedServices, namedServices);
container.Kernel.ComponentRegistered += registered;
// The method that captures the services
private static ComponentDataDelegate captureRegistrations(
IList<Type> unnamedServices, IDictionary<string, Type> namedServices)
{
return (key, handler) =>
{
if (handler.ComponentModel.Name == handler.ComponentModel.Implementation.FullName)
{
unnamedServices.Add(handler.Service);
}
else
{
namedServices.Add(key, handler.Service);
}
};
}
Danach bevor ich registrieren Im Code überprüfe ich, ob sie bereits registriert sind. Ich habe auch eine Basisklasse erstellt, die das vereinfacht.Dies ist eine Anwendungskonfiguration:
public class ApplicationConfiguration : WindsorConfigurationSkeleton
{
internal static WindsorServiceLocator create()
{
var container = createWith(null, "components-config.xml", coreServices, caches, roles);
return new WindsorServiceLocator(container);
}
internal static IEnumerable<IRegistration> coreServices()
{
yield return Component.For<ISystemClock>()
.ImplementedBy<PreciseSystemClock>()
.Parameters(Parameter.ForKey("synchronizePeriodSeconds").Eq("10"))
.LifeStyle.Singleton;
yield return Component.For<IMailService>()
.ImplementedBy<MailQueueService>()
.LifeStyle.Singleton;
}
internal static IEnumerable<IRegistration> caches()
{
yield return Component.For<IDataCache<ServiceAttributes>>()
.ImplementedBy<NoDataCache<ServiceAttributes>>()
.LifeStyle.Singleton;
// ....
}
}
Die Klasse Basis, die die Verkabelung funktioniert: (Protokollierung von commons.logging)
public class WindsorConfigurationSkeleton
{
private static readonly ILog _log = LogManager.GetLogger(
typeof(WindsorConfigurationSkeleton));
internal static IWindsorContainer createWith(
IRegistration[] customs, string configFile, params Func<IEnumerable<IRegistration>>[] methods)
{
IWindsorContainer container = new WindsorContainer();
BugFix.Kernel = container.Kernel;
container.AddFacility("factory.support", new FactorySupportFacility());
IList<Type> unnamedServices = new List<Type>();
IDictionary<string, Type> namedServices = new Dictionary<string, Type>();
ComponentDataDelegate registered = captureRegistrations(unnamedServices, namedServices);
container.Kernel.ComponentRegistered += registered;
if (customs != null)
{
container.Register(customs);
}
if (configFile != null)
{
tryAddXmlConfig(container, configFile);
}
container.Kernel.ComponentRegistered -= registered;
if (methods != null && methods.Length > 0)
{
container.Register(union(unnamedServices, namedServices, methods));
}
return container;
}
private static ComponentDataDelegate captureRegistrations(
IList<Type> unnamedServices, IDictionary<string, Type> namedServices)
{
return (key, handler) =>
{
if (handler.ComponentModel.Name == handler.ComponentModel.Implementation.FullName)
{
var text = unnamedServices.Contains(handler.Service) ? "another" : "default";
_log.Info(
m => m(
"Registered {2} service for {0} with {1}.",
handler.Service.GetDisplayName(),
handler.ComponentModel.Implementation.GetDisplayName(),
text
));
unnamedServices.Add(handler.Service);
}
else
{
var text = namedServices.ContainsKey(key) ? "another" : "default";
_log.Info(
m => m(
"Registered {3} service {0} with name '{1}' and {2}.",
handler.ComponentModel.Service,
handler.ComponentModel.Name,
handler.ComponentModel.Implementation.GetDisplayName(),
text
));
namedServices.Add(key, handler.Service);
}
};
}
protected static void tryAddXmlConfig(IWindsorContainer container, string filename)
{
var fi = Resources.GetFileFromResourceHierarchy(typeof(ApplicationContext).Namespace, filename);
if (fi == null) {
return;
}
var configFile = fi.FullName;
var xd = immitateFluentApiDefaultIdBehaviour(configFile);
container.Install(Configuration.FromXml(new StaticContentResource(xd.OuterXml)));
}
private static XmlDocument immitateFluentApiDefaultIdBehaviour(string configFile)
{
var xd = new XmlDocument();
xd.Load(configFile);
foreach (
XmlElement component in
xd.SelectNodes("/configuration/components/component[@type and (not(@id) or @id = '')]"))
{
var type = Type.GetType(component.GetAttribute("type"), true);
component.SetAttribute("id", type.FullName);
}
return xd;
}
private static IRegistration[] union(
IList<Type> unnamed, IDictionary<string, Type> named, params Func<IEnumerable<IRegistration>>[] methods)
{
var all = new List<IRegistration>();
foreach (var method in methods)
{
foreach (var registration in method())
{
var registrationType = registration.GetType();
if (registrationType.IsGenericTypeOf(typeof(ComponentRegistration<>)))
{
var componentType = registrationType.GetGenericArgumentsFor(typeof(ComponentRegistration<>))[0];
var name = (string)registrationType.GetProperty("Name").GetValue(registration, null);
if (name != null)
{
if (named.ContainsKey(name))
{
_log.Debug(
m => m("Skipped registering default named component {0}.", name));
continue;
}
}
else if (unnamed.Contains(componentType))
{
_log.Debug(
m => m("Skipped registering default component for type {0}.", componentType));
continue;
}
all.Add(registration);
}
else
{
all.Add(registration);
}
}
}
return all.ToArray();
}
}
Ich habe eine XML-Datei, die die fließenden Verdrahtungen überschreibt. Aber ich habe es jetzt gelöst, indem ich zuerst die XML-Datei gelesen habe und nicht die Konfigurationen aus dem Code hinzugefügt habe, wenn die XML-Datei sie neu definiert. –
Das ist besser Ansatz –
@Lars: Können Sie genauer sein, wie Sie das tun? Ich habe das gleiche Problem hier, ich habe meine Kern-Verdrahtungen und möchte eine Implementierung mit einer anderen wechseln, ohne die Kern-Verdrahtungen modifizieren zu müssen. – Marcus