IoC in complex environment - inversion-of-control

Here is the situation:
ICategorized is used by ICategoryService to manage categories.
public interface ICategorized
{
ICategory Category { get; set; }
}
Then some class implements ICategorized.
public class Cart : ICategorized
{
...
ICategory Category {
get {
return _categoryService.GetItemCategory(...)
}
set {
_categoryService.SetCategoryForItem(...);
};
}
...
}
So, what is the best solution to set _categoryService implementation?
Through constructor or property injection?
Using of constructor can lead to very complex constructor like
public class Cart : ICategorized. ITagged, ISecured, IMediaSupport {
public Cart(ICategoryService cs, ITagService ts, ISecurityService ss, IMediaService ms) {...}
...
}
I doubt this is a good design. Any ideas?
What would be your suggestion?
I can give to CartService responsibility of ICategoryService but in that case I can't use Lazy loading. Something like
public class CartService : ICartService {
public CartService(ICategoryService cs) {...}
...
}

I favor constructor injection over property injection, mainly because it makes explicit what services the component requires. If you use an IoC-container you wouldn't have to worry about the constructor getting too complicated since you never have to use the constructor, only the container does.
Property injection could be used for non-required services.
By the way; generally speaking, very long constructor signatures probably means that your class does not adhere to the single responsibility principle and perhaps it should be refactored into two or more separate classes.

Related

Define Generic List from interface

This may be an easy answer, but I'm creating what I thought was a simple interface that is to contain a definition for a generic list. Basically just something that says "create a generic list" like below:
public static List<UserControl> ViewList = new List<UserControl>();
This is proving more difficult than I expected. Maybe I'm going about it wrong? Each definition I try results in the expected list being a property or a method. For example, I've tried the below with no luck
//FirstTry
public interface IAddToViewList
{
List<UserControl> ViewList();
}
//Second
public interface IAddToViewList
{
List<UserControl> ViewList { get; set; }
}
Also I'm not sure if it's possible to include that the list should be static, I'm having trouble finding anyone with a question matching these requirements, maybe because it's just not possible or I'm thinking about it the wrong way?
Interfaces are collections of abstract methods. This means that you are unable to add class variables to them.
What you would need to functionally accomplish this is an Abstract Class.
public abstract class AddToViewList
{
List<UserControl> ViewList;
}
However, all you need to do is define a method that returns a list
public interface IAddToViewList
{
public List<UserControl> createViewList();
}
This will ensure that every class that implements IAddToViewList also has the createViewList() method. Now, in this case, UserControl would have to be a defined class and so this is a list of UserControl objects, not a "Generic List".
To make the list generic you have add the diamond after the interface name:
public interface IAddToViewList<UserControl>
{
public List<UserControl> createViewList();
}
then when you are implementing your class it would look like this
public class Foo implements IAddToViewList<String>
{
public List<String> createViewList(){
// TODO
return null;
}
}

How can I resolve a service based upon generic type argument in Castle Windsor?

