Resolving single implementation for multiple interfaces

May 31, 2012 at 8:17 AM

Hi guys, 

I was wandering is it possible to register a single implementation under two interfaces so that the same implementation will be injected where either of the interfaces is needed?

I encountered a problem where I have, for example, IServiceInterface which inherits IBaseServiceInterface (IBaseServiceInterface I use in a couple of my simpler projects, and in one other (more complex) project I needed to extend that interface with other methods) and ServiceImpl as the implementation of IServiceInterface.

The problem is actually that in classes where I need IBaseServiceInterface injected (because those are the classes that are shared between all my projects) in project where I use ServiceImpl. Unity does not now how to handle that and my ServiceImpl is never injected in places where it is needed.

Is there a possible workaround for this problem? Because I would like to avoid the situation where I need to register to different instances of the (basically) same service implementation.

I tried changing the classes that implement IBaseServiceInterface and defining through unity.config and generic parameters which services need to be injected. This solved my problems for services which unity resolves but I still had problems with property injection in FilterAttribute classes which are also shared among my projects.

Any kind of advice would be most welcome :)

May 31, 2012 at 8:40 AM

I was wandering is it possible to register a single implementation under two interfaces so that the same implementation will be injected where either of the interfaces is needed?

Sure you can:

    IUnityContainer container = new UnityContainer();

    container.RegisterType<ILogger, AuditLogger>();
    container.RegisterType<IAuditor, AuditLogger>();

    //AuditLogger instance
    var logger = container.Resolve<ILogger>();
            
    //AuditLogger instance
    var auditor = container.Resolve<IAuditor>();

Perhaps you could post a specific example of the issues you are hitting?

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

May 31, 2012 at 9:07 AM
Edited May 31, 2012 at 9:19 AM

Registration of my services looks something like this in Unity.config

			<register name="myService" type="IServiceInterface, MyProject.Common" 
                      		mapTo="ServiceImplementation,  MyProject.Common">
				<lifetime type="singleton" />
			</register>

			<register type="IBaseServiceInterface, MyProject.Common"
                     		mapTo="ServiceImplementation, MyProject.Common">
				<lifetime type="singleton" />				
			</register>

And I have a FilterAttribute class, which looks something like this:

    public class PermissionAttribute : AuthorizeAttribute
    {	[Dependency]
        public IBaseServiceImplementation service { get; set; }

        private RoleType[] allowedPermissions;

        public PermissionAttribute(params RoleType[] permisions)
        {
            allowedPermissions = permisions;
	    service .DoSomething();
        }
    }

When the constructor of this FilterAttribute is executed (due to build_up of a certain cotroller) my service is null, because no injection happened.Apparently Unity does not know which service needs to be injected here

May 31, 2012 at 9:08 PM
Edited May 31, 2012 at 9:11 PM

Property injection occurs AFTER constructors.  Unless you set the property values from a constructor they will ALWAYS be the default value for that type.  How can Unity set a property value on a instance that hasn't been created yet.

Also, be careful about attributes, as they are not usually instantiated with their type, it is usually done by reflecting metadata on the type/method so therefore will not be under the "control" of unity.

May 31, 2012 at 10:56 PM

Hi,

let me try to simplify  and clarify the problem through examples.
We have two classes, where one inherits the other and adds additional behavior.
Base class belongs to common project (BaseDataBean, IBaseDataBean) and is used as is in simple projects.
Something like this:

namespace MvcApplication3
{
   
    public interface IBaseDataBean
    {
        string GetBase();
    }

    public class BaseDataBean : IBaseDataBean
    {
        public string GetBase()
        {
            return "Base";
        }
    }
}

While extended class belongs to complex project (DataBean, IDataBean) where is used.

namespace MvcApplication3
{
    public interface IDataBean
    {
        string GetData();
    }

    public class DataBean : BaseDataBean, IDataBean
    {
        public string GetData()
        {
            return "Data";
        }
    }
}

In both project types we want to use some sort of "data bean" which is singleton.

In a simple project, extract from xml unity configuration (simple_unity.config) would be as follows:
....
<container>
     <register name="dataBean" type="MvcApplication3.IBaseDataBean, MvcApplication3" mapTo="MvcApplication3.BaseDataBean, MvcApplication3" >
        <lifetime type="singleton" />   
    </register>

....


And in a complex project, extract from xml unity configuration (complex_unity.config) would be:
....
<container>
     <register name="dataBean" type="MvcApplication3.IDataBean, MvcApplication3" mapTo="MvcApplication3.DataBean, MvcApplication3" >
        <lifetime type="singleton" />   
    </register>

