Using Unity, how do you register type mappings for generics? - entity-framework

I'm trying to implement a repository solution for Entity Framework but I am having trouble registering the types that include generics using Unity.
Given:
// IRepository interface
public interface IRepository<TEntity>
{
// omitted for brevity
}
// Repository implementation
public class Repository<TEntity, TContext> : IRepository<TEntity>, IDisposable
where TEntity : class
where TContext : DbContext
{
// omitted for brevity
}
// service layer constructor
public MyServiceConstructor(IRepository<Account> repository)
{
_repository = repository;
}
I need to register the type mapping for IRepository to Repository. but I'm having trouble with the Unity syntax for this kind of mapping.
I have tried the following with no luck:
container.RegisterType<IRepository<>, typeof(Repository<,>)>();
container.RegisterType<typeof(IRepository<>), Repository<,>>();
EDIT
Based, on #Steven response I have the following implementation now:
// UnityRepository implementation
public class UnityRepository<TEntity> : Repository<TEntity, MyDbContextEntities>
where TEntity : class
{
public UnityRepository() : base(new MyDbContextEntities()) { }
}
// Unity bootstrapper
container.RegisterType(typeof(IRepository<>), typeof(UnityRepository<>));

You are trying to do the following:
container.RegisterType(typeof(IRepository<>), typeof(Repository<,>));
This would normally work, but won't do the trick in this case, since there is IRepository<TEntity> has one generic argument and Repository<TEntity, TContext> has two, and Unity (obviously) can't guess what type it should fill in for TContext.
What you need is this:
container.RegisterType(
typeof(IRepository<>),
typeof(Repository<, MyDbContextEntities>));
In other words, you'd want to supply the Repository<TEntity, TContext> as a partial open generic type (with one parameter filled in). Unfortunately, the C# compiler does not support this.
But even if the C# did support this, Unity doesn't support partial open generic types. In fact most IoC libraries eworks don't support this. And for that one library that does support it, you would still have to do the following (nasty thing) to create the partial open generic type:
Type myDbContextEntitiesRepositoryType =
typeof(Repository<,>).MakeGenericType(
typeof(Repository<,>).GetGenericParameters().First(),
typeof(MyDbContextEntities));
There's a easy trick work around to get this to work though: define a derived class with one generic type:
// Special implementation inside your Composition Root
public class UnityRepository<TEntity> : Repository<TEntity, MyDbContextEntities>
where TEntity : class
{
public UnityRepository([dependencies]) : base([dependencies]) { }
}
Now we can easily register this open generic type:
container.RegisterType(typeof(IRepository<>), typeof(UnityRepository<>));

Related

How to define a BaseConfigration for all other configuration in EF7 code first?

I want to define a base configuration (for some reason) for all model configuration(which using fluent api on them), so i create BaseConfigration class:
public class BaseConfigration<T> : EntityTypeBuilder<T> where T : class
{
public BaseConfigration(InternalEntityTypeBuilder builder) :base(builder)
{
}
}
and all of other configuration inherit from it:
public class LoyaltyActivityConfig : BaseConfigration<LoyaltyActivity>
{
public LoyaltyActivityConfig(InternalEntityTypeBuilder builder) : base(builder)
{
this.Property(x => x.Title).HasMaxLength(100);
}
}
in this point all thing goes right, but when i want to introduce this configuration in OnModelCreating method:
new LoyaltyActivityConfig(modelBuilder.Entity<NotificationPlatform>());
it gives me error:
cannot convert from 'Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder' to 'Microsoft.EntityFrameworkCore.Metadata.Internal.InternalEntityTypeBuilder'
How can i do it?
As the exception message says, you are using incorrect type. During OnModelCreating you have EntityTypeBuilder<T> object. InternalEntityTypeBuilder should not be used in user code as its internal to EF core as said in documentation.
To define a BaseConfiguration which will be applied to each entity type in the model and derived by EntityTypeConfiguration, code should be organized in following manner:
public class BaseConfiguration<T> where T : class
{
public BaseConfiguration(EntityTypeBuilder<T> entityTypeBuilder)
{
// Write fluent API code here which will be applied to all entityTypes in the model
entityTypeBuilder.HasKey("Id");
}
}
public class LoyaltyActivityConfig : BaseConfiguration<LoyaltyActivity>
{
public LoyaltyActivityConfig(EntityTypeBuilder<LoyaltyActivity> entityTypeBuilder)
: base(entityTypeBuilder)
{
// Write fluent API code here which will be applied to EntityType LoyaltyActivity only
entityTypeBuilder.Property(x => x.Title).HasMaxLength(100);
}
}
Then call above code from OnModelCreating like this
new LoyaltyActivityConfig(modelBuilder.Entity<LoyaltyActivity>());
Above method will call BaseConfiguration constructor followed by EntityTypeConfiguration constructor, applying all fluent API code.
Few things to remember here,
In BaseConfiguration even if you have generic EntityTypeBuilder you will not be able to use generic methods since T is unknown type. You can define an interface which will be implemented by every T (all entity types in the model) and use generic methods afterwards. Using non-generic methods will also get you same result though. Its just matter of readability.
You can also use method calls instead of constructor in Config classes to achieve the same.
To organize code like above, IEntityTypeConfiguration<TEntity> feature from EF6 has been implemented in EF core and will be available in 2.0 release. More info https://github.com/aspnet/EntityFramework/issues/2805

