How do you use RegisterFactory? - unity-container

I am having problems understanding how to use RegisterFactory. The code below works fine with the older InjectionFactory but I am having problems when I try to do the same thing with RegisterFactory.
In the sample code there is an uncommented section that uses RegisterFactory and a commented section that uses InjectionFactory. The InjectionFactory code works fine but the RegisterFactory throws an ResolutionFailedException.
Unity.ResolutionFailedException: 'The current type, ConsoleApp1.IFoo, is an interface and cannot be constructed. Are you missing a type mapping?
What am I doing incorrectly?
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
container.EnableDebugDiagnostic();
container.RegisterType<IFoo, Foo1>("Foo1");
container.RegisterType<IFoo, Foo2>("Foo2");
container.RegisterType<MainViewModel>();
// This does not work
container.RegisterFactory<Func<string, IFoo>>((c, type, name) => c.Resolve<IFoo>(name));
// This works
//container.RegisterType<Func<string, IFoo>>(new InjectionFactory(
// ctx => new Func<string, IFoo>(name => container.Resolve<IFoo>(name))));
var vm = container.Resolve<MainViewModel>();
}
}
public class MainViewModel
{
public MainViewModel(Func<string, IFoo> fooFactory)
{
var foo1 = fooFactory.Invoke("Foo1");
var foo2 = fooFactory.Invoke("Foo2");
}
}
public interface IFoo
{
string Name { get; }
}
public class Foo1 : IFoo
{
public string Name { get; set; }
public Foo1()
{
Name = "Foo1";
}
}
public class Foo2 : IFoo
{
public string Name { get; set; }
public Foo2()
{
Name = "Foo2";
}
}

If you're registering with RegisterFactory, you tell Unity how to construct the instance. But Unity already knows how to construct Foo1 and Foo2, because you registered those already.
What you want is a factory for you to use, that's what RegisterType does, so this works.
Normally, such a factory would implement some IFooFactory, thus making the context more obvious. But as long as Func<string, IFoo> is registered only used once, it works fine, too, of course.

Related

Create Singleton instance in MEF2

I'm creating an application with multiple plugins using MEF2 (Microsoft.Composition). These plugins should import some common object and they should all share the same instance of this object... so a typical Singleton.
However, when I [Import] this common object into my plugins they all get their own copy instead of a shared one.
In .NET Framework MEF1, all object were created as singletons by default. This does not seem to be the case for .NET Core MEF2.
How can I make sure that all my plugins get the same singleton instance of my common object?
Sample code
Startup
static void Main(string[] args) {
ContainerConfiguration containerConfig = new ContainerConfiguration()
.WithAssembly(Assembly.GetExecutingAssembly())
.WithAssembly(typeof(ICommonObject).Assembly);
using (CompositionHost container = containerConfig.CreateContainer()) {
_mainApp = container.GetExport<MainApp>();
_mainApp.Start();
}
}
MainApp
[Export(typeof(MainApp))]
public class MainApp {
[Import] public ICommonObject CommonObject { get; set; }
[ImportMany] public IEnumerable<IPlugin> Plugins { get; set; }
public void Start() {
CommonObject.SomeValue = "foo";
Console.WriteLine("SomeValue (from MainApp): " + CommonObject.SomeValue);
foreach (IPlugin plugin in Plugins) {
plugin.Start();
}
}
}
Plugin
[Export(typeof(IPlugin))]
public class SomePlugin : IPlugin {
[Import] public ICommonObject CommonObject { get; set; }
public void Start() {
Console.WriteLine("SomeValue (from plugin): " + CommonObject.SomeValue);
}
}
Output
SomeValue (from MainApp): foo
SomeValue (from plugin):
After much trial and error I seem to have finally found a solution myself.
The trick seems to be to use ConventionBuilder. This has an extension method called .Shared() which makes all objects derived from a specific type into a Singleton.
For my code examples, just add the following to the top of the Startup code:
ConventionBuilder conventions = new ConventionBuilder();
conventions.ForTypesDerivedFrom<ICommonObject>()
.Export<ICommonObject>()
.Shared();
ContainerConfiguration containerConfig = new ContainerConfiguration()
.WithAssembly(Assembly.GetExecutingAssembly(), conventions);
For some reason, the object implementing ICommonObject doesn't even need an [Export] attribute. In any case, the output from the example is now:
SomeValue (from MainApp): foo
SomeValue (from plugin): foo

