I've got an application using Autofac at the moment. I've structured my autofac to register from the config file after the modules are loaded in. (For an xml-based override of the default behaviour).
Right now I've got a class with a bunch of basic environmental settings (a slew of public auto-properties really). This class tries to guess the default configuration based on some settings, but the idea is that each environment the app runs under would override these settings in the xml config.
Here's my problem:
Earlier in the development of this system, things were peachy. Now it seems to be completely ignoring the input of the XML Configs. I am unsure what changed that caused this to get broken, so I'm hoping someone can point out something obvious I am doing wrong.
I have verified the config file is getting read/parsed by autofac, just not applied.
web.config:
<autofac>
<files>
<file name="Config/Environment.config" section="autofac-common" />
<file name="Config/Environment.config" section="autofac-public" />
</files>
</autofac>
Environment.config:
<configuration>
<configSections>
<section name="autofac-common" type="Autofac.Configuration.SectionHandler, Autofac.Configuration"/>
<section name="autofac-public" type="Autofac.Configuration.SectionHandler, Autofac.Configuration"/>
</configSections>
<!-- Common -->
<autofac-common>
<components>
<component type="MyApp.Web.Configuration.ServerConfiguration, MyApp.Web"
service="MyApp.Web.Configuration.IServerConfiguration, MyApp.Web">
<properties>
<property name="Host" value="beta.mysite.com" />
<property name="MediaHost" value="beta.media.mysite.com" />
</properties>
</component>
</components>
</autofac-common>
<!-- Web Site -->
<autofac-public>
<modules>
<module type="MyApp.Configuration.CachingModule, MyApp">
<properties>
<property name="Disable" value="true" />
</properties>
</module>
</modules>
</autofac-public>
</configuration>
Container Building Code
var builder = new ContainerBuilder();
// Register Identifier so it's available to modules
builder.RegisterType<ServerIdentifier>()
.As<IServerIdentifier>()
.SingleInstance();
var container = builder.Build();
builder = new ContainerBuilder();
builder.RegisterModule(new CachingModule() { Disable = true });
builder.RegisterModule(new LoggerModule());
builder.RegisterModule(new InventoryModule());
builder.RegisterModule(new CatalogModule());
builder.RegisterModule(new WebModule(container));
// Override with settings from XML
builder.RegisterModule(new ConfigurationSettingsReader("autofac"));
builder.Update(container);
Autofac Version is 2.3.2.632 For .NET 3.5
The problem is in your <files> section. Since this is handled by FileElementCollection, a configuration class inheriting the NamedConfigurationElementCollection class and using the name property as its key value, multiple entries must have unique name values.
Since you are referring to the same name twice, the first entry referring to the autofac-common section is effectively overwritten by the second entry. Thus, the service will never be registered, only the CachingModule.
I cannot say whether this is new behavior on Autofac's part or not, as far as I can tell from the source, the FileElementCollection class was introduced in 2.0 and haven't changed logic since then. Could it be that you have referenced different .config files earlier?
Related
I have learnt about custom configurations using the ConfigurationManager. For some reason you have to use the assembly reference in the section element of the app.config, otherwise the ConfigurationManager won't load the app.config. But in an ASP.NET app this works fine. Why?
Consider this custom configuration class:
namespace CustomConfiguration
{
class MySection : ConfigurationSection
{
[ConfigurationProperty("link", IsKey = true)]
public string Link
{
get => (string) this["link"];
set => this["link"] = value;
}
}
}
Using this app.config, I can easily get the link-attribute of myCustomSection in my program:
<configuration>
<configSections>
<section name="myCustomSection" type="CustomConfiguration.MySection, myAssembly" />
</configSections>
...
<myCustomSection link="link i can access in my code" >
</myCustomSection>
</configuration>
Removing the assembly reference in section-element of app.config will result in a ConfigurationErrorsException, because the ConfigurationManager can't load my CustomConfiguration.MySection class in it's own System.Configuration assembly.
E.g.:
<section name="myCustomSection" type="CustomConfiguration.MySection" />
But Microsofts documentation says I should be able to do this.
And in fact I can do this in an ASP.NET app. Not supplying an assembly-name in a type attribute for a section still works and system.configuration magically looks in the right app assembly. Why?
The ASP.NET hosting environment has a different assembly loading behaviour;
it loads all referenced assemblies (from then bin and GAC) at the moment of startup.
For that reason, the assembly of the CustomConfiguration.MySection section can be resolved automatically without specifying it in the type definition.
If you include the settings below in you web.config file, your assembly myAssembly will not be loaded at initial startup anymore.
Then it will also be required to specify the assembly part in the type definition via CustomConfiguration.MySection, myAssembly. Here you get the same behaviour as in a non web-based application.
<configuration>
<!-- ... -->
<system.web>
<compilation>
<assemblies>
<remove assembly="myAssembly" />
</assemblies>
</compilation>
</system.web>
<!-- ... -->
</configuration>
The referenced documentation in your question shows that a section (shown belown) can be declared in an app.config file (of non web-based application), but this will only work for the out-of-the-box supplied configuration classes/handlers, like eg. System.Configuration.SingleTagSectionHandler, which resides in the core System assemby (System.dll).
For all other (custom) sections, a full assembly-qualified name is required.
<configuration>
<configSections>
<section name="sampleSection"
type="System.Configuration.SingleTagSectionHandler" />
</configSections>
<sampleSection setting1="Value1"
setting2="value two"
setting3="third value" />
</configuration>
I have consolidated the connection string information for a number of C# .NET solutions that are in my possession. Previously, each project was storing its connection string in its own format, requiring me to modify several files for each installation of the software.
Only one remaining solution is giving me trouble. This particular solution uses Castle Windsor 2.0, ActiveRecord 2.0 and NHibernate 2.1. The code reads its configuration from an XML file. I wish to remove the connection string from the config file and set it programmatically in the code.
Here is the relevant section of code that initiates Windsor:
windsorContainer = new WindsorContainer(new XmlInterpreter(xmlFileName));
windsorContainer.Resolve<IWindsorConfigurator>().Configure(windsorContainer);
logger = windsorContainer.Resolve<ILogger>();
Here are the contents of the XML file:
<?xml version="1.0"?>
<configuration>
<properties>
<connectionString>Server=*****;Database=*****;User Id=*****;Password=*****</connectionString>
</properties>
<facilities>
<facility id="logging" type="Castle.Facilities.Logging.LoggingFacility, Castle.Facilities.Logging" loggingApi="log4net" configFile="Configs/log4net.config" />
<facility id="atm" type="Castle.Facilities.AutomaticTransactionManagement.TransactionFacility, Castle.Facilities.AutomaticTransactionManagement" />
<facility id="arfacility" type="Castle.Facilities.ActiveRecordIntegration.ActiveRecordFacility, Castle.Facilities.ActiveRecordIntegration" isDebug="false" isWeb="false">
<!-- Configure the namespaces for the models using Active Record Integration -->
<assemblies>
<item>ChronoSteril.Application</item>
</assemblies>
<config>
<add key="connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
<add key="dialect" value="NHibernate.Dialect.MsSql2005Dialect" />
<add key="connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
<add key="connection.connection_string" value="#{connectionString}" />
<add key="hibernate.cache.provider_class" value="NHibernate.Caches.SysCache.SysCacheProvider, NHibernate.Caches.SysCache" />
<add key="proxyfactory.factory_class" value="NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle" />
<add key="hibernate.expiration" value="60" />
</config>
</facility>
</facilities>
<components>
<component id="windsorConfigurator" service="ChronoSteril.Application.IWindsorConfigurator, ChronoSteril.Application" type="ChronoSteril.WinApp.ClarionIntegrationWindsorConfigurator, ChronoSteril.WinApp" />
</components>
I am not familiar with Windsor. During my Google tour, I did see some code that adds facilities programmatically, but those examples were not valid for my version of Windsor (I assume).
Question: Can anyone guide me in removing the connection string information from the XML file and allow me to set it in the code?
Thank you!
I managed to accomplish my intention. It is not ideal, but will work until the code base is rewritten. (I cannot wait to drop the existing code like a bad dream.)
Patrick's comment, under my initial question, let me to refine my search criteria, which yielded the thread located here.
My XML file remains the same, except that I use bogus values for the connection string information. I will never need to modify these, and they do not reveal any valid connection information. This was my intention. I still have not discovered how to successfully remove the ActiveRecord configuration from the XML file and configure using code.
I now call a method that contains the following code:
ISessionFactoryHolder sessionFactoryHolder = ActiveRecordMediator.GetSessionFactoryHolder();
NHibernate.Cfg.Configuration configuration = sessionFactoryHolder.GetConfiguration(typeof(ActiveRecordBase));
connectionString = ReadConnectionString();
configuration.SetProperty("connection.connection_string", connectionString);
This works for me. I hope that it can also help someone else who is in the same position as I was.
I have a problem to config unity in app.config file, My project is wcf service project and I have used unity on this project well, but I don't know exactly, how to config generic types in app.config, before that I config my unity for MVC web application in UnityConfig.cs class like below and I wanna do that in wcf service project.
What is my wrong?
Works fine in class level:
container.RegisterType(typeof (IRepositoryAsync<>), typeof (Repository<>), new PerRequestLifetimeManager());
container.RegisterType(typeof (IRepository<>), typeof (Repository<>), new PerRequestLifetimeManager());
Not work in app.config:
<register type="IRepository[], FaraGostar.Repository.Pattern.Repositories" mapTo="Repository, FaraGostar.Repository.Pattern">
<lifetime type="singleton" />
</register>
<register type="IRepositoryAsync[], FaraGostar.Repository.Pattern.Repositories" mapTo="Repository, FaraGostar.Repository.Pattern">
<lifetime type="singleton" />
</register>
In my personal view I think, I can not config well []!
See the Generic Types section at the bottom of Unity's Specifying Types in the Configuration File
Short answer the unexpected:
<register type="IRepository`1, FaraGostar.Repository.Pattern.Repositories" mapTo="Repository`1, FaraGostar.Repository.Pattern">
We are currently using StructureMap as the IoC container. All was working ok, but now we need to change the defaults in runtime.
What we need is ability to provide IEntityRepository, IEntityService based on a user. Having EntityRepositoryEur, EntityRepositoryRus...
Is there some way how to chnage Instances in runtime based on user setting? What is the best way to do that? Maybe is there some better IoC right now to do that?
I am not familiar with StructureMap but with Unity Application Block (called usually just Unity) you can register more concrete types (services) with single interface. You assign names to these services and at the time of resolution you receive the list of registered services. Then you can choose one based on the user settings.
This is example how to register named services using config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>
<unity>
<containers>
<container>
<types>
<type name="OutputService1" type="InterfacesLibrary.IOutputService, InterfacesLibrary" mapTo="InputOutputLibrary.ConsoleOutputService, InputOutputLibrary" />
<type name="OutputService2" type="InterfacesLibrary.IOutputService, InterfacesLibrary" mapTo="InputOutputLibrary.MsgBoxOutputService, InputOutputLibrary" />
</types>
</container>
</containers>
</unity>
</configuration>
Or you can do the same thing from code
container.RegisterType<IOutputService, ConsoleOutputService>("OutputService1");
container.RegisterType<IOutputService, MsgBoxOutputService>("OutputService2");
At the time of resolution you resolve one or the other type based on user's requirements
IOutputService outputService;
if (user.LikesConsole == true)
outputService = container.Resolve<IOutputService>("OutputService1");
else
outputService = container.Resolve<IOutputService>("OutputService2");
Have a look at the series of videos on PRISM. The second video is introduction to Unity.
This is somewhat specific and difficult situation to explain, so bear with me.
I have created a UnityContainerExtension that is responsible for loading and configuring other .config files.
For example, my App.Config file looks like this:
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration, Version=2.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</configSections>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<assembly name="SomeAssembly" />
<namespace name="SomeAssembly.SomeNameSpace" />
<container>
<extension type="ConfigSectionExtension" />
<extension type="TestExtension" />
</container>
</unity>
</configuration>
My first extension ConfigSectionExtension runs code (following) that loads in and configures the container with another .config file. ex.
var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = "logging.config"};
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration( fileMap, ConfigurationUserLevel.None );
((UnityConfigurationSection)configuration.GetSection( "unity" )).Configure( Container );
This code runs fine, however the TestExtension extension in my config cannot be resolved after the Container has been configured with the logging.config file.
The specific response is
"The type name or alias TestExtension could not be resolved."
If I remove the code that loads and configures the logging.config file with the container, then both extensions are found. Is there any way to make this work?
This is essentially my approach to the problem of not being able to link together multiple .config files. If someone knows a better way to link .config files together for Unity, I would of course be open to that solution as well.
OK, I think I have an OK solution. For my extension I can just fully qualify the Type and it will work. ie.
<extension type="MediaInjectorUI.ContainerExtensions.ConfigSectionExtension, MediaInjectorUI" />
<extension type="MediaInjectorUI.ContainerExtensions.TestExtension, MediaInjectorUI" />
Maybe not the prettiest thing in the world, but itdoes the job.