Class from Interface.cll

I'm trying to implement a class instance of an interface class. Exploring the interface (.NET DLL) with the project explorer, it says:
bool CreateInstance(SharedLibrary::MemoryArbiter^ pntMemory,
SharedLibrary::clsMessageQueue^ pntMessageQueue,
SharedLibrary::clsGPIO^ pntGPIO,
SharedLibrary::Types^ pntProgramSettings,
SharedLibrary::DisplayDriver^ pntDisplayDriver)
Member from Plugin_Interface::IPlugin
But if I write in my MyClass.h:
using namespace System;
using namespace System::ComponentModel;
using namespace SharedLibrary;
namespace MyCppPlugin {
[AttributeUsageAttribute(AttributeTargets::Class | AttributeTargets::Method |
AttributeTargets::Property | AttributeTargets::Field,
AllowMultiple = true, Inherited = false)]
ref class MyPlugin abstract : public Plugin_Interface::IPlugin
{
bool CreateInstance(SharedLibrary::MemoryArbiter^ pntMemory,
SharedLibrary::clsMessageQueue^ pntMessageQueue,
SharedLibrary::clsGPIO^ pntGPIO, SharedLibrary::Types^
pntProgramSettings, SharedLibrary::DisplayDriver^ pntDisplayDriver);
};
};
It says: "error C3766: Missing implementation of Plugin_Interface::IPlugin::CreateInstace(...)
What the heck do I do wrong?
EDIT:
Forgot the abstract statement.
And: Why is it saying "IntelliSense: Class can not implement interface member function "Plugin_Interface::IPlugin::CreateInstance" (declared in "Plugin_Interface.dll")"
???
You got a lot more diagnostic messages from this snippet, you are making several mistakes:
[AttributeUsage] is only valid on a class that derives from System::Attribute. You no doubt need to use some kind of attribute so that the plugin host can recognize your class as a valid plugin candidate, I can't guess what that attribute might be.
A method that implements an interface method should be public.
A method that implements an interface method must be virtual.
The method signature must be an exact match with the interface method declaration.
Just in case: you must actually implement the method, not just declare it.
The third and forth bullets are the chief reasons for the "must provide an implementation of the interface method" compile error. So proper code ought to resemble something like this:
[NoIdeaWhatAttribute]
public ref class MyPlugin : public Plugin_Interface::IPlugin {
public:
virtual bool CreateInstance(SharedLibrary::MemoryArbiter^% pntMemory,
SharedLibrary::clsMessageQueue^% pntMessageQueue,
SharedLibrary::clsGPIO^% pntGPIO,
SharedLibrary::Types^% pntProgramSettings,
SharedLibrary::DisplayDriver^% pntDisplayDriver)
{
// Todo...
return false;
}
};
I got it. Thanks to Hans Passant who gave me so many hints :)
To export the function it has to implement the Interface 1:1. The export statement has to be added over the class header:
[Export(IPlugin::typeid)]
public ref class MyPlugin : public Plugin_Interface::IPlugin
And: While VB.NET will compile to "Any CPU" and C++/CLI will compile to Win64/Win32 it will missfit. Both Projects have to have the same target - either 64bit OR 32bit.
Now it works.

Simple Injector with several bounded DbContexts - exception "IDbContext has already been registered"