BuildUp method in unity doesn't consider MappingName

I have a strange problem with unity BuildUp method. I have one interface that's mapped to three classes. I have given a name to each mapping.
Now I need to inject the dependency in an existing object (it's an attribute so I don't have control over lifetime). I call the BuildUp method to inject the dependency, but it always throws an exception which says that the interface is not mapped.
If I map the interface to one type only and I remove the mappingname, the BuildUp method works.
If I map the interface to one type only and I specify the mappingname, the BuildUp method fail.
I have tried registering types in configuration and code and nothing changes.
I suspect this is a bug, but I would like to know if anyone else has another idea.
This is how i call buildup method:
var newAttr = _container.BuildUp(myAttribute.GetType(), myAttribute, "Mapping1");
I tried to follow your scenario and this sample works
var container = new UnityContainer();
container.RegisterType<IFoo, One>("1", new InjectionProperty("Bar", "1"));
container.RegisterType<IFoo, Two>("2", new InjectionProperty("Bar", "2"));
container.RegisterType<IFoo, Three>("3", new InjectionProperty("Bar", "3"));
One one = new One();
container.BuildUp(one.GetType(), one, "1");
Assert.AreEqual("1", one.Bar);
public interface IFoo
{
string Bar { get; set; }
}
public class One : IFoo
{
public string Bar { get; set; }
}
public class Two : IFoo
{
public string Bar { get; set; }
}
public class Three : IFoo
{
public string Bar { get; set; }
}
Update
var container = new UnityContainer();
container.RegisterType<Person>(new InjectionProperty("Foo"));
container.RegisterType<IFoo, One>("1");
container.RegisterType<IFoo, Two>("2");
container.RegisterType<IFoo, Three>("3");
Person person = container.Resolve<Person>("1");
Assert.IsNotNull(person.Foo);
Assert.IsInstanceOfType(person.Foo, typeof(One));
public class Person
{
public IFoo Foo { get; set; }
}
I guess this is what you mean? Short answer: That's not the way Unity works.
Long answer: You will have to specify a ResolverOverride that does that for you. But even that is not enough as you want the container to create the value you want to inject for you. So you would need to specify a ResolvedParameter as the value for your ResolverOverride. With Unity's out-of-the-box parts the Resolve would look like this
Person person = container.Resolve<Person>(new PropertyOverride("Foo", new ResolvedParameter(typeof(IFoo), "1")));
Or you can use this custom override instead
public class NamedPropertyOverride : ResolverOverride
{
private readonly string propertyName;
private readonly string registrationName;
public NamedPropertyOverride(string propertyName, string registrationName)
{
this.propertyName = propertyName;
this.registrationName = registrationName;
}
public override IDependencyResolverPolicy GetResolver(IBuilderContext context, Type dependencyType)
{
var currentOperation = context.CurrentOperation as ResolvingPropertyValueOperation;
if (currentOperation != null &&
currentOperation.PropertyName == this.propertyName)
{
Type propertyType = currentOperation
.TypeBeingConstructed
.GetProperty(currentOperation.PropertyName, BindingFlags.Instance | BindingFlags.Public)
.PropertyType;
return new NamedTypeDependencyResolverPolicy(propertyType, this.registrationName);
}
return null;
}
}
Change the line that contains the call to Resolve in the above sample to this one
Person person = container.Resolve<Person>(new NamedPropertyOverride("Foo", "1"));
That should do the trick.

