2

I am in this situation where my service interface is being implemented by two service classes.

For example,

IFooService is implemented by FooService and FooWithExtraInfoService

Here is the interface:

public interface IFooService
{
    Foo GetEntity(string fieldName, stringFieldValue);
}

Here is FooService:

public class FooService: BarService,  IFooService
{
    public FooService(ILogService logservice): base(logservice)
    {
    }

    public Foo GetEntity(string fieldName, string fieldValue)
    {
        //here goes the logic
    }
}

Here is FooWithExtraInfoService:

public class FooWithExtraInfoService: BarService, IFooService
{
    public FooWithExtraInfoService(ILogService logservice): base(logservice)
    {
    }

    public Foo GetEntity(string fieldName, string fieldValue)
    {
        //one possible option could be
        var foo = new FooService(logservice).GetEntity(fieldName, fieldValue)
        //do additional stuff
        foo.SomeField = "abc";
    }
}

As you can see one option could be creating new object of FooService and then telling unity to register type where IFooService is implemented by FooWithExtraInfoService.

Something like:

container.RegisterType<IFooService, FooWithExtraInfoService>();

But is there some other way where I don't have to create new object of FooService?

//one possible option could be
var fooService = new FooService(logservice).GetEntity(fieldName, fieldValue)
//do additional stuff

And let Unity handle it somehow?

Or should I create different interface for FooWithExtraInfoService?

I don't know what is the best way to approach this problem at this point.

Any suggestions would be helpful.

NightOwl888
  • 55,572
  • 24
  • 139
  • 212
Cybercop
  • 8,475
  • 21
  • 75
  • 135

5 Answers5

1

This seems like a good candidate for the decorator pattern.

The decorator pattern wraps the existing service, adding additional functionality to it without having to make changes to it. This allows you to cleanly separate responsibilities of what FooService does from FooWithExtraInfoService and still allow the DI container to provide the "inner" instance.

public class FooWithExtraInfoService : IFooService
{
    private readonly IFooService fooService;

    public FooWithExtraInfoService(IFooService fooService)
    {
        if (fooService == null)
            throw new ArgumentNullException(nameof(fooService));
        this.fooService = fooService;
    }

    public Foo GetEntity(string fieldName, string fieldValue)
    {
        // call the decorated instance of IFooService
        var foo = this.fooService.GetEntity(fieldName, fieldValue);
        //do additional stuff
        foo.SomeField = "abc";
    }
}

Then you just need to wire it up with your DI container like:

var instance = new FooWithExtraInfoService(new FooService(new LogService()));

In Unity, this registration could be done like:

container.RegisterType<ILogService, LogService>();

// Register FooService as a named service
container.RegisterType<IFooService, FooService>("foo");

// Register FooWithExtraInfoService and inject FooService into it
container.RegisterType<IFooService, FooWithExtraInfoService>(
    new InjectionConstructor(new ResolvedParameter<IFooService>("foo")));

NOTE: An example of how you could make decorator registrations convention-based is in this answer.

Unlike using inheritance, the decorator is loosely coupled from FooService. The ILogService does not need to be passed into the decorator only so it can be forwarded into the superclass constructor. Additionally, you can easily add another decorator class between FooWithExtraInfoService and FooService simply by changing the DI configuration.

var instance = new FooWithExtraInfoService(
    new FooDecorator1(
    new FooService(new Logger())));
NightOwl888
  • 55,572
  • 24
  • 139
  • 212
  • I like this answer till now, unless someone comes up with better answer in a while. I will accept this answer. But my confusion is Unity injection, I saw the link to the answer you posted and for me it was little complicated. Could you in simple terms post here and update the answer, I think this might help other people too – Cybercop Mar 08 '18 at 12:37
  • I have updated the answer to include the simplest Unity decorator registration. – NightOwl888 Mar 08 '18 at 13:28
  • If you pass the decorated type as type parameter, registration becomes simple, without the need to resolve at registration time. See this answer for an example: https://stackoverflow.com/a/18748399/5758420 – Haukinger Mar 08 '18 at 13:34
  • That seems to defeat the purpose of using a decorator. But then, Unity really sucks at this sort of thing - most other DI containers have a way to inject specific parameters without having to define the whole constructor signature. – NightOwl888 Mar 08 '18 at 13:39