I have an installer like this:
public void Install(IWindsorContainer container, IConfigurationStore store) {
//Services
container.Register(
Classes.FromAssemblyNamed(ASSEMBLY_NAME)
.BasedOn<IService>()
.WithServiceFirstInterface()
.LifestyleTransient());
//Repository
container.Register(
Component.For(typeof(IRepository<>))
.ImplementedBy(typeof(Repository<>))
.LifestyleTransient());
//Contexts
container.Register(
Component.For(typeof(Context<IGlobalObject>))
.ImplementedBy(typeof(GlobalContext<>)).LifestyleTransient());
}
The repository is an open generic, and it has a Context constructor injected, which is a wrapper around an EF DbContext, but takes a type argument to indicate the database it needs to connect to. The idea is that I have several DbContexts as I need to connect to multiple databases, and I want windsor to resolve the appropriate DBcontext based upon the type argument passed to the repository.
The repositories type argument is constrained to the following (GlobalObject and GlobalContext refer to types associated with 1 such database):
public interface IGlobalObject : IObject
{}
public interface IObject
{
int Key { get; set; }
}
However, Windsor cannot resolve the context, and I cannot work out why? It is registered and in the container, but it cannot resolve.
EDIT:
Code for GlobalContext:
public class GlobalContext<T> : Context<T>
where T : IGlobalObject
{
private const string GLOBAL_CSTR = "Global";
public GlobalContext() : base(ConfigurationManager.ConnectionStrings[GLOBAL_CSTR].ConnectionString) {}
public DbSet<Company> Companies { get; set; }
public DbSet<ConnectionString> ConnectionStrings { get; set; }
public DbSet<Server> Servers { get; set; }
}
Context:
//Wrapper around dbcontext which enforces type
public abstract class Context<T> : DbContext where T : IObject
{
protected Context() {}
protected Context(string connectionString) : base(connectionString){}
}
Edit 2:
If i specify the concrete types for every scenario it works, so it is clearly something to do with matching on the interface.
//Contexts
container.Register(
Component.For(typeof(Context<Server>))
.ImplementedBy(typeof(GlobalContext<Server>)).LifestyleTransient());
This looks like a problem to me:
//Contexts
container.Register(
Component.For(typeof(Context<IGlobalObject>))
.ImplementedBy(typeof(GlobalContext<>)).LifestyleTransient());
Here you're saying - when somebody asks for Context inject a GlobalContext<> - the problem being how is windsor meant to know what the generic argument for GlobalContext is.
Its hard to see without seeing your GlobalContext object, but should it be:
container.Register(
Component.For(typeof(Context<>))
.ImplementedBy(typeof(GlobalContext<>)).LifestyleTransient());
This isn't really a direct answer to your question. But I feel the approach may be wrong.
Considering you repositories are implemented by a generic base Repository<> I cant see a clean way of relating the generic Type to the correct context. I think you may need to switch to 'flavoured' repositories with explicit contexts injected into them and/or be more verbose in the way you register your contexts.

Why DbContext doesn't implement IDbContext interface?

Why there is no IDbContext interface in the Entity Framework? Wouldn't it be easier to test things if there was an existing interface with methods like SaveChanges() etc. from which you could derive your custom database context interface?
public interface ICustomDbContext : IDbContext
{
// add entity set properties to existing set of methods in IDbContext
IDbSet<SomeEntity> SomeEntities { get; }
}
I see this IDbContext:
See this link And then you make a new partial class for your Entities Context With That interface.
public partial class YourModelEntities : DbContext, IDbContext
EDITED:
I edited this post, This Works for me.
My Context
namespace dao
{
public interface ContextI : IDisposable
{
DbSet<TEntity> Set<TEntity>() where TEntity : class;
DbSet Set(Type entityType);
int SaveChanges();
IEnumerable<DbEntityValidationResult> GetValidationErrors();
DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity:class;
DbEntityEntry Entry(object entity);
string ConnectionString { get; set; }
bool AutoDetectChangedEnabled { get; set; }
void ExecuteSqlCommand(string p, params object[] o);
void ExecuteSqlCommand(string p);
}
}
YourModelEntities is your auto-generated partial class, and your need to create a new partial class with the same name, then add your new context interface, for this example is ContextI
NOTE: The interface hasn't implement all methods, because the methods are implemented in your auto-generate code.
namespace dao
{
public partial class YourModelEntities :DbContext, ContextI
{
public string ConnectionString
{
get
{
return this.Database.Connection.ConnectionString;
}
set
{
this.Database.Connection.ConnectionString = value;
}
}
bool AutoDetectChangedEnabled
{
get
{
return true;
}
set
{
throw new NotImplementedException();
}
}
public void ExecuteSqlCommand(string p,params object[] os)
{
this.Database.ExecuteSqlCommand(p, os);
}
public void ExecuteSqlCommand(string p)
{
this.Database.ExecuteSqlCommand(p);
}
bool ContextI.AutoDetectChangedEnabled
{
get
{
return this.Configuration.AutoDetectChangesEnabled;
}
set
{
this.Configuration.AutoDetectChangesEnabled = value;
}
}
}
}
I was thinking also about that, I assume you are going to use it for mocking DbContext. I find no reason for that, except that you will need to implement your own DbSet manually in your anyway for your mocked class (so will need to rewrite your own interface anyway).
Just create a mock DbContext extending your production DbContext overriding the methods that complicate testing. That way, any changes to the production DbContext are automatically reflected in the tests, save for the overridden methods. For any other classes that deal with persistence and take the DbContext just extend them as well passing in the extended mock DbContext.
namespace Test.Mocks
{
public sealed class MockDatabaseContext : MainProject.Persistence.Database.DatabaseContext
{
public MockDatabaseContext(ConfigurationWrapper config) : base(config)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var dbPath = "test.db";
optionsBuilder.UseSqlite($"Filename={dbPath}");
}
}
}
namespace Test.Mocks
{
public class MockInventoryFacade : InventoryFacade
{
public MockInventoryFacade(MockDatabaseContext databaseContext) : base(databaseContext)
{
}
}
}
There is no IDbContext because it would be useless, the only implementation of it would be the DbContext.
EF team is also going this way with IDbSet if you look at this design meeting note
For me, the real problem with EF when it comes to unit testing is the DbConnection in the DbContext, fortunately there is Effort a nice project on codeplex that starts to fill this.
Effort is a powerful tool that enables a convenient way to create automated tests for Entity Framework based applications.
It is basically an ADO.NET provider that executes all the data operations on a lightweight in-process main memory database instead of a traditional external database. It provides some intuitive helper methods too that make really easy to use this provider with existing ObjectContext or DbContext classes. A simple addition to existing code might be enough to create data driven tests that can run without the presence of the external database.
With this, you can leave your DbContext and DbSet as is and do your unit tests easily.
The only drawback with this is the difference between Linq providers where some unit tests may pass with effort and not with the real backend.
UPDATE with EF7
I still maintain that IDbContext would be useless and the problem comes from the DbConnection.
EF7 will not have an IDbContext either, in order to do unit testing they are now giving an in memory provider.
You can see Rowan Miller doing a demo here: Modern Data Applications with Entity Framework 7