Moq: Return mock object with most implementation created

I want to mock my Repository object in such a way that it can still do actual DB retrieve operations. Only for Saving operations, I wanted to setup to return mock data since I don't want it to save into the DB.
How should I do it?
Thanks.
Maybe you should make your Save operation virtual and override it in a subclass which you use in your tests rather than using Moq?
First of all, your unit tests should never actually go out to the database (it is all right for integration tests, but that is a larger topic). What you want to do is pretty straightforward with Moq, though:
public class MyRepo
{
public virtual string Save(MyClass foo)
{
// perform save...
}
}
public class MyService
{
public MyRepo Repo { get; set; }
public string VerifyAndSave(MyClass foo)
{
// verify foo...
return new Repo.Save(foo);
}
}
public class MyClass()
{
public string SomeData { get; set; }
}
Notice the virtual modifiers on the methods--these are important for Moq to be able to stub them.
In your tests you could then do something like this:
[TestClass]
public class SomeTests
{
private Mock<MyRepo> MockRepo { get; set; }
private MyService Target { get; set; }
[TestInitialize]
public void Setup()
{
MockRepo = new Mock<MyRepo>();
Target = new MyService();
Target.Repo = MockRepo.Object;
}
[TestMethod]
public void MyTest()
{
const string expectedOutput = "SAVED";
MyClass exampleData = new MyClass();
MockRepo.Setup(x => x.Save(It.IsAny<MyClass>())).Returns(expectedOutput);
Target.VerifyAndSave(exampleData);
MockRepo.Verify(x => x.Save(It.IsAny<MyClass>()));
}
}
The chained calls of Setup and Returns in this case would guarantee that the calling method (i.e. VerifyAndSave) would see the value that you specified--"SAVED" in this case.
For more examples, take a look at the Moq quickstart docs.

Mocking ChildProperty cannot get it to work?

I am trying to test a property that is nested in a child class.
I always get an error.
Am I missing something?
Is it possible to test a child property in moq.
I have the following
[Test]
public void Should_be_able_to_test_orderCollection()
{
var orderViewMock = new Mock<IOrderView>();
orderViewMock.SetupGet(o => o.Customer.OrderDataCollection.Count).Returns(2);
orderViewMock.SetupSet(o => o.Customer.OrderDataCollection[1].OrderId = 1);
orderViewMock.VerifySet(o => o.Customer.OrderDataCollection[1].OrderId=1);
}
public class CustomerTestHelper
{
public static CustomerInfo GetCustomer()
{
return new CustomerInfo
{
OrderDataCollection = new OrderCollection
{
new Order {OrderId = 1},
new Order {OrderId = 2}
}
};
}
}
public class CustomerInfo
{
public OrderCollection OrderDataCollection { get; set; }
}
public class OrderCollection:List<Order>
{
}
public class Order
{
public int OrderId { get; set; }
}
public interface IOrderView
{
CustomerInfo Customer { get; set; }
}
You can't mock the OrderDataCollection property of CustomerInfo because it's a non-virtual property on a concrete class.
The best way to fix this would be to extract an interface from CustomerInfo and let IOrderView return that instead:
public interface IOrderView
{
ICustomerInfo Customer { get; set; }
}
It is definitely possible if you have the right abstractions. You need to mock your Customer and its children too, for your example to work, like:
var customerMock = new Mock<ICustomer>();
orderViewMock.SetupGet(o => o.Customer).Returns(customerMock.Object);
etc. for the entire hierarchy of child objects you want to control with mocks. Hope it makes sense.
/Klaus
You will get a runtime error, as you've found:
System.ArgumentException: Invalid setup on a non-overridable member:
o => o.Customer.OrderDataCollection.Count
at Moq.Mock.ThrowIfCantOverride(Expression setup, MethodInfo methodInfo)
You can mock the IOrderView and return any CustomerInfo instance you want, but you're also trying to mock CustomerInfo and OrderCollection. As Mark Seemann mentioned, you can only mock interfaces and virtual properties/methods. This will hold true for almost any mocking/isolation framework except for Typemock (commercial).
As others have already stated, one way to solve the problem is to return an interface for the customer.