....


Lets have a service in common project, that we want to reuse in the both dependent projects:

namespace MvcApplication3
{
 public class SomeService : ISomeService
    {
        public IBaseDataBean bean { get; set; }

     

        public SomeService (IBaseDataBean  dataBean)
        {
            bean = dataBean;
         
        }
       

        public string GetSome()
        {
            return "Something" + bean.GetBase()  ;
        }
    }
}

This service uses IBaseDataBean  since they share common behavior.

If we extend simple_unity.config with

<register name="someService" type="MvcApplication3.ISomeService, MvcApplication3" mapTo="MvcApplication3.SomeService, MvcApplication3" >
       <lifetime type="singleton" />   
        <constructor>
          <param name="dataBean">
            <dependency name="dataBean"></dependency>
          </param>
        </constructor>
      </register>
everything will work fine.

But, if we extend complex_unity.config with the same registration from above, error will be raised since type defined in dataBean registration does not match contructor parameter (IDataBean vs. IBaseDataBean). The same happens when IDataBean interface extends IBaseDataBean or DataBean is used instead of IDataBean in registration.
It would be nice if we could instruct unity to cast IDataBean to IBaseDataBean during injection.
The same problem reappears in filter attributes if we want them to have common behavior.


One workaround for types instantiated by unity could be to create a class with generic parameter.

namespace MvcApplication3
{
 public class SomeService<T> : ISomeService
    {
        public T bean { get; set; }

     

        public SomeService(T dataBean)
        {
            bean = dataBean;
         
        }
       

        public string GetSome()
        {
            return "Something" +((IBaseDataBean) bean).GetBase() ;
        }
    }
}

In this way, we could instruct unity in both project types which data bean type to use.
In simple_unity.config  we would use

<register name="someService" type="MvcApplication3.ISomeService, MvcApplication3" mapTo="MvcApplication3.SomeService`1[[MvcApplication3.IBaseDataBean, MvcApplication3]], MvcApplication3" >
       <lifetime type="singleton" />
        <constructor>
          <param name="dataBean">
            <dependency name="dataBean"></dependency>
          </param>
        </constructor>
      </register>

while in complex_unity.config

<register name="someService" type="MvcApplication3.ISomeService, MvcApplication3" mapTo="MvcApplication3.SomeService`1[[MvcApplication3.IDataBean, MvcApplication3]], MvcApplication3" >
       <lifetime type="singleton" />
        <constructor>
          <param name="dataBean">
            <dependency name="dataBean"></dependency>
          </param>
        </constructor>
      </register>

But this solves just part of the problem related to types instantiated by unity.

What we want is to have filter attributes in common project that will be reused by others.
Filter attributes are not instantiated by unity, unity just resolves dependencies.  If unity registered type and targeted dependency type do not match we get error.

Example of filter attribute class:

 public class PermissionAttribute : AuthorizeAttribute
    {

 [Dependency("dataBean")]
        public IBaseDataBean DataBean { get; set; }
....
}

Is it possible to somehow reuse the same filter attribute implementation for base and derived databean, avoiding to register both of them?

 

Apart from previously said, having

<register  type="MvcApplication3.IBaseDataBean, MvcApplication3" mapTo="MvcApplication3.DataBean, MvcApplication3" >
        <lifetime type="singleton" />   
    </register>

<register  type="MvcApplication3.IDataBean, MvcApplication3" mapTo="MvcApplication3.DataBean, MvcApplication3" >
        <lifetime type="singleton" />   
    </register>

in one xml would create one instance of DataBean  registered to both IBaseDataBean and IDataBean, but if we name either of them it is no longer the case.

If we take this path, is it possible to somehow assign named instance

<register name="dataBean"  type="MvcApplication3.IDataBean, MvcApplication3" mapTo="MvcApplication3.DataBean, MvcApplication3" >
        <lifetime type="singleton" />   
    </register>

to (un)named IBaseDataBean type (which could be further injected to a class properties of IBaseDataBean type).

<register  type="MvcApplication3.IBaseDataBean, MvcApplication3" mapTo="MvcApplication3.DataBean, MvcApplication3" >
        <lifetime type="singleton" />   
    </register>

 

Thanks in advance.

 

Jun 1, 2012 at 2:48 AM

It sounds like you are trying to inject attributes (correct me if I'm wrong).  The issue is that attributes are not created by the container which is why the dependency (service) is not injected.  For this case you could create a custom ActionInvoker to BuildUp the attributes.  See Dependency Injection in ASP.NET MVC: Filters for an approach that uses StructureMap but should work just as well with Unity.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com