How to link Autofac to UnitTesting - c#

Within my Web API I have linked Autofac as IoC container, and I do it like this:
Domain level
public class Autofac
{
protected ContainerBuilder Builder { get; set; }
public Autofac()
{
this.Builder = new ContainerBuilder();
}
public virtual IContainer Register()
{
// Register dependencies
SetUpRegistration(this.Builder);
// Build registration.
var container = this.Builder.Build();
// End
return container;
}
private static void SetUpRegistration(ContainerBuilder builder)
{
// === DATALAYER === //
// MyRepository
builder.RegisterType<MyRepository>()
.As<IMyRepository>()
.InstancePerLifetimeScope();
// === DOMAIN === //
// MyManager
builder.RegisterType<MyManager>()
.As<IMyManager>()
.InstancePerLifetimeScope();
}
}
Web API
public class Autofac : Domain.IoC.Autofac
{
public IContainer Register(HttpConfiguration config)
{
// Register your Web API controllers.
base.Builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// OPTIONAL: Register the Autofac filter provider.
base.Builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
// Complete registration and get container instance.
var container = base.Register();
// Set the dependency resolver to be Autofac.
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// Done.
return container;
}
}
As you see it inherits from the base class from Domain and sets up Web API specific config.
Usage
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
new IoC.Autofac().Register(GlobalConfiguration.Configuration);
}
Which is at global.asax, as you know.
The question
This works fine for Web API, but I haven't got a clue what I need to do to register all this within a UnitTest project context.
The idea is that I would create a similar implementation to the Autofac class at Web API level, but than with mocks (completely ignoring the base class from Domain).
Any pointers?

Personally I never see the need (and I struggle to comprehend how viable or helpful it would be) to setup my IoC container directly within a unit test.
As a unit test is used to test a logical piece of code that can be quickly built, easily ran and doesn't require much (I'd advocate no) tear-down. It should not require all of your application to be be setup for the test to run.
Remember that your unit test is simply testing the flow of data through the system i.e that your DomainManager is actually going to call a IRepository when you expect that it should. Then you would have separate test classes for all your repositories to determine that they would correctly add to the database etc.
I'm not sure how you use the DBContext class but as an example of a wrapper this is what it would sort of look like.
interface IDBSetWrapper
{
object Add(object entity);
}
interface IDBContextWrapper
{
...
IDBSet Set(Type entityType);
...
}
class DBContextWrapper : IDBContextWrapper
{
private readonly DBContext context;
public DBContextWrapper()
{
context = new DBContext();
}
...
public IDBSet Set(Type entityType)
{
var dbSet = context.Set(entityType);
return new DBSetWrapper(dbSet);
}
...
}
It's not much but I hope that it demonstrates what I mean about a thin wrapper. Basically the wrapper is the DBContext and will contain an instance of it within the class, the actual DBContext will be called when you request the wrapper to do anything.
I have shown what would happen when returning another object (in this case a DBSet), this will also be wrapped in a separate object with an interface. This is so that you can mock the returns from this class easily.
You can add this new wrapper into your IoC a little better now as it provides an interface.
One thing to note is that you won't be able to and probably wouldn't wish to test the wrapper class, there would be very little point as I see it. But previously I've seen colleagues do an integration test on these sort of classes.

Related

ASP.NET Core DI based on requesting type

