i want to config my bindings.
Bind<DbContext>().To<HangTagVerwaltungContext>();
Bind<IUnitOfWork>()
.ToConstructor(
x => new UnitOfWork(true, true, x.Inject<DbContext>()));
// Managers
Bind<ITagManager>().To<TagManager>();
// ViewModels
Bind<TagEditViewModel>().ToMethod(
context =>
{
IUnitOfWork unitOfWork = context.Kernel.Get<IUnitOfWork>();
ITagManager tagManager =
context.Kernel.Get<ITagManager>(
new Parameter(#"unitOfWork", unitOfWork, false));
return new TagEditViewModel(tagManager,
context.Kernel.Get<INavigationService>(), unitOfWork);
});
My Problem is, that everytime he is creating a new UnitOfWork for the TagManager and not use the Parameter i give him in the ToMethod method. What do i wrong?
Thx for the Help.
Dennis
I think you should be using ConstructorArgument instead of Parameter. The parameter name will have to match that of the constructor.
However, why are you doing this so complicated? (DI is about making things easier for you, not more complicated.) Is it because you need the same IUnitOfWork instance for tagManager and TagEditViewModel?
If that's the case, there's other ways to achieve this. You should look into scopes. They are used to make some part of the object tree use the same instance.
For the scenario you showed you might want to try .InCallScope(), but generally for IUnitOfWork there's other things which work better in the whole application, like .InRequestScope() for web projects or some other custom scope. There's other stackoverflow questions already covering this.
Related
I am using Ninject to set up bindings for a class which is an IObservable.
I have set up a rebind to ensure that the IObservable has it's IObserver subscribed as follows...
kernel.Rebind<IAddressRepository>().To<AddressRepository>().InRequestScope()
.OnActivation(repo => repo
.Subscribe(new SyncTrackerDataEventObserver<Address, AddressRepository>()));
This seems to work OK but it really isn't ideal. SyncTrackerDataEventObserver will, when it's more than a stub have dependencies of it's own. Then we end up with this...
kernel.Rebind<IAddressRepository>().To<AddressRepository>().InRequestScope()
.OnActivation(repo => repo
.Subscribe(new SyncTrackerDataEventObserver<Address, AddressRepository>(new SyncTrackerRepository(new SyncDataSource))));
Ouch!!
What I want to do is make use of the existing bindings at this point. I'd expect to be able to write something like this (but this is just made up..)
kernel.Rebind<IAddressRepository>().To<AddressRepository>().InRequestScope()
.OnActivation(repo => repo
.Subscribe(kernel.Resolve<ISyncTrackerDataEventObserver>()));
What is the correct way to achieve this without creating a hell of hard coded dependencies and breaking IoC paradigms?
This was quite straightforward when I figured out where to look. kernel.TryGet<> will get you the service type from the current bindings.
kernel.Rebind<IAddressRepository>().To<AddressRepository>().InBackgroundJobScope()
.OnActivation(repo => repo
.Subscribe(kernel.TryGet<SyncTrackerDataEventObserver<Address, AddressRepository>>()
?? throw new ObserverBindingException("Address")));
(where ObserverBindingException is a custom exception type I created just for this purpose).
I am trying to create a dependency graph in StructureMap 3 with a chain of decorators:
Each instance has a constructor with multiple arugments, but exactly one argument of an inner IGeocoder, e.g.
public SomeCachingGeocoder(IGeoCoder inner, IFoo somethingElse)
I am hooking them up like this:
For<OviGeoCoder>().Use<OviGeoCoder>();
For<SqlCachingGeocoder>().Use<SqlCachingGeocoder>().Ctor<IGeoCoder>().Is<OviGeoCoder>();
For<RedisCachingGeocoder>().Use<RedisCachingGeocoder>().Ctor<IGeoCoder>().Is<SqlCachingGeocoder>();
For<IGeoCoder>().Use<RedisCachingGeocoder>();
But I get
Bi-directional dependency relationship detected! Check the StructureMap stacktrace below:
1.) Instance of SOAM.Services.IGeoCoder (SOAM.Services.Geocoding.RedisCachingGeocoder)
2.) new RedisCachingGeocoder(Default of IDatabase, Default of IGeoCoder)
3.) SOAM.Services.Geocoding.RedisCachingGeocoder
4.) Instance of SOAM.Services.IGeoCoder (SOAM.Services.Geocoding.RedisCachingGeocoder)
5.) new HomeController(Default of IGeoCoder, Default of IAlertService)
6.) SOAM.Web.Controllers.HomeController
7.) Instance of SOAM.Web.Controllers.HomeController
8.) Container.GetInstance(SOAM.Web.Controllers.HomeController)
Any ideas how to solve this?
DecorateAllWith allows auto-wiring by default and allows stacking decorators in a quite easy way:
For<IGeoCoder>().Use<OviGeoCoder>();
For(typeof(IGeoCoder)).DecorateAllWith(typeof(SqlCachingGeocoder));
For(typeof(IGeoCoder)).DecorateAllWith(typeof(RedisCachingGeocoder));
If for some reason you cannot use DecorateAllWith() then this should work:
var container = new Container(
c =>
{
c.For<IFoo>().Use<Foo>();
c.For<IGeoCoder>().Add<OviGeoCoder>().Named("default");
c.For<IGeoCoder>()
.Add<SqlCachingGeocoder>()
.Ctor<IGeoCoder>()
.Is(ctx => ctx.GetInstance<IGeoCoder>("default"))
.Named("SqlCaching");
c.For<IGeoCoder>()
.Use<RedisCachingGeocoder>()
.Ctor<IGeoCoder>()
.Is(ctx => ctx.GetInstance<IGeoCoder>("SqlCaching"));
});
Wanna find what's the difference when using Use vs Add? Take a look here
I ran into a strange problem yesterday. I built a makeshift viewmodel locator style system yesterday using ninject as its di container. I then tried to have it resolve a moq mock implementation of a data repository interface to feed into the viewmodels through constructor injection. But, I keep getting the following exception from moq at design time.
Error 2 Unable to cast object of type 'Castle.Proxies.IADEmployeeRepoProxy_1' to type 'MVVMSupport.TestHarness.Data.IADEmployeeRepo'. D:\Users\kicksagnome\Desktop\MVVMSupport\MVVMSupport.TestHarness\App.xaml 16 13 MVVMSupport.TestHarness
Mock<IADEmployeeRepo> repo = new Mock<IADEmployeeRepo>();
repo.Setup<List<ADEmployee>>(r => r.GetAllEmployees())
.Returns(new List<ADEmployee>() { new ADEmployee() { FirstName = "Ryan Butcher" } });
Bind<IADEmployeeRepo>().ToConstant(repo.Object); //Also tried Bind<IADEmployee>().ToMethod(context => repo.Object);
It runs fine the first load of the designer and fails every time design data is changed and I rebuild the solution.
I recognize this isn't how moq is meant to be used so the question is...
1.) Is there a way to fix this issue?
2) How should I be adding design time data?
Well, you have several options.
You could have different options in your View Model depending on "IsInDesignMode", and have your design data reside there. That would be your quick and dirty option.
A better option would be to have a DataService, and a Mock one (or DesignDataService), and in your ViewModelLocator, you'll use that in your "IsInDesignMode".
From there, just add whatever you need to mock to the Interface of the DataService, this service will be injected into your view model on construction, and you can then simple have something like:
MyData = DataService.GetData();
In the real data service, you'll fetch your data, and in the design/mock one, you can fake to your liking, having your design data displayed easily.
Let me know if you have any other questions, or need more code for the example.
I'm using WebAPI + Autofac + Automapper, with a repository for data access. I need to map a model to my domain entities, specifically, I need to convert an identity value to the actual entity. No big deal, right? I've done this in MVC with no problem. I will simplify what I am doing to expose the essentials.
public class EntityConverter<T> : ITypeConverter<int, T>
where T : Entity
{
public EntityConverter(IRepository<T> repository)
{
_repository = repository;
}
private readonly IRepository<T> _repository;
public T Convert(ResolutionContext context)
{
_repository.Get((int) context.SourceValue);
}
}
Repositories are registered with Autofac, and are managed as InstancePerApiRequest because of session/transaction management. So, I need to register my converter in that same scope:
builder.RegisterGeneric(typeof(EntityConverter<>))
.AsSelf()
.InstancePerApiRequest();
The Automapper config looks something like:
var container = builder.Build(); // build the Autofac container and do what you will
Mapper.Initialize(cfg => {
cfg.ConstructServicesUsing(container.Resolve); // nope nope nope
// configure mappings
cfg.CreateMap<int, TestEntity>().ConvertUsing<EntityConverter<TestEntity>>()
});
Mapper.AssertConfigurationIsValid();
So here's the part that sucks. I am to understand Automapper requires the ConstructServicesUsing guy to be set before you build your config. If you set it later, it won't be used. The example above won't work because container is the root scope. If I try and resolve EntityConverter<TestEntity>, Autofac will complain that the requested type is registered for a different scope, and the one you're in ain't it. Makes sense, I want the scope created by WebApi.
Let me pause a sec and cover one fact about WebApi dependency injection (I don't really think this is Autofac-specific). WebApi creates an IDependencyScope for the request, and stashes it in the HttpRequestMessage.Properties. I can't get it back again unless I have access to that same HttpRequestMessage instance. My AsInstancePerApiRequest scoping on IRepository and my converter thus rely on that IDependencyScope.
So, that's really the meat and potatoes of the problem, and I really frustrated with this difference from MVC. You can't do
cfg.ConstructServicesUsing(GlobalConfiguration.Configuration.DependencyResolver.GetService);
That's equivalent to using container.Resolve. I can't use
GlobalConfiguration.Configuration.DependencyResolver.BeginScope().GetService
because A) that creates a new scope next to the one I actually want B) doesn't really let me clean up the new scope I created. Using Service Locator is a new way to have the same problem; I can't get to the scope WebApi is using. If my converter and its dependencies were single instance or instance per dependency, it wouldn't be a problem, but they aren't, so it is, and changing that would create lots more problems for me.
Now, I can create AutoMapper config with Autofac and register it as a single instance. I can even create per-request IMappingEngine instances. But that doesn't do me any good if the service constructor always uses that single delegate you register at the beginning, which has no access to the current scope. If I could change that delegate per each mapping engine instance, I might be in business. But I can't.
So what can I do?
Another option, this time it's built-in, is to use the per-map options:
Mapper.Map<Source, Destination>(dest, opt => opt.ConstructServicesUsing(type => Request.GetDependencyScope().GetService(typeof(YourServiceTypeToConstruct))));
Don't bother with setting up the global IoC config in your mapping configuration.
Another option is to use your IoC tool to configure how to instantiate the MappingEngine:
public MappingEngine(
IConfigurationProvider configurationProvider,
IDictionary<TypePair, IObjectMapper> objectMapperCache,
Func<Type, object> serviceCtor)
The first one is just Mapper.Configuration, the second should probably be a singleton, and the third you can fill in with the current nested container's resolution. This would simplify from having to call the Map overload every time.
Update: Automapper was updated to support that feature. See #Jimmy Bogard 's answer
This solution could be not very nice, but it works. The solution relates to WebAPI 2, I'm not sure about previous versions.
In WebAPI 2 you can get current IDependencyScope from current HttpRequestMessage via GetDependencyScope() extension method. Current HttpRequestMessage is stored in the Items property of the current HttpContext. Knowing that your factory could look like:
Mapper.Initialize(cfg =>
{
cfg.ConstructServicesUsing(serviceTypeToConstruct =>
{
var httpRequestMessage = HttpContext.Current.Items["MS_HttpRequestMessage"] as HttpRequestMessage;
var currentDependencyScope = httpRequestMessage.GetDependencyScope();
return currentDependencyScope.GetService(serviceTypeToConstruct);
});
// configure mappings
// ...
});
This may or may not be suitable for you.. but here goes:
We recently did this.. for model binders in MVC. Our model binders (on GET requests) now use Ninject-managed Services to build models.
Basically, we inject a factory (using Ninject's Factories extension.. perhaps there is a similar one for Autofac) into an "AutomapperBootstrapper" class, which in turn creates Automapper mapping Profile's and adds them to Automapper. Somewhat like this:
Mapper.Initialize(cfg =>
{
cfg.AddProfile(_factory.CreateServiceViewModelMappingProfile());
// etc..
});
The mappings Profile's themselves use MapFrom(), which is evaluated each time a mapping occurs. Something like this:
Mapper.CreateMap<Service, ServiceViewModel>()
.ForMember(x => x.Regions,
opt =>
opt.MapFrom(x => getRegions()))
private IEnumerable<Region> getRegions() {
return _factory.CreateTheService().GetRegions();
}
Each time the model binder is fired up, Ninject still wires up all dependencies for the request and it all filters down.
(For those interested, this setup basically lets us do this: /Area/Controller/Action/12, and our controller action method is this:
[HttpGet]
public ActionResult Action(ServiceViewModel model) {
// ...
}
).
I just started working with Unit Testing with NMock
I one my test cases involve adding an entry in a dictionary which is then passed to the unit being tested. I define the map as:
var item = new Mock<MyClass>().Object;
var myMap = new Dictionary<MyClass, IList<MyOtherClass>>
{
{ item, completionRequirement }
};
However when I do a myMap.ContainsKey(item) inside the unit being tested it returns false.
I am able to view a proxied item in the Dictionary on inspecting it. I am guessing that I need to do something else as well on the mocked item.(Most probably define .Equals(object o)).
My question is :
How do you define the Equals(object o) for the mocked item.
Or is there a different solution to the problem altogether.
You might want to mock the dictionary as well. That is, refactor to use IDictionary<MyClass,IList<MyOtherClass>, then pass in a mocked dictionary. You can then set up expectations so that it returns mocked objects as necessary.
It's also possible that you may not need to use a mock at all in this instance. It's not possible to tell from what you've given us, but I've often found that people new to mocking can sometimes forget that you can use the real objects as well if those objects don't have cascading dependencies. For example, you don't really need to mock a class that's just a simple container. Create one and use it, instead. Just something to think about.
The approach given at http://richardashworth.blogspot.com/2011/12/using-reflection-to-create-mock-objects.html is in Java, but presents another approach to this problem using Reflection.
I like the idea of setting up a 'fake' object along the lines of what tvanfosson is suggesting.
But if you want to do it with a mocking framework, I think all you need to do is setup an expectation for what item.Object should be. In Rhino Mocks the syntax would be something like:
var knownObject = "myKey";
var mock = MockRepository.GenerateStub<IMyClass>();
mock.Stub(x=>x.Object).Return(knownObject);
That said, I have no idea what the equivalent code would be in NMocks, but it shouldn't be hard to figure it out if you're working with it (you can always ask a question on the user group).
HTH