I am trying to swap a nested dependency when resolving a specific instance using StructureMap. In 2.x I was able to do this with the following UseSpecial code, but it does not work in 3.x
The code is basically saying... when requesting an instance of IObject, swap the default instance for ITwo with AnotherTwo which is a dependency of IObject's dependency.
public class MyStructureMapRegistry : Registry
{
public MyStructureMapRegistry()
{
For<IObject>().UseSpecial(cfg => cfg.ConstructedBy(x =>
{
x.RegisterDefault(typeof(ITwo), x.GetInstance<AnotherTwo>());
return x.GetInstance<DependsOnOne>();
}));
}
}
The following is the sample object graph that I am trying to wire up.
public interface IObject { }
public interface IOne { }
public interface ITwo { }
public class DependsOnOne : IObject
{
IOne _one;
public DependsOnOne(IOne one)
{
_one = one;
}
}
public class DependsOnTwo : IOne
{
ITwo _two;
public DependsOnTwo(ITwo two)
{
_two = two;
}
}
public class Two : ITwo { }
public class AnotherTwo : ITwo { }
Related
I am having a difficult time figuring out how to create a 1:1 mapping between objects in a container using AutoFac. I am getting resolution errors and the documentation is too terse with not enough examples.
Here's the rule I would like to use to resolve my dependencies:
An IHouse object can only be constructed using an IDoor parameter of a specific concrete type, creating a 1:1 mapping between IHouse and IDoor types.
As am example, using the code below, if I resolve the container using a MonkeyDoor, it should give me back a fully constructed MonkeyHouse and only a MonkeyHouse object.
[TestClass]
public class HousingDeveloperTest
{
[TestMethod]
public void TestMethod1()
{
// Load them from an assembly or disc. We are interested in IHouse and IDoor types
var builder = new ContainerBuilder();
// Get all the houses
var assembly = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.EndsWith(nameof(House))).AsImplementedInterfaces();
// get all the doors
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.EndsWith(nameof(Door))).AsImplementedInterfaces();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var house = container.Resolve<IDoor>(new TypedParameter(typeof(MonkeyDoor), new MonkeyDoor()));
}
}
}
public interface IDoor
{
void Open();
}
public abstract class Door : IDoor
{
public void Open()
{
Trace.WriteLine($"Opening {GetType().ToString()}.");
}
}
// Only works with Victorian homes
public class VictorianDoor : Door
{
}
// Only works with Craftsman homes
public class CraftsmanDoor : Door
{
}
// Only works with monkey homes
public class MonkeyDoor : Door
{
}
public interface IHouse
{
void OpenHouse();
}
public abstract class House : IHouse
{
public IDoor Door;
protected House(IDoor door)
{
Door = door;
Trace.WriteLine($"Building this {this.GetType()} with {door.GetType()} door.");
}
public void OpenHouse()
{
Trace.WriteLine($"We're having an open house on this wonderful {this.GetType().ToString()}.");
Door.Open();
}
}
// Doors must match the homes. (i.e. No monkey doors on a Victorian or Craftsman home.)
public class VictorianHouse : House
{
public VictorianHouse(VictorianDoor door) : base(door)
{
}
}
public class CraftsmanHouse : House
{
public CraftsmanHouse(CraftsmanDoor door) : base(door)
{
}
}
public class MonkeyHouse : House
{
public MonkeyHouse(MonkeyDoor door) : base(door)
{
}
}
In autoFac, I can register multiple implementation of an interface. When autofac instantiates my object, all instances are passed to the constructor.
From autofac’s documentation: here
For example, when Autofac is injecting a constructor parameter of type
IEnumerable it will not look for a component that supplies
IEnumerable. Instead, the container will find all
implementations of ITask and inject all of them.
Is this functionality available in StructureMap?
For my classes:
public interface IFoo
{
}
public class Foo1 : IFoo
{
}
public class Foo2 : IFoo
{
}
public class UsingFoo
{
public UsingFoo(IEnumerable<IFoo> allFoos)
{
foreach (var foo in allFoos)
{
}
}
}
How do I register my implementations, so that when UsingFoo is instantiated, the constructor will be passed all implementations of IFoo?
In StructureMap you can do:
ObjectFactory.Intialize(x => x.Scan(y => y.AddAllTypesOf<IFoo>()));
That will register all types of IFoo
Then when you resolve UsingFoo, they will be injected.
Edit:
I just quickly wrote this up in a console app:
ObjectFactory.Initialize(x =>
{
x.Scan(y =>
{
y.AddAllTypesOf<IFoo>();
});
});
var usingFoo = ObjectFactory.GetInstance<UsingFoo>();
Edit:
You made me doubt myself, so I double checked.
It works fine.
Here's a working example I quickly wrote in a console app:
public interface IFoo
{
string Text { get; }
}
public class Foo1 : IFoo
{
public string Text
{
get { return "This is from Foo 1"; }
}
}
public class Foo2 : IFoo
{
public string Text
{
get { return "This is from Foo 2"; }
}
}
public class Bar
{
private readonly IEnumerable<IFoo> _myFoos;
public Bar(IEnumerable<IFoo> myFoos)
{
_myFoos = myFoos;
}
public void Execute()
{
foreach (var myFoo in _myFoos)
{
Console.WriteLine(myFoo.Text);
}
}
}
class Program
{
static void Main(string[] args)
{
ObjectFactory.Initialize(x =>
{
x.UseDefaultStructureMapConfigFile = false;
x.Scan(y =>
{
y.TheCallingAssembly();
y.AddAllTypesOf<IFoo>();
});
});
var myBar = ObjectFactory.GetInstance<Bar>();
myBar.Execute();
Console.WriteLine("Done");
Console.ReadKey();
}
}
The output is:
This is from Foo 1
This is from Foo 2
Done
I have successfully setup a simple mvc application that lists teams. I'm using Ninject to inject the appropriate repository depending on the controller (thanks to stack overflow ;). All looks good, except that the repository code looks exactly the same. And I know that's wrong. So my TeamRepository has two classes (for now).
public class SwimTeamRepository : ITeamRepository<SwimTeam>
{
private readonly Table<SwimTeam> _teamTable;
public SwimTeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<SwimTeam>());
}
public IQueryable<SwimTeam> Team
{
get { return _teamTable; }
}
}
public class SoccerTeamRepository : ITeamRepository<SoccerTeam>
{
private readonly Table<SoccerTeam> _teamTable;
public SoccerTeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<SoccerTeam>());
}
public IQueryable<SoccerTeam> Team
{
get { return _teamTable; }
}
}
They look exactly the same except for the Class and Table name, so clearly I need to re-factor this. What would be the best approach here? Singleton? Factory Method?
Thanks in advance!
You could use generics:
public interface ITeamRepository<T>
{
}
public class TeamRepository<TTeam> : ITeamRepository<TTeam>
where TTeam : Team
{
private readonly Table<TTeam> _teamTable;
public TeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<TTeam>());
}
public IQueryable<TTeam> Team
{
get { return _teamTable; }
}
}
public class Team
{
}
public class SwimTeam : Team
{
}
Then use it like so...
public void MyMethod()
{
var repository = new TeamRepository<SwimTeam>();
}
...and set up your IoC container w/ Ninject like so...
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<ITeamRepository<SwimTeam>>
.To<TeamRepository<SwimTeam>>();
}
}
public void MyMethod()
{
var repository = kernel.Get<ITeamRepository<SwimTeam>>();
}
If you want to get REAL generic and have a single repository for ALL of your mapped classes, you can do something like this:
public interface IRepository
{
IQueryable<T> Get<T>() where T : class, new();
}
public class Repository : IRepository, IDisposable
{
private DataContext _dataContext;
public Repository(string connectionString)
{
_dataContext = new DataContext(connectionString);
}
public IQueryable<T> Get<T>()
where T : class, new()
{
return _dataContext.GetTable<T>().AsQueryable();
}
public void Dispose()
{
if (_dataContext != null)
{
_dataContext.Dispose();
_dataContext = null;
}
}
}
...which you could call like so (after setting up your Ninject container)...
using (var repository = kernel.Get<IRepository>())
{
var swimTeam = repository.Get<SwimTeam>();
}
Since Ninject takes care of the life-cycle management of your objects, you don't HAVE to wrap the repository in a using statement. In fact, you don't want to use a using statement there at all if you plan to use the repository more than once within the scope of its lifetime. Ninject will automatically dispose of it when it's life-cycle ends.
Here's a good article by Rob Conery on using this kind of technique to reduce the friction of using different ORMs.
EDIT by keeg:
I Think
public class TeamRepository<TTeam> : ITeamRepository<TTeam> where TTeam : Team {}
Should be
public class TeamRepository<TTeam> : ITeamRepository<TTeam> where TTeam : class {}
Please correct if I'm wrong.
Is this what you want?
public class TeamRepository : ITeamRepository<T>
{
private readonly Table<T> _teamTable;
public TeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<T>());
}
public IQueryable<T> Team
{
get { return _teamTable; }
}
}
If I have the following, and I were to say ObjectFactory.GetInstance<Master>() is it possible to tell StructureMap to make the I_A instance to A_User the same instance as the I_A passed to Master?
public interface I_A { }
public interface I_B { }
public class A_User {
public A_User(I_A A) { }
}
public class Master {
public Master(I_A _, I_B __, A_User ___) { }
}
The default behavior of StructureMap will always give you the same instance within a "build session" (effectively, a single call to GetInstance). You should not have to configure anything extra to get the behavior you want.
If it is not working as you expect, please post more details, or mention it on the StructureMap mailing list.
UPDATED:
As #Joshua Flanagan points out below, this is default SM behaviour. The following unit tests show that. The first tests uses the default behaviour. The second shows how you would get a unique instance if you wanted it:
using System;
using System.Collections.Generic;
using NUnit.Framework;
using StructureMap;
using StructureMap.Pipeline;
namespace SMTest
{
[TestFixture]
public class TestSOQuestion
{
class Foo : IFoo { }
interface IFoo { }
private interface IBar {
IFoo Foo { get; set; }
}
class Bar : IBar
{
public IFoo Foo { get; set; }
public Bar(IFoo foo)
{
Foo = foo;
}
}
class UsesFooAndBar
{
public IBar Bar { get; set; }
public IFoo Foo { get; set; }
public UsesFooAndBar(IFoo foo, IBar bar)
{
Foo = foo;
Bar = bar;
}
}
[Test]
public void TestOtherAnswer()
{
IContainer container = new Container(x =>
{
x.For<IFoo>().Use<Foo>();
x.For<IBar>().Use<Bar>();
});
var usesFooAndBar = container.GetInstance<UsesFooAndBar>();
Assert.AreSame(usesFooAndBar.Foo, usesFooAndBar.Bar.Foo);
}
[Test]
public void TestNonDefaultBehaviour()
{
IContainer container = new Container(x =>
{
x.For<IFoo>().AlwaysUnique().Use<Foo>();
x.For<IBar>().Use<Bar>();
});
var usesFooAndBar = container.GetInstance<UsesFooAndBar>();
Assert.AreNotSame(usesFooAndBar.Foo, usesFooAndBar.Bar.Foo);
}
}
}
i have a generic interface
public interface IDomainDataRepository<T>
{
T[] GetAll();
}
with a generic implementation
public class DomainDataRepository<T> : IDomainDataRepository<T>
{
public virtual T[] GetAll()
{
return GetSession().Linq<T>().ToArray();
}
}
how do I register it in StructureMap so that if I request IDomainDataRepository<State> then it will new up a DomainDataRepository<State>. Furthermore if I decide to implement a CountryDomainDataRepository and I request a IDomainDataRepository<Country> I want to get the specific implementation.
public class CountryDomainDataRepository : IDomainDataRepository<State>
{
public virtual Country[] GetAll()
{
return GetSession().Linq<Country>().ToArray();
}
}
You can accomplish this by configuring the generic open type to use a concrete open type:
[TestFixture]
public class open_generic_registration
{
[Test]
public void should_resolve_to_the_configured_concrete_instance_of_T()
{
var container = new Container(cfg =>
{
cfg.For(typeof (IDomainDataRepository<>)).Use(typeof (DomainDataRepository<>));
});
container.GetInstance<IDomainDataRepository<string>>().ShouldBeOfType<DomainDataRepository<string>>();
container.GetInstance<IDomainDataRepository<int>>().ShouldBeOfType<DomainDataRepository<int>>();
container.GetInstance<IDomainDataRepository<DateTime>>().ShouldBeOfType<DomainDataRepository<DateTime>>();
}
}