0

Given both inherit from BarService, create an intermediate type FooServiceBase that implements the interface:

public abstract class FooServiceBase : BarService, IFooService
{
    public Foo GetEntity(string fieldName, string fieldValue)
    {
        //here goes the logic
    }
}

And let FooWithExtraInfoService and FooService inherit from that.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • How would that help anyway? Problem is with DI here? – Rahul Mar 08 '18 at 11:32
  • @Rahul as far as I understand, the problem is with "traits", or letting two types who implement the same interface implement the same behavior. – CodeCaster Mar 08 '18 at 11:33
  • My FooWithExtraInfoService has to use the GetEntity method of FooService and after GettingEntity FooWithExtraInfoService will add other stuffs to that entity – Cybercop Mar 08 '18 at 11:35
  • So you are essentially saying this `container.RegisterType();` – Rahul Mar 08 '18 at 11:35
  • 1
    @Cybercop so then you make it virtual, override it and call the base implementation. – CodeCaster Mar 08 '18 at 11:36
  • so when I use the IFooService how will Unity know which service to use as implementation? – Cybercop Mar 08 '18 at 11:37
  • 1
    @Cybercop it doesn't. Is your problem about a duplicate implementation of the same interface method, or is it about registering two services for the same interface? Because those are vastly different problems, and your question edges on the first. – CodeCaster Mar 08 '18 at 11:38
  • problem is two services are implementing same interface but one implementation should use other implentation and extend it. I don't know if having seperate interface would be good as they both are returning same entity (one will have more information) – Cybercop Mar 08 '18 at 11:41
  • I don't even know if this approach is good and if I need to have seperate interfaces for this implementations – Cybercop Mar 08 '18 at 11:43
0

I believe in your case you should use Composition ... mean have a property of type FooService rather like below since you just want to use the GetEntity() method and have no intention of extending it

public class FooWithExtraInfoService: BarService
{
   public FooService FooService { get; set; }
Rahul
  • 76,197
  • 13
  • 71
  • 125
0

When you can't always rely on the interface alone to define the behavior your service-consumers require, one alternative is to register one or both of your concrete implementations for DI.

Then any class that can safely depend on the simpler IFooService can declare a dependency on that, and those which you know will need the additional capabilites from FooWithExtraInfoService can depend upon that instead. And FooWithExtraInfoService can even declare a dependency on IFooService to inject the simpler implementation.

Basically, interface services are useful, but don't get too hung up on trying to use them in every case.

McGuireV10
  • 9,572
  • 5
  • 48
  • 64
0

This seems like the FooWithExtraInfoService is meant to be FooService, but with extra info, right?

So then, actually make it a FooService class with extra info. Give the GetEntity function in FooService the virtual keyword, and it can be overridden in child classes. This then allows you to have a new override in FooWithExtraInfoService which can simply call its parent implementation.

The adapted FooService class:

public class FooService: BarService,  IFooService
{
    public FooService(ILogService logservice): base(logservice)
    {
    }

    public virtual Foo GetEntity(string fieldName, string fieldValue)
    {
        //here goes the logic
    }
}

The implementation:

public class FooWithExtraInfoService: FooService
{
    public FooWithExtraInfoService(ILogService logservice): base(logservice)
    {
    }

    public override Foo GetEntity(string fieldName, string fieldValue)
    {
        Foo foo = base.GetEntity(fieldName, fieldValue)
        //do additional stuff
        foo.SomeField = "abc";
    }
}
Nyerguds
  • 5,360
  • 1
  • 31
  • 63