Asp.Net Mvc templated helpers with interface types

I would like to use the Asp.net MVC templated helpers functionality to generate a standard UI for my objects throughout my application, but I've run into a significant issue:
I do not directly pass class types from my controllers into their views. Instead, I pass interface types.. with the actual implementation of the Model wrapped up in a Mongo or NHibernate specific class in an indirectly referenced project.
For discussion, my objects look like:
public interface IProductRepository {
IProduct GetByName(string name);
}
public interface IProduct {
string Name { get; set; }
}
public class NHibernateProductRepository : IProductRepository {
public IProduct GetByName(string name) {
/* NHibernate Magic here */
return nhibernateFoundProduct;
}
}
public class NHibernateProduct : IProduct {
public virtual Name { get; set; }
}
public class ProductController : Controller {
public ProductController(IProductRepository productRepo) {
_ProductRepo = productRepo;
}
public ActionResult Index(string name) {
IProduct product = _ProductRepo.GetByName(name);
return View(product);
}
}
Is it possible to use interface types with the Editor.For() syntax? Are there any problems or sticking points that I need to be aware of?
I have an EditorTemplate\IProduct.ascx file available. At this time, I can't seem to get that template to be rendered without hardcoding the "IProduct" name into the Editor.For() call. I would prefer this type of 'Convention over Configuration'....
The templates helpers will use the runtime type of the object for the name. In this case you should name the file NHibernateProduct.ascx
If you don't know the name of the type at design time than you could write a helper method that would inspect the object instance and walk the list of interfaces that a particular type is implementing and return a name based on that. Then you would call the appropriate override to EditorFor that takes the string "templateName" parameter.
I have decided to use an approach with a ViewModel native to the Web project that implements the IProduct interface.

Does MEF Support Customized CTOR?

It looks like that MEF framework creates objects which have default CTOR. How about customized CTOR, or Constructor with parameters? For example:
[Export (typeof(IInterface1))]
public class MyClass : IInterface1
{
public MyClass(int id) {....}
....
}
If not, one way I can think is to pass object as parameters to CTOR. For example:
public Interface IParameterID {
public int Id { get; private set; }
...
}
Then the CTOR will be:
public MyClass([Import(typeof(IParameter))] IParameterID id)
{ ... }
Not sure if it is possible to add attribute to CTOR's parameters? And the next question is that if MEF will automatically create an instance of IParameter and inject it to the CTOR's parameter?
Yes, this is possible. Just put an [ImportingConstructorAttribute] on the constructor you would like to use. The parameters will automatically be treated as imports, but if you need to change the contract name on them you can also put an import attribute on them.