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.
Related
I am playing with the IoC Container Unity, and according to the documentation, adding this xmlns attribute to the "unity" section must allow Visual Studio doing some Intellisense stuff :
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>
[..]
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
[..]
</unity>
</configuration>
Actually, it doesn't work. It seems the resource has been (re?)moved. Do you know the new link ?
The actual xsd file can be found here: https://raw.githubusercontent.com/unitycontainer/configuration/master/src/Unity.Configuration.xsd
It looks like you're talking about this link:
http://msdn.microsoft.com/en-us/library/dn507436(v=pandp.30).aspx
I'm trying to use xml configuration file in my project. Now it looks like:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="replication" type="Project.Replication.ReplicationConfigSection, Project.Replication" />
<section name="processing" type="Project.Processing.ProcessingConfigSection, Project.Processing" />
</configSections>
<replication>
<streams>
<stream name="STREAM_DATA_14360" />
</streams>
</replication>
<processing dataStream="STREAM_DATA_14360" />
</configuration>
It works OK, but I'm confused with duplicates in it ("STREAM_DATA_14360").
Can you remind me, how to create variables in XML or something for data reusing to be acceptable in application configuration?
UPDATE:
In real life my configuration has much more sections. There is a value, which apeears in many of this sections: STREAM_DATA_14360. So I want to be able to change this value only in one place of config file, and in other places to use reference to it.
Speed of changing configuration - is the first reason for it.
Size of a file is a second, because values can be huge: STREAM_INFO_FUTURE_SESSION_CONTENTS_12421 (that is third-party names)
You can simply add this value in <appSettings> and access it as you are saying.
You can do this as below:
<appSettings>
<add key="StreamName" value="STREAM_DATA_14360"/>
</appSettings>
In the code, you can access it as below:
string streamName = ConfigurationManager.AppSettings["StreamName"];
Make sure to add reference to System.Configuration assembly before using this.
XML doesn't have any native expansion macros or templating - any scenario would require that you do a preprocess step or have the code that reads the config involved in substituting the value.
If those aren't redacted names though, it seems a simple search/replace would solve the problem without much of a concern on false positives.
You could put something together with T4 templates as a preprocessor, whether that's worth it really depends on how often you expect to modify this file.
It should also be possible to shoehorn the web.config transformation engine into doing the replacements, but you may have to write some hosting code for the XDT engine depending on how your config file is setup.
Apart from using external code that might (or might not) facilitate your life, you can define your own classes that inherit from ConfigurationSection, wherein you define and encapsulate your key/value pairs and use the ConfigurationProperty attribute.
Have look at http://msdn.microsoft.com/en-us/library/2tw134k3.aspx for more info on How to: Create Custom Configuration Sections Using ConfigurationSection.
EDIT: you can make references in xsd (check here)
Thanks for your answers. I agree with Mark, there's no support of variables or references in XML. But, in my case there's much simpler solution. I feel stupid now, but hope that it will help another slowpoke too.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="global" type="Project.GlobalConfigSection, Project" />
<section name="replication" type="Project.Replication.ReplicationConfigSection, Project.Replication" />
<section name="processing" type="Project.Processing.ProcessingConfigSection, Project.Processing" />
</configSections>
<global>
<streamNames>
<streamName name="STREAM_DATA_14360" id="1"/>
</streamNames>
</global>
<replication>
<streams>
<stream nameId="1" />
</streams>
</replication>
<processing dataStreamId="1" />
</configuration>
Consequence: need to edit code to use global section as a source of all long names
Advantage: fast renaming, reusability of values
I am using the Unity framework as IoC container.
My Config looks some like this:
<unity>
<container>
<register type="Namespace1.IFoo, FooAsm"
mapTo="Namespace2.Bar, BarAsm">
</register>
</conainer>
I would like to register a container to use a factory method. How do i achive it using the app.config?
I am looking for something like this:
<unity>
<container>
<register type="Namespace1.IFoo, FooAsm"
factory="Namespace2.Bar, BarAsm"
method="create">
</register>
</conainer>
</unity>
Any suggestsions?
This thread offers a nice response about how to add support of Factory methods for Unity. I fact you have to download this bitbucket source (and change the references to 4.0 framework).
If you now add Generic support for Unity you get a pretty awesome solution that might look like this:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity xmlns="schemas.microsoft.com/practices/2010/unity">
<sectionExtension type="Unity.FactoryConfig.FactoryConfigExtension, Unity.FactoryConfig"/>
<alias alias="Factory" type="Namespace1.GenericFactory`1, asm1"/>
<container>
<register type="Namespace1.ITest, asm1">
<factory type="Factory[[Namespace1.ITest, asm1]]" method="Create" />
</register>
</container>
</unity>
</configuration>
Support of generic Factories for unity framework using xml configuration!
Thanks for all comments :)
I don't think there is a built-in way to do this currently. I usually just register the factory itself (Map IMyFactory -to-> MyFactoryImpl) then inject the factory into the classes that need it, and have the classes call the factory.
However, I think you can probably make something call a factory straight from Unity by making an extension for Unity. There are a couple mentioned in the answers to this question: How to create objects using a static factory method?
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.
I'm currently getting an error trying to resolve my IDataAccess class.
The value of the property 'type' cannot be parsed. The error is: Could not load file or assembly 'TestProject' or one of its dependencies. The system cannot find the file specified.
(C:\Source\TestIoC\src\TestIoC\TestProject\bin\Debug\TestProject.vshost.exe.config line 14)
This is inside a WPF Application project.
What is the correct syntax to refer to the Assembly you are currently in? is there a way to do this? I know in a larger solution I would be pulling Types from seperate assemblies so this might not be an issue. But what is the right way to do this for a small self-contained test project. Note: I'm only interested in doing the XML config at this time, not the C# (in code) config.
UPDATE: see all comments
My XML config:
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>
<unity>
<typeAliases>
<!-- Lifetime manager types -->
<typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />
<typeAlias alias="external" type="Microsoft.Practices.Unity.ExternallyControlledLifetimeManager, Microsoft.Practices.Unity" />
<typeAlias alias="IDataAccess" type="TestProject.IDataAccess, TestProject" />
<typeAlias alias="DataAccess" type="TestProject.DataAccess, TestProject" />
</typeAliases>
<containers>
<container name="Services">
<types>
<type type="IDataAccess" mapTo="DataAccess" />
</types>
</container>
</containers>
</unity>
</configuration>
In unity 5.7
The section line should be like this
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Unity.Configuration" />
This looks fine. Are you sure your assembly name is correct? Check the project preferences to make sure the name of your assembly is correct:
Right click your project and click Properties
Click on the Application tab on the left
Look at the value of the "Assembly Name" field.
Sometimes if you've renamed your project, this field will still be the old value.
It's possible that this is not the issue at all, but it is the simplest thing to check. If you find that this is not the issue, reply to this and I'll post any other ideas I have.
Also, you might consider posting your sample as a .zip file so we can take a look at it.
I just had the same issue. this works for me :
Turn "Copy local" to true in the properties of Microsoft.Practices.Unity.
You should also add a reference to Microsoft.Practices.ObjectBuilder2 (Microsoft.Practices.Unity depends of it)