How do I configure dependency injection in ASP.NET Core to return a certain instance depending on the type it's being injected into?
Let's say I have a simple interface,
public interface IHello
{
string SayHello();
}
And two different implementations:
public class Hello : IHello
{
public string SayHello() => "Hello...";
}
public class Hey : IHello
{
public string SayHello() => "HEY!";
}
And finally I have a few classes that all depend on an instance of IHello:
public class Class1
{
public Class1(IHello hello)
{
}
}
public class Class2
{
public Class2(IHello hello)
{
}
}
Now, in ConfigureServices I would do something like this:
services.AddSingleton<IHello, Hello>();
to configure any class depending on IHello to always get the same instance of Hello.
BUT: What I really want is for Class1 to always get the same singleton instance of Hey and all other classes should just get an instance of Hello. It could look like this in ConfigureServices (doesn't work, obviously):
services.AddSingleton<IHello, Hello>();
services.AddSingleton<IHello, Hey, Class1>(); // Doesn't work, but would be neat if it did...
Here's a simple approach. It lacks a certain elegance, but it will do what you need:
public static void Register(IServiceCollection serviceCollection)
{
serviceCollection.AddSingleton<Hello>();
serviceCollection.AddSingleton<Hey>();
serviceCollection.AddSingleton<ClassThatDependsOnIHello1>(serviceProvider =>
new ClassThatDependsOnIHello1(serviceProvider.GetService<Hello>()));
serviceCollection.AddSingleton<ClassThatDependsOnIHello2>(serviceProvider =>
new ClassThatDependsOnIHello2(serviceProvider.GetService<Hey>()));
}
There are two classes that depend on IHello. The registration for each of them includes a function. That function resolves either Hello or Hey from the service provider and passes it to the constructor of each respective class. That way you get control over which implementation gets passed to which class.
(It's beside the point that the service provider hasn't been built yet. The function you're providing will be executed later, and the service provider passed to it will be the one that has been built from the service collection.)
A downside to this is that now your DI registration explicitly calls your constructors. That can be a nuisance because if the constructors change (maybe you inject other dependencies) then you'll have to edit this code. That's not great, but it's not uncommon.
Plan B would be to do as Microsoft suggests and use another container.
Autofac
First, add the Autofac.Extensions.DependencyInjection NuGet package. This references Autofac and also provides the extensions needed to add an Autofac container to a service collection.
I've arranged this to focus on the way dependencies get registered with Autofac. It's similar to IServiceCollection and IServiceProvider. You create a ContainerBuilder, register dependencies, and then build a Container from it:
static void RegisterDependencies(this ContainerBuilder containerBuilder)
{
containerBuilder.RegisterType<Hello>().Named<IHello>("Hello");
containerBuilder.RegisterType<Hey>().Named<IHello>("Hey");
containerBuilder.RegisterType<ClassThatDependsOnIHello1>().WithParameter(
new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(IHello),
(parameter, context) => context.ResolveNamed<IHello>("Hello")
));
containerBuilder.RegisterType<ClassThatDependsOnIHello2>().WithParameter(
new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(IHello),
(parameter, context) => context.ResolveNamed<IHello>("Hey")
));
}
That's not really pretty either, but it sidesteps the problem of calling the constructors.
First it registers two implementations of IHello and gives them names.
Then it registers the two classes that depend on IHello. WithParameter(new ResolvedParameter()) uses two functions:
The first function determines whether a given parameter is the one we want to resolve. So in each case we're saying, "If the parameter to resolve is IHello, then resolve it using the next function."
It then resolves IHello by specifying which named registration to use.
I'm not excited by how complicated that is, but it does mean that if those classes have other dependencies injected, they'll be resolved normally. You can resolve ClassThatDependsOnIHello1 without actually calling its constructor.
You can also do it without the names:
static void RegisterDependencies(this ContainerBuilder containerBuilder)
{
containerBuilder.RegisterType<Hello>();
containerBuilder.RegisterType<Hey>();
containerBuilder.RegisterType<ClassThatDependsOnIHello1>().WithParameter(
new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(IHello),
(parameter, context) => context.Resolve<Hello>()
));
containerBuilder.RegisterType<ClassThatDependsOnIHello2>().WithParameter(
new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(IHello),
(parameter, context) => context.Resolve<Hey>()
));
containerBuilder.RegisterType<SomethingElse>().As<ISomethingElse>();
}
We can clean that up some with an method that simplifies creating that ResolvedParameter because that's so hideous.
public static ResolvedParameter CreateResolvedParameter<TDependency, TImplementation>()
where TDependency : class
where TImplementation : TDependency
{
return new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(TDependency),
(parameter, context) => context.Resolve<TImplementation>());
}
Now the previous registration becomes:
containerBuilder.RegisterType<ClassThatDependsOnIHello1>().WithParameter(
CreateResolvedParameter<IHello, Hello>());
containerBuilder.RegisterType<ClassThatDependsOnIHello2>().WithParameter(
CreateResolvedParameter<IHello, Hey>());
Better!
That leaves the details of how you integrate it with your application, and that varies with your application. Here's Autofac's documentation which provides more detail.
For testing purposes you can do this:
public static IServiceProvider CreateServiceProvider()
{
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterDependencies();
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
I like to write unit tests for this sort of thing. This method will create an IServiceProvider from the Autofac container, and then you can test resolving things from the container to make sure they get resolved as expected.
If you prefer another container, see if it has similar integrations to use it with Microsoft's container. You might find one you like better.
Windsor
Here's a similar example using Castle.Windsor.MsDependencyInjection.
public static class WindsorRegistrations
{
public static IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection)
{
var container = new WindsorContainer();
container.RegisterDependencies();
return WindsorRegistrationHelper.CreateServiceProvider(container, serviceCollection);
}
public static void RegisterDependencies(this IWindsorContainer container)
{
container.Register(
Component.For<Hello>(),
Component.For<Hey>(),
Component.For<ClassThatDependsOnIHello1>()
.DependsOn(Dependency.OnComponent<IHello, Hello>()),
Component.For<ClassThatDependsOnIHello2>()
.DependsOn(Dependency.OnComponent<IHello, Hey>())
);
}
}
There are two things I like about this:
It's so much easier to read! When resolving ClassThatDependsOnIHello2, fulfill the dependency on IHello with Hey. Simple.
This - WindsorRegistrationHelper.CreateServiceProvider(container, serviceCollection) - allows you to register dependencies with the IServiceCollection and include them in the service provider. So if you have existing code that registers lots of dependencies with IServiceCollection you can still use it. You can register other dependencies with Windsor. Then CreateServiceProvider mixes them all together. (Maybe Autofac has a way to do that too. I don't know.)

IoC Web Forms - How to load interface implementation from one of two assemblies depending on value of certain variable?

I have two assemblies which implement the same interfaces (two different implementations for the same interface). When user logs into web forms application certain variable (flag) is being set to specific value. This variable should be used for loading implementations from one of these assemblies.
When application starts, I have the following code in Global.asax to register or known implementations - I have tried using Autofac and SimpeInjector:
// SimpleInjector
private static void Bootstrap()
{
var container = new Container();
// 2. Configure the container (register)
container.Register<IUserRepository, UserRepository>();
// 3. Store the container for use by Page classes.
Global.container = container;
// 4. Optionally verify the container's configuration.
// Did you know the container can diagnose your configuration?
// For more information, go to: https://bit.ly/YE8OJj.
container.Verify();
VerifyPages(container);
}
// Autofac
protected void Application_Start(object sender, EventArgs e)
{
BundleConfig.RegisterBundles(BundleTable.Bundles);
// Build up your application container and register your dependencies.
var builder = new ContainerBuilder();
builder.RegisterType<UserRepository>().As<IUserRepository>().InstancePerRequest();
// ... continue registering dependencies...
// Once you're done registering things, set the container
// provider up with your registrations.
_containerProvider = new ContainerProvider(builder.Build());
}
Now, after a user logs in, I need to register additional implementations, but from one of the two assemblies. I need to do this from code behind of login.aspx page, I believe.
Now I don't know if I should update the container by registering additional types somehow or if I can override some method of Autofac or SimpleInjector so when it tries to instantiate an implementation for an interface, I can point it to a specific assembly.
How could I implement this behavior? Please advise. Thanks.
What you need is some abstraction that allows you to request some contextual information for the user that allows you to base the decision of on which type to load. For instance:
public interface IUserContext
{
bool IsAdministrator { get; }
}
Here the Administator property is the thing that determines what types to load for the user. How to implement this class of course completely depends on how to store this information. Perhaps you retrieve this information from the database, or from a cookie, the session, what ever.
If you need an implementation that is depending on something that is ASP.NET specific (cookie, sessie, request), you will need to have an Web application specific implementation, such as:
public class AspNetUserContext : IUserContext
{
public bool IsAdministrator
{
get
{
return HttpContext.Current != null &&
(bool?)HttpContext.Current.Session["isadmin"] == true;
}
}
}
You can register this context using Simple Injector as follows:
container.Register<IUserContext, AspNetUserContext>();
Now if you have a certain abstraction where the implementations must differ based on this flag, you can register a factory delegate as follows:
container.Register<AdministratorUserRepository>();
container.Register<NormalUserRepository>();
container.Register<IUserRepository>(() =>
{
container.GetInstance<IUserContext>().IsAdministrator
? container.GetInstance<AdministratorUserRepository>()
: container.GetInstance<NormalUserRepository>();
});
Or better it would be to create some sort of composite proxy type that allows delegating to the actual repository:
public class AdminSelectableUserRepositoryProxy : IUserRepository
{
private readonly AdministratorUserRepository adminRepo;
private readonly NormalUserRepository normalRepo;
private readonly IUserContext userContext;
public AdminSelectableUserRepositoryProxy(
AdministratorUserRepository adminRepo,
NormalUserRepository normalRepo,
IUserContext userContext)
{
this.adminRepo = adminRepo;
this.normalRepo = normalRepo;
this.userContext = userContext;
}
public User GetById(Guid id)
{
return this.Repository.GetById(id);
}
private IUserRepository Repository
{
get
{
return this.userContext.IsAdministrator ? this.adminRepo : this.normalRepo;
}
}
}
Now the registration will can be simplified to the following:
container.Register<AdministratorUserRepository>();
container.Register<NormalUserRepository>();
container.Register<IUserRepository, AdminSelectableUserRepositoryProxy>();

How to configure unit tests with an IoC container in ASP.NET?

I have configured Unity in my ASP.NET application and the configuration is loaded when the first request is received in Application_BeginRequest. then the Unity container is stored in the Global.ascx as a property so that my other class can access it:
public static IUnityContainer ContainerHolder { get; set; }
IUnityContainer IContainerAccessor.Container
{
get { return ContainerHolder; }
}
ContainerHolder, holds the container instance across application and Container property allows access to this property in each session.
Then I have a UnityLocator class which enables me access this property across the application:
public static class UnityLocator
{
private static IUnityContainer Container
{
get
{
return ((IContainerAccessor)HttpContext.Current.ApplicationInstance).Container;
}
}
}
Everything works fine!
I have also a method to access the instance from Unity:
UnityLocator.GetInstance<IThemeManager>();
protected Repository(ICustomCacheManager customCacheManager)
{
this.Cache = customCacheManager;
}
protected Repository()
: this(UnityLocator.GetInstance<ICustomCacheManager>())
{
}
this has been used in my app so that I can retrieve an existing instance from Unity so that I can inject it to other classes. For example my view (asp.net page) injects this to its Presenter class as a dependency.
Now, I'd like to configure my Unit tests to run.
How could I do that?! global.ascx doesn't exist there obviously so I thought I should create a BaseTest class and let all my tests inherit it. then at the constructor of this BaseTest class, I build up my instances. Is it the right way to do it?
How to configure unit tests with Unity now?
Thanks
UPDATE:
UnityLocator.GetInstance added.
You shouldn't worry about accessing your IoC container. That is a violation of Unit Tests.
Unit tests you should not worry about any concrete implementation or dependency (other than the class under test).
To me, having your IoC globally available is a bad design choice. You should have your dependencies injected via properties or constructors.
Probably using the global application class for storing the service locator was not a good idea. Why don't you use the built-in ServiceLocator class? It is available from anywhere in the code and doesn't depend on global application / HttpContext.
Whether or not using the container in unit tests is another story. Personally I am not against it as long as you put stub implementations of your services into the container.
Edit: the way to configure your container using ServiceLocator:
private void ConfigureUnity()
{
UnityServiceLocator locator = new UnityServiceLocator( ConfigureUnityContainer() );
ServiceLocator.SetLocatorProvider( () => locator );
}
private IUnityContainer ConfigureUnityContainer()
{
IUnityContainer container = new UnityContainer();
// this loads container's configuration, comment or uncomment
container.LoadConfiguration();
return container;
}
You can then access the container from within the locator like:
var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
In your page, try doing things like this:
public class DepartmentReportPage : Page
{
private readonly DepartmentReportPresenter _presenter;
public DepartmentReportPage()
{
this._presenter =
UnityLocator.GetInstance<DepartmentReportPresenter>();
this._presenter.View = this;
}
}

Dependency Injection / Constructor Injection Help

I have the following classes / interfaces:
public interface IProjectRepository
{
IQueryably<Project> GetProjects();
}
// Depends on my EF Context
public ProjectRepository : IProjectRepository
{
private MyDbEntities context;
public ProjectRepository(MyDbEntities context)
{
this.context = context;
}
public IQueryable<Project> GetProjects()
{
return context.Projects;
}
}
My controller:
// Depends on IProjectRepository
public class ProjectsController : Controller
{
private IProjectRepository projectRepository;
public ProjectsController(IProjectRepository projectRepository)
{
this.projectRepository = projectRepository;
}
public ActionResult Index()
{
return View(projectRepository.GetProjects());
}
}
I need to set up my dependency injection so that it passes in ProjectRepository into my Controller AND it needs to pass in my Entity Framework context into the Project Repository. I need to Entity Context to be HTTP Request scoped.
I'm not sure where I am supposed to put all the mapping code to make the dependency injection work. I also don't understand how MVC will work without the default constructor.
Can someone help me put all the pieces together? I am using StructureMap but I could easily switch to something else because I have no idea what I'm doing.
If you are using MVC 3, to do things properly, you should make use of the built in dependency resolution bits. I would highly recommend you read through the series of blog posts from Brad Wilson (member of the ASP.NET MVC team).
As far as a StructureMap specific implementation, I found the following blog posts helpful.
StructureMap and ASP.NET MVC 3 – Getting Started
StructureMap, Model Binders and Dependency Injection in ASP.NET MVC 3
StructureMap, Action Filters and Dependency Injection in ASP.NET MVC 3
StructureMap, Global Action Filters and Dependency Injection in ASP.NET MVC 3
Anyway, here's some code. To start with, I would suggest that you install the StructureMap-MVC3 NuGet package.
I can't remember what exactly it creates in the way of files, but here's what's basically involved.
/App_Start/StructuremapMvc.cs - This hooks into the Application_Start and sets up your container (SmIoC.Initialize()) and then sets the MVC 3 DependencyResolver to a your SmDependencyResolver
using System.Web.Mvc;
using YourAppNamespace.Website.IoC;
using StructureMap;
[assembly: WebActivator.PreApplicationStartMethod(typeof(YourAppNamespace.App_Start.StructuremapMvc), "Start")]
namespace YourAppNamespace.Website.App_Start {
public static class StructuremapMvc {
public static void Start() {
var container = SmIoC.Initialize();
DependencyResolver.SetResolver(new SmDependencyResolver(container));
}
}
}
/IoC/SmDependencyResolver.cs - this is your MVC 3 IDependencyResolver implementation. It's used in the App_Start code above.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using StructureMap;
namespace YourAppNamespace.Website.IoC
{
public class SmDependencyResolver : IDependencyResolver
{
private readonly IContainer _container;
public SmDependencyResolver(IContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
if (serviceType == null)
{
return null;
}
try
{
return _container.GetInstance(serviceType);
}
catch
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.GetAllInstances(serviceType).Cast<object>(); ;
}
}
}
/IoC/SmIoC.cs - this is where you setup your container... also used in the App_Start code.
namespace YourAppNamespace.Website.IoC
{
public static class SmIoC
{
public static IContainer Initialize()
{
ObjectFactory.Initialize(x =>
{
x.For<IProjectRepository>().Use<ProjectRepository>();
//etc...
});
return ObjectFactory.Container;
}
}
}
Now everything is hooked up... (I think ;-) but you still have one last thing to do. Inside your Global.asax, we need to make sure you dispose of everything that is HttpContext scoped.
protected void Application_EndRequest()
{
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
}
So you should be able to achieve dependency injection through constructor injection, which is the correct way to go about doing things.
If you are set on using StructureMap, here is a tutorial on the setup that you will probably need.
Some other dependency injection frameworks come with custom controller factories which will do that for you. Ninject (open source dependency injection), for example has an extension that you can use that contains this behaviour. See here for example. And here to the extension.
You can use also Unity IOC which is another popular dependency injection framework with which, to my knowledge, you will have to create a custom controller factory (like with structuremap) to achieve this behaviour. See here for an example.
You can also research all other dependency injection frameworks to see what support you can get with each.
EDIT:
I hope I am explaining this correctly but here is some background info.
MVC uses a controller factory that has the responsibilities of instantiating the respective controllers needed when a request is made. By default, it will initialize a controller by calling its parameterless constructor.
To create the infrastructure for the constructor parameter injection you need to create a custom factory that can resolve constructor parameters. That is where the dependency injection containers come in: essentially the DI container (if configured properly) knows how to resolve those dependency and your custom factory will leverage it to request the registered dependencies and pass the to the controller constructor.
All work pretty much the same. Historically, all have had setter injectors (set up a property that is then filled), but most have constructor injection now. In structure map, the easiest way to accomplish this is use the attribute: [StructureMap.DefaultConstructor].
Once you add the attribute, the objects you have placed in your "map" should inject without any extra work. If you can't use attributes, consider using the setter.
There is a file on the structure map site:
http://structuremap.net/structuremap/ConstructorAndSetterInjection.htm
When using StructureMap I would generally have something like this in my controller:
private static IProjectRepository GetProjectRepository()
{
var retVal = ObjectFactory.TryGetInstance<IProjectRepository>()
?? new ProjectRepository();
return retVal;
}
If the TryGetInstance returns null (because nothing was set for that type) it will default to the concrete type you specify.
Now you have a bootstrapper somewhere like this:
public static class StructureMapBootStrapper
{
public static void InitializeStructureMap()
{
ObjectFactory.Initialize(x =>
{
x.For<IProjectRepository>().Use<ProjectRepository>();
}
}
}
Now you call this bootstrapper in your Global.asax Application_Start event:
protected void Application_Start()
{
StructureMapBootStrapper.InitializeStructureMap();
}
Now in a test project, when you want to inject a mock repository you can just do this:
[TestMethod]
public void SomeControllerTest()
{
StructureMap.ObjectFactory.Inject(
typeof(IProjectRepository),
new MockProjectRepository());
// ... do some test of your controller with the mock
}

Castle Windsor: How do I register a factory method, when the underlying type isn't accessible to my assembly?

I have a project where my business layer is constructed using DI, but I'm trying to go an additional step and use Windsor to manage object construction.
Let's just say I have a pre-existing data layer (that I don't want to modify), that can be accessed via the following interface:
interface IDataFactory {
IDataService Service { get; }
}
A series of classes in my business layer depend on the services exposed through IDataFactory:
IFactory factory = DataFactory.NewFactory();
IBusinessService service = new ConcreteBusinessService(factory.Service);
I understand that in order to register IBusinessService to the Castle Windsor container, I'd use code similar to this:
IWindsorContainer container = new WindsorContainer();
container.AddComponent("businessService", typeof(IBusinessService), typeof(ConcreteBusinessService));
But for the life of me, I can't figure out how to register services from my data layer, using the my existing factory object. In essence, I'd like to say:
container.AddComponent("dataService", typeof(IDataService), factory.service);
Windsor seems to want me to say container.AddComponent("dataService", typeof(IDataService), typeOf(SomeConcreteDataService)), but in this instance, ConcreteDataService is internal to that assembly, and thus not accessible in mine.
How would I go about wiring up the data service, given that SomeConcreteDataService isn't known to my assembly?
This question is very similar to my own, except in my case, the AddComponent("calculator", typeof(ICalcService), typeof(CalculatorService), "Create"); call wouldn't work -- CalculatorService would be internal to another assembly, not available to the assembly wiring up the container.
Using Windsor 2.0:
[TestFixture]
public class WindsorTests {
public interface IDataService {}
public class DataService: IDataService {}
public interface IDataFactory {
IDataService Service { get; }
}
public class DataFactory: IDataFactory {
public IDataService Service {
get { return new DataService(); }
}
}
[Test]
public void FactoryTest() {
var container = new WindsorContainer();
container.AddFacility<FactorySupportFacility>();
container.AddComponent<IDataFactory, DataFactory>();
container.Register(Component.For<IDataService>().UsingFactory((IDataFactory f) => f.Service));
var service = container.Resolve<IDataService>();
Assert.IsInstanceOfType(typeof(DataService), service);
}
}
See the fluent API wiki page for more information.
Got it. The answer is, you don't need to worry about the implementation type:
IWindsorContainer container = new WindsorContainer();
container.AddFacility("factories", new FactorySupportFacility());
container.AddComponent("standard.interceptor", typeof(StandardInterceptor));
container.AddComponent("factory", typeof(DataFactory));
MutableConfiguration config = new MutableConfiguration("dataService");
config.Attributes["factoryId"] = "factory";
config.Attributes["factoryCreate"] = "get_Service";
container.Kernel.ConfigurationStore.AddComponentConfiguration("dataService", config);
container.Kernel.AddComponent("dataService", typeof(IDataService));
IDataService dataService = (IDataService) container["dataService"];
I had a "whoa" moment when I saw it execute successfully, because I hadn't passed in the specific implementation type to Kernel.AddComponent()

Categories

Resources