I am trying to switch to Simple Injector Dependency Injection framework as I am impressed with its speed.
private static void RegisterServices(Container container)
{
container.RegisterPerWebRequest<IDbContext, DbContext1>();
////container.RegisterPerWebRequest<IDbContext, DbContext2>();
container.RegisterPerWebRequest<IUnitOfWork, UnitOfWork>();
container.RegisterPerWebRequest<IColourRepository, ColourRepository>();
where DbContext1 and DbContext2 inherit from a BaseDbContext class
public class BaseDbContext<TContext> : DbContext, IDbContext where TContext : DbContext
which implements a rather simple IDbContext interface (like the many offered on SO), e.g:
public interface IDbContext
{
IQueryable<TEntity> Find<TEntity>() where TEntity : class;
DbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
void Dispose();
}
If I use just a single DbContext class, it works fine - repositories get injected, data pulled etc.
However, I'd also like to use bounded contexts with a smaller number of DbSets in each of them (Shrink EF Models with DDD Bounded Contexts) as my Code-First DbContext would otherwise include hundreds of classes
private static void RegisterServices(Container container)
{
container.RegisterPerWebRequest<IDbContext, DbContext1>();
container.RegisterPerWebRequest<IDbContext, DbContext2>();
container.RegisterPerWebRequest<IUnitOfWork, UnitOfWork>();
container.RegisterPerWebRequest<IColourRepository, ColourRepository>();
Then I get an exception:
System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=Type IDbContext has already been registered and the container is currently not configured to allow overriding registrations. To allow overriding the current registration, please set the Container.Options.AllowOverridingRegistrations to true.
Source=SimpleInjector
StackTrace:
at SimpleInjector.Container.ThrowWhenTypeAlreadyRegistered(Type type)
at SimpleInjector.Container.AddRegistration(Type serviceType, Registration registration)
at SimpleInjector.Container.Register[TService,TImplementation](Lifestyle lifestyle, String serviceTypeParamName, String implementationTypeParamName)
at SimpleInjector.Container.Register[TService,TImplementation](Lifestyle lifestyle)
at SimpleInjector.SimpleInjectorWebExtensions.RegisterPerWebRequest[TService,TImplementation](Container container)
If I follow the suggestion:
container.Options.AllowOverridingRegistrations = true;
then DbContext2 seems to override DbContext1, e.g. DbSet "Colour" is in DbContext1 and it is not accessible any more:
Additional information: The entity type Colour is not part of the model for the current context.
How should I use Simple Injector and bounded DbContexts together?
[UPDATE]
The DbContexts are no used in controllers directly, they are dependencies of repositories which Simple Injector should be able to initialise in constructors
public class ColoursController : ApiController
{
private readonly IColourRepository _repository;
private readonly ModelFactory _modelFactory;
public ColoursController(IColourRepository repository)
{
_repository = repository;
_modelFactory = new ModelFactory();
}
where
public class ColourRepository : Repository<Colour>, IColourRepository
{
public ColourRepository(IDbContext context) : base(context) { }
ColourRepository expects a concrete implementation of DbContext1, but some other repository would need DbContext2 (with a different set of entities)
I do not see the reason why it is impossible to use IDbContext interface (or a base type) for both DbContext1 and DbContext2.
Unity can do it:
container.RegisterType<IDbContext, NorthwindContext>(new PerRequestLifetimeManager(), "NorthwindContext");
container.RegisterType<IDbContext, NorthwindCustomerContext>(new PerRequestLifetimeManager(), "NorthwindCustomerContext");
Ninject can do it.
Simple Injector mentions CompositeLogger - maybe that one could do the trick?
https://simpleinjector.org/
ColourRepository expects a concrete implementation of DbContext1, but
some other repository would need DbContext2 (with a different set of
entities)
Your design is currently ambiguous. Although your design speaks about an IDbContext and it looks like if there's just one abstraction with two implementations, but those implementations are not interchangeable (a Liskov Substitution principle violation) which is an indication that there should in fact be two different interfaces. Besides, having one single interface makes your DI configuration more complicated and harder to maintain (this is independent on the framework you pick).
So the solution is to remove the ambiguity from your design by giving each context its own interface. This allows your repositories to take the dependency on the abstraction they need:
public class ColourRepository : Repository<Colour>, IColourRepository
{
public ColourRepository(ICustomerDbContext context) : base(context) { }
}
And this allows you to simplify the registration:
container.Register<IDbContext, NorthwindContext>(Lifestyle.Scoped);
container.Register<ICustomerDbContext, NorthwindCustomerContext>(Lifestyle.Scoped);
Note that using keyed registrations won't solve the core problem; you'll still forced to explicitly state which keyed version should be injected in which repository, which will make your DI configuration a maintenance nightmare and very error prone.

Cast class to base interface via reflection cause exception

I'm loading a .NET assembly dinamically via reflection and I'm getting all the classes that it contains (at the moment one). After this, I'm trying to cast the class to an interface that I'm 100% sure the class implements but I receive this exception: Unable to cast object of type System.RuntimeType to the type MyInterface
MyDLL.dll
public interface MyInterface
{
void MyMethod();
}
MyOtherDLL.dll
public class MyClass : MyInterface
{
public void MyMethod()
{
...
}
}
public class MyLoader
{
Assembly myAssembly = Assembly.LoadFile("MyDLL.dll");
IEnumerable<Type> types = extension.GetTypes().Where(x => x.IsClass);
foreach (Type type in types)
{
((MyInterface)type).MyMethod();
}
}
I have stripped out all the code that is not necessary. This is basically what I do. I saw in this question that Andi answered with a problem that seems the same mine but I cannot anyway fix it.
You are trying to cast a .NET framework object of type Type to an interface that you created. The Type object does not implement your interface, so it can't be cast. You should first create a specific instance of your object, such as through using an Activator like this:
// this goes inside your for loop
MyInterface myInterface = (MyInterface)Activator.CreateInstance(type, false);
myInterface.MyMethod();
The CreateInstance method has other overloades that may fit your needs.

How do I register a generic class to be resolved when the generic argument is based on a certain type?

How do I register IPetFactory<TPet> to be resolved with DefaultPetFactory<TPet> where TPet can be any class based on Pet in the example below?
I'd like to be able to resolve IPetFactory<Dog> with DefaultPetFactory<Dog>.
I've just found examples using BasedOn where the Factory itself is based on a class, not the generic argument.
class Pet
{
public string Name { get; set; }
}
class Fish : Pet {}
class Dog : Pet {}
class Cat : Pet { }
interface IPetFactory<TPet> where TPet : Pet;
class DefaultPetFactory<TPet> : IPetFactory<Pet> where TPet : Pet
{
// default implementation
}
My real implementation has a lot of classes based on Pet so I'm looking for a more generic approach than just calling register on each of them.
EDIT:
I found out the problem wasn't what I thought it was. It was due to the generic arguments and an exception of “the arity of the generic type definition” which caused my problems.
And I over-simplified my example. In my real implementation I have to generic arguments and it turns out Windsor need the the same generic parameters to be able to resolve the type.
If I do like this it won't work.
class Owner
{
}
class DefaultPetFactory<TPet> : IPetFactory<Owner, TPet> where TPet : Pet
{
// default implementation
}
If I do like this it will:
class DefaultPetFactory<TOwner, TPet> : IPetFactory<TOwner, TPet>
where TOwner : Owner
where TPet : Pet
{
// default implementation
}
If anyone has a better solution to this, preferably with the registrations it's appreciated. I don't like to change my classes to make the registration work.
(For the updated question)
There is a ticket in Windsor's issue tracker to support scenarios like that (feel free to vote for it), but in general this is something very hard to implement... generically (no pun intended), and as far as I know no container currently supports it.
In Windsor 3 you can workaround it by implementing a new interface called IGenericImplementationMatchingStrategy doing roughly the following (untested, I'm writing this from memory):
public class PetMatcher: IGenericImplementationMatchingStrategy
{
public Type[] GetGenericArguments(ComponentModel model, CreationContext context)
{
if (SomePreconditionToMakeSureThatsReallyTheScenarioDescribedAbove() == false )
{
return null;// which will fallback to default behaviour
}
// implementation needs just one generic arg, second of two the interface has
return new[]{ context.GenericArguments[1] };
}
}
You then register this as follows:
Container.Register(
Classes.FromAssemblyContaining(typeof(IPetFactory<,>)).BasedOn(typeof(IPetFactory<,>))
.WithServiceBase()
.Configure(
c => c.ExtendedProperties(
Property.ForKey(ComponentModel.GenericImplementationMatchingStrategy)
.Eq(new PetMatcher()))));