I want to inject DispatcherNotifiedObservableCollection into (and only into) all ViewModels (located in MyProject.ViewModels) as ObservableCollection.
With Ninject I can accomplish this with:
Bind(typeof(ObservableCollection<>))
.To(typeof(DispatcherNotifiedObservableCollection<>))
.When(context => context.ParentContext.Binding
.Service.Namespace == "MyProject.ViewModels");
I've learned from Nicholas Blumhardt: Autofac vs Ninject contextual binding?
that Autofac does not provide this functionality, but some workaround could be applied.
Thanks!
(sorry for my English)
Edit 1: Changed title for better description.
Edit 2, 3: Changed contents and title for better description.
Sorry about the slow reply.
Your best bet with Autofac is to use a rule for registering the ViewModels and to apply a parameter to resolve the different implementation of ObservableCollection<>:
// Default for other components
builder.RegisterGeneric(typeof(ObservableCollection<>));
// Won't be picked up by default
builder.RegisterGeneric(typeof(DispatcherNotifiedObservableCollection<>))
.Named("dispatched", typeof(ObservableCollection<>));
var viewModelAssembly = typeof(AViewModel).Assembly;
builder.RegisterAssemblyTypes(viewModelAssembly)
.Where(t => t.Name != null && t.Name.EndsWith("ViewModel"))
.WithParameter(
(pi, c) => pi.ParameterType.IsClosedTypeOf(typeof(ObservableCollection<>)),
(pi, c) => c.ResolveNamed("dispatched", pi.ParameterType));
You'll need to be using Autofac; for IsClosedTypeOf(). Also, if the version of Autofac you're using doesn't support this overload of WithParameter() you can use the overload that takes a Parameter and pass a ResolvedParameter instead.
Hope this helps,
Nick
Related
I have this code in my project, how can I use Moq to moq the documentsession and setup the return value?
_session.Query<IPageModel, PageByUrl>()
.Customize(x => x.WaitForNonStaleResultsAsOfLastWrite())
.FirstOrDefault(x => x.Metadata.Url == virtualUrl);
This is what I have tried before I asked
var session = new Mock<IDocumentSession>();
var pageModel = new DummyModel();
session.Setup(x => x.Query<IPageModel, PageByUrl>()
.Customize(y => y.WaitForNonStaleResultsAsOfLastWrite())
.FirstOrDefault(y => y.Metadata.Url == path)).Returns(pageModel);
This throws an exception and I can't figure out how to change the moq
System.NotSupportedException : Expression references a method that does not belong to the mocked object: x => x.Query<IPageModel,PageByUrl>().Customize(y => y.WaitForNonStaleResultsAsOfLastWrite()).FirstOrDefault<IPageModel>(y => y.Metadata.Url == .path)
at Moq.Mock.<>c__DisplayClass1c`2.<Setup>b__1b()
at Moq.Mock.Setup(Mock mock, Expression`1 expression, Func`1 condition)
at Moq.Mock`1.Setup(Expression`1 expression)
at BrickPile.Tests.Web.Routing.PathResolverTests.Home_Page_With_Default_Action(String path) in PathResolverTests.cs: line 26
Instead of mocking the document session, have you thought about using the embeddabledocumentstore? It could run completely in memory and you have the full database as backend for your tests.
See also this blog post which describes some of the backgrounds: http://novuscraft.com/blog/ravendb-and-the-repository-pattern
This question inspired a blog post.
The short answer: Don't. You're coupling your application to RavenDB and violating the Interface Segregation Principle. Instead, write a custom interface that specifies precisely what services your class (the system under test) needs. Write a wrapper class that implements that and delegates to RavenDB. This might use the Repository Pattern, or it might be something simpler. Your interface should be simple to mock.
You need to mock whatever IDocumentSession.Query() returns as a separate mock so that you can then setup the customize call. I'm typing this on my phone so I can't easily give you an example.
Some of the IOC containers have what's called auto-wiring based on conventions, for e.g., IProductRepository maps to ProductRepository without any manual wiring on your part.
Is there such a thing with Ninject?
// use Ninject.Extensions.Conventions for convention-based binding
kernel.Scan(scanner =>
{
// look for types in this assembly
scanner.FromCallingAssembly();
// make ISomeType bind to SomeType by default (remove the 'I'!)
scanner.BindWith<DefaultBindingGenerator>();
});
copied from #Pete Montgomery comment
Ninject comes with an extension for convention based configuration. But you still need to configure your convenions. See https://github.com/ninject/ninject.extensions.conventions The syntax has changed for 3.0.0 but has become much more powerful. The following would add bindings for all classes in your system. But normally you want several of these conventions for different kind of classes (e.g. services are singletons, ....)
kernel.Bind(
x => x.FromThisAssembly()
.SelectAllClasses()
.BindAllInterfaces());
I am mapping quite a few WCF Data Contracts to Entity Framework Classes.
For every class I have to do this kind of thing:
Mapper.CreateMap<MyContractClass, MyDalClass>()
.ForMember(x => x.EntityKey, opt => opt.Ignore())
.ForMember(x => x.SomeAssociation, opt => opt.Ignore())
.ForMember(x => x.SomeAssociationReference, opt=> opt.Ignore())
// Repeat
// the
// last
// /two
// lines
// for
// every
// single
// association
// (Some classes have a lot of associations)
;
Is there an easier way? Some way to rule out all the extra stuff put in by EntityFramework?
Or does this just have to be done by hand?
NOTE: I have extensively evaluated the POCO template and it does not work for my scenario. Please do not just recommend that instead of Automapper.
Assuming that your contract class doesn't have the association properties, you could use this extension method to ignore them all in one statement:
Mapper.CreateMap<MyContractClass, MyDalClass>().IgnoreAllNonExisting();
I'm using T4 templates to generate the mappings from the EDMX model. This works very well and has saved me a lot of time so far. The idea is from this guy. You can download his templates and customize them to work for your scenario.
You can use EntitiesToDTOs which is simpler than AutoMapper. You don't have to write the map, neither configurate it. It is all automatically generated by the tool.
We have two Assemblies that contain their own Entity-Framework EDMX & repositoriy objects. These are registered using Autofac in an ASP.NET webapplication.
These Assemblies are very similar of architecture (but differing EDMX) we have found that the last EntityConnection being registered is the EntityConnection that is being used in both Assemblies. We need to limit the usage of an EntityConnection to only be used by Types of an assembly or namespace.
var assembly = typeof(Activity).Assembly;
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();
builder.Register(reg => new EntityConnection(ConnectionString));
var assembly = typeof(User).Assembly;
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();
builder.Register(reg => new EntityConnection(ConnectionString));
Is there a way to register the EntityConnection and limit the depth of EntityConnection? Limit each EntityConnection to the assembly it belong to?
Here's a pseudocode example of how we want to register EntityConnection for use in only an assembly or namespace.
builder.Register(reg => new EntityConnection(ConnectionString)).ForNamespace("x");
try to solve the problem at an higher level of abstraction. Since you have two separate domains (one containing the Activity entity, and one containing the User entity), it would be convenient to have this explicitly in your application design. For instance, define a factory of some kind per domain:
public interface IActivityDomainContextFactory
{
ObjectContext CreateNew();
}
public interface IPeopleDomainContextFactory
{
ObjectContext CreateNew();
}
You can now easily create an implementation for each interface, register them in the Autofac ContainerBuilder and let your services depend on one of those interfaces, instead of depending them on a EntityConnection.
In this case you of course still have a dependency on the Entity Framework itself (see here for how to abstract that away), but this makes your configuration much easier, less fragile, better performing, and your application code more maintainable.
I hope this helps.
You probably want to name/key your registrations. See TypedNamedAndKeyedServices - Autofac
I think this solves half your problem, how to register the types. The other half is in the resolution. Since your doing autoregistration via assembly scanning, this might take a little more trickery.
There are plenty of good suggestions out there on improving this, so just recording my solution as a general sketch of how you'd do this in Autofac.
The trick is to use named services for the connections, then customise parameter resolution for types in each assembly so that the EntityConnection parameters get a named instance:
builder.Register(reg => new EntityConnection(ConnectionString))
.Named<EntityConnection>("activities");
builder.RegisterAssemblyTypes(typeof(Activity).Assembly)
.AsImplementedInterfaces()
.WithParameter(
(pi, c) => pi.ParameterType == typeof(EntityConnection),
(pi, c) => c.ResolveNamed<EntityConnection>("activities"));
builder.Register(reg => new EntityConnection(ConnectionString))
.Named<EntityConnection>("users");
builder.RegisterAssemblyTypes(typeof(User).Assembly)
.AsImplementedInterfaces()
.WithParameter(
(pi, c) => pi.ParameterType == typeof(EntityConnection),
(pi, c) => c.ResolveNamed<EntityConnection>("users"));
I'm adding autofac to an existing project and some of the service implementations require their Initialize method to be called and passed configuration information. Currently I'm using the code:
builder.Register(context =>
{
var service =
new SqlTaxRateProvider(context.Resolve<IUserProvider>());
service.Initialize(config);
return service;
}
).As<ITaxService>()
.SingleInstance();
which works but I'm still creating the object myself which is what I'm trying to get away from this and allow autofac to handle it for me. Is it possible to configure a post create operation that would carry out the custom initialisation?
To give you an idea of what I'm after ideally this would be the code:
builder.RegisterType<SqlTaxRateProvider>()
.As<ITaxService>()
.OnCreated(service=> service.Initialize(config))
.SingleInstance();
Update:
I am using Autofac-2.1.10.754-NET35
.OnActivating(e => e.Instance.Initialize(...))
should do the trick.
You might also investigate the Startable module (see the Startable entry in the Autofac wiki).
Mark's suggestion to do initialisation in the constructor is also a good one. In that case use
.WithParameter(new NamedParameter("config", config))
to merge the config parameter in with the other constructor dependencies.