IOC with multiple databases that use same interface (StructureMap or any other DI Framework)

We've been experimenting with StructureMap, and I'm having trouble grasping how to handle situations where a single interface has multiple implementations. The code below shows an example where we have two databases that are both accessible from a single service.
public class SomeController : Controller
{
private ISomeService _service;
private IClientRepository _repository;
protected IContext _masterContext;
protected IContext _clientContext;
public SomeController(ISomeService service, ISomeRepository repository
, IContext masterCon, IContext clientCon)
{
_service = service;
_repository = repository;
_masterContext = masterCon;
_clientContext = clientCon;
}
}
public class SomeService : ISomeService
{
private IContext _masterContext;
private IContext _clientContext;
public SomeService(IContext masterContext, IContext clientContext)
{
masterContext = _masterContext;
clientContext = _clientContext;
}
}
public class ClientRepository : IClientRepository
{
private IContext _clientContext;
public ClientRepository(IContext clientContext)
{
_clientContext = clientContext;
}
}
public class MasterContext : IContext
{
public MasterContext(String connString)
//<snip, snip> implement 3rd party data context
}
public class ClientContext : IContext
{
public ClientContext(String connString)
//<snip, snip> implement 3rd party data context
}
StructureMap worked GREAT when we had a single context (database), but how do I tell it how to resolve the 2nd? Note: in most situations we wouldn't have a service handling 2 databases (but may have a controller handling 2 connections, i.e. 2 repositories accessing 2 different databases), but it still doesn't seem to make it easier.
I'm half ready to just give up on using an IoC framework and go back to poor man's DI.
Is it not possible to have an IClientContext and an IMasterContext, possibly inheriting from IContext. My feeling is that the code would be doing one of two very different things depending on whether you were talking to the 'Master' or 'Client' database.
In Unity you can have named registrations, allowing you to effectively register more than a class for a given interface. So you could do (typing by heart, check the actual Unity documentation if interested):
container.RegisterType<IContext, MasterContext>("Master");
container.RegisterType<IContext, ClientContext>("Client");
and then the constructor for SomeService would be:
public SomeService(
[Dependency("Master")]IContext masterContext,
[Dependency("Client")]IContext clientContext)
{
//...
}
The drawback is that in this way your service class is no longer independent of the DI framework used, but depending on the project that may be ok.
This can be a little difficult if you're relying on StructureMap to resolve the dependencies automatically. The first solution (and what I'd err towards) is to make use of marker interfaces like Richard mentions in his answer then just register them. You can then explicitly specify whether you want your client or master context there.
The second way is to make use of named registrations, then specify the constructor params explicitly.
ForRequestedType<IContext>().AddInstances(
i => {
i.OfConcreteType<ClientContext>().WithName("Client");
i.OfConcreteType<MasterContext>().WithName("Master");
});
ForRequestedType<SomeController>().TheDefault.Is.ConstructedBy(
i => new SomeController(i.GetInstance<ISomeService>(),
i.GetInstance<IClientRepository>(),
i.GetInstance<IContext>("Master"),
i.GetInstance<IContext>("Client")));
Not particularly nice but it does the job and ultimately if it's only in one or two places it might be OK.
If you want to resolve differently on namespace / assembly you could try something like this:-
ForRequestedType<IContext>().AddInstances(
i => {
i.OfConcreteType<ClientContext>().WithName("Client");
i.OfConcreteType<MasterContext>().WithName("Master");
}).TheDefault.Is.Conditional(c => {
c.If(con => con.ParentType.Namespace.EndsWith("Client"))
.ThenIt.Is.TheInstanceNamed("Client");
c.If(con => con.ParentType.Namespace.EndsWith("Master"))
.ThenIt.Is.TheInstanceNamed("Master");
c.TheDefault.Is.OfConcreteType<ClientContext>();
});
Where the predicate on ParentType can refer to Assembly (or whatever you want really)
In case someone stumble in this problem, you can achieve it using factory pattern.
Service extension
public static class ServiceFactoryExtensions
{
public static void RegisterSqlFactory(this IServiceCollection serviceCollection)
{
serviceCollection.Configure<MsSqlOption>(option => option.ConnectionString = "Mssql connection string");
serviceCollection.Configure<MySqlOption>(option => option.ConnectionString = "Mysql connection string");
serviceCollection.Configure<PostgreOption>(option => option.ConnectionString = "Postgrel connection string");
serviceCollection.AddSingleton<ISqlDatabase, MsSql>();
serviceCollection.AddSingleton<ISqlDatabase, Postgre>();
serviceCollection.AddSingleton<ISqlDatabase, MySql>();
serviceCollection.AddSingleton<Func<IEnumerable<ISqlDatabase>>>(serviceProvider => () => serviceProvider.GetService<IEnumerable<ISqlDatabase>>());
serviceCollection.AddSingleton<ISqlDatabaseFactory, SqlDatabaseFactory>();
}
}
Factory class
public class SqlDatabaseFactory : ISqlDatabaseFactory
{
private readonly Func<IEnumerable<ISqlDatabase>> _factory;
public SqlDatabaseFactory(Func<IEnumerable<ISqlDatabase>> factory)
{
_factory = factory;
}
public ISqlDatabase CreateSql(SqlType sqlType)
{
var databases = _factory();
var sqlDatabase = databases.FirstOrDefault(x => x.DatabaseName == sqlType);
if (sqlDatabase == null)
throw new NotImplementedException($"Sql type {nameof(sqlType)} is not implemented");
return sqlDatabase;
}
}
Sql classes
public class MsSql : ISqlDatabase
{
public SqlType DatabaseName => SqlType.MsSql;
public string Connecionstring { get; private set; }
public MsSql(IOptions<MsSqlOption> option)
{
Connecionstring = option.Value.ConnectionString;
}
}
public class Postgre : ISqlDatabase
{
public SqlType DatabaseName => SqlType.Postgre;
public string Connecionstring { get; private set; }
public Postgre(IOptions<PostgreOption> option)
{
Connecionstring = option.Value.ConnectionString;
}
}
public class MySql : ISqlDatabase
{
public SqlType DatabaseName => SqlType.MySql;
public string Connecionstring { get; private set; }
public MySql(IOptions<MySqlOption> option)
{
Connecionstring = option.Value.ConnectionString;
}
}
public interface ISqlDatabase
{
string Connecionstring { get; }
SqlType DatabaseName { get; }
}
public enum SqlType
{
MsSql,
Postgre,
MySql
}
Usage
internal class Program
{
static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.RegisterSqlFactory();
var provider = serviceCollection.BuildServiceProvider();
var sqlFactory = provider.GetService<ISqlDatabaseFactory>();
var mySql = sqlFactory.CreateSql(SqlType.MySql);
var msSql = sqlFactory.CreateSql(SqlType.MsSql);
var postgre = sqlFactory.CreateSql(SqlType.Postgre);
Console.WriteLine($"Database Type : {mySql.DatabaseName}, Connectionstring: {mySql.Connecionstring}");
Console.WriteLine($"Database Type : {msSql.DatabaseName}, Connectionstring: {msSql.Connecionstring}");
Console.WriteLine($"Database Type : {postgre.DatabaseName}, Connectionstring: {postgre.Connecionstring}");
Console.ReadKey();
}
}
Output
Dependencies:
.Net Core 3.1
Microsoft.Extensions.DependencyInjection;
Microsoft.Extensions.Options;
System
System.Collections.Generic
System.Linq;

Resources