2

Possible Duplicate:
Can dependency injection prevent a circular dependency?

I am developing a framework which will have various services like dal, integration with sharepoint, exception handling etc.

I need to do it in IoC and I am new to this approach.[there seems to be circular reference with how i am doing]

So in my opinion we will have three types of projects

  • an interface: preferably a separate project
  • concrete class projects(service project like exception, dal, integration etc)that implements an interface
  • bootstrapper\conifiguration (configurator): preferably a separate project, if it resides in the "interface" project it will create circular reference with the concrete class projects as IoC requires the reference of both interface and concrete class.

now here is the thing

  1. the concrete classes should not have reference of any other concrete class as this will end up creating circular reference.(doesn't it kill the whole purpose of IoC if there is circular reference, or am i wrong here?).

  2. secondly the start project(unit test, WCF service etc) should load the bootstrapper first to get all the types registered, so should I add bootstrapper project to the start up project, create an instance[singleton] of the unity container to register all the types. To resolve the types I need the same instance in every other service project.

so i have to add the bootstrapper project to services projects for type resolution. This approach doesn't feel right because it will result in the same issue as i mentioned in point # 1 (every service project will contain the reference of the service projects).

How to go about it? I have tried adding the UnityContainer as a property in each concrete class through property injection at the time of registration. I am not even sure if this is the right way. My main concern is the best practice to achieve the results So if you can guide me through this i will be really thankful...

Thank you in advance!

One more thing which way you prefer for performance, configuration, in-code type Registration or instanceregistration?

If it is required i can upload the demo project. I can explain one thing. Dal uses exception manager, exception manager uses translator for user friendly message, translator uses DAL to get the user friendly message. this is one case where we have circular reference. but there can be many if we add reference in each other.

[UPDATED - sample code included] we haven't implemented IoC yet so you won't see any reference to it public bool Update() {
bool result = false;

        //Central DB
        IDataServiceManager oDataServiceMgr = null;
        DbTransaction oTrans = null;

        //Client DB
        IDataServiceManager oDataServiceMgrClient = null;
        DbTransaction oTransClient = null;

        try
        {

            oDataServiceMgr = new DataServiceManager(); //Connets to Centeral DB
            oTrans = oDataServiceMgr.BeginTransaction();

            if (this.UpdateUserData(oDataServiceMgr, oTrans))  //First Update in Center
            {
                oDataServiceMgrClient = new DataServiceManager(this.clientIDField); //Connects to client db
                oTransClient = oDataServiceMgrClient.BeginTransaction();
                if (this.UpdateUserData(oDataServiceMgrClient, oTransClient))
                    result = true;
            }

            if (result)
            {
                oTrans.Commit(); //Center DB
                oTransClient.Commit(); //Center DB
            }


        }
        catch (UserServiceException ex)
        {
            this._UserServiceException = new UserServiceException();
            SnapFlow.ExceptionHandling.ExceptionHandler.Wrap(this._UserServiceException, ex, true);
            throw this._UserServiceException;
        }

        finally 
        {
            if (!result && oTrans != null)
                oTrans.Rollback();

            if (!result && oTransClient != null)
                oTransClient.Rollback();

        }

        return result;
    }
Community
  • 1
  • 1
Waqas
  • 424
  • 7
  • 15
  • Related: http://stackoverflow.com/questions/1453128/is-there-a-good-proper-way-of-solving-the-dependency-injection-loop-problem-in-th – Mark Seemann Mar 14 '11 at 13:24
  • 1
    Possible duplicate: http://stackoverflow.com/questions/2053044/can-dependency-injection-prevent-a-circular-dependency – Mark Seemann Mar 14 '11 at 13:25

2 Answers2

4

As with any circular references, you need to look at the actual architecture of the code itself. Putting IoC/DI aside, have a look at where your circular references are occurring and refactor. Do these references really need to be there? Is there a better design you can use?

Matthew Abbott
  • 60,571
  • 9
  • 104
  • 129
1

Note: i donot know much about Unity but i worked with other ioc-containers

if i understood you correctly you want to know how to layout your project in order to avoid circular reference. In my opinion you need these projects(dlls)

  • Waqas.Base.dll containing all interfaces. no dependecy to unity or any other Waqas.*.dll
  • one or more dlls containing implementation of services, dal, ... (i.e. Waqas.Service.Payment.dll) that only depend on Waqas.Base.dll no dependecy to unity
  • One Bootstrapper component (ideally only one method) that knows Waqas.Base.dll and all other Waqas.*.dll. Its only responsibility is to wire up the system. This is the only component that knows unity.
  • your main application and your integrationtest use the bootstrapper.
  • if you have unittests you wire up your tests manually by replacing seriveces, dal, ... with mocks.

(Update) Example

waqas.service.payment needs access to dal without referencing the bootstrapper or unity:

change form old version

    public class PaymentService
    {
        public PaymentService();

        SavePayment( ...)
        {
                         IDAL dal = ioCContainer.resolve<IDAL>();
                         dal.Save(...);
        }
    }

to new version

    public class PaymentService
    {
        IDAL theDal;
        public PaymentService(IDAL dal) {theDal = dal;};

        SavePayment(...)
        {
             theDal.Save(...);
        }
    }

The bootstrapper is responsible for creating Dal and PaymentService and connection them with each other. IDal is defined in Waqas.Base.dll.

k3b
  • 14,517
  • 7
  • 53
  • 85
  • These are the project(dlls) i already have in place. but lets say i need to use dal in waqas.service.payment then it requires the payment project to add a bootstrapper reference to resolve the mapping. e.g. public void savepayment() { IDAL dal = ioCContainer.resolve } now iocContainer should be the isntance which knows all the registered types to resolve IDAL. and that cann't be achieved without the bootstrapper project reference in all service projects – Waqas Mar 14 '11 at 09:54
  • I totally agree with k3b. To summarize: use constructor injection pattern, not the service locator pattern. Don't use Unity in your unit tests, only (optionally) in your integration tests. Having circular references is often a sign of an incorrect design. k3b++. – Steven Mar 14 '11 at 10:23
  • thanks, but there is one more issue. A payment can either create dal with parameterized contructor(when it connects to a customer db) or default constructor(when it connects to the main db) and that depends on the function which is calling the dal. UpatePaymentToClient can use client db and UpdatePayment can call dal which is connected to main db. sorry for bothering you so much :) – Waqas Mar 14 '11 at 10:35
  • so you need two different instances of PaymentServe one, that is wired to maindb and one with a different dal-instance that is wired to a different database – k3b Mar 14 '11 at 10:43
  • @Waqas: Again I agree with k3b: It seems that that class has multiple responsibilities: You should separate them. And if that service connects to a db, it's impossible for it to have a default constructor, because that means that you aren't using dependency injection. Dependency injection is the way to go. A DI best practice is to let every service only have a single public constructor in which you inject all dependencies. – Steven Mar 14 '11 at 11:00
  • @Steven\@k3b we're developing a saas solution & are in multi-tenanat mode. So we don't know in advance the dbmwhich we are gona connect to. hence we introduced parameterized constructor for dal. e.g. our Fabric service creating a client will also create a new db for that client. that function will not only call Dal which wil be connected to mainDb to store clientinfo, it'll also create a dal object to connect to client db servers and create a new db & db user for client & update the mainDb with connstring. so one public constructor with creating dependent object doesn't solve our problem – Waqas Mar 14 '11 at 12:46
  • @Waqas: If you like, update your answer to show us the code for that particular part of your application. I am very certain that you can fix this by using the SOLID design principles. If you let me, I will show this to you. – Steven Mar 14 '11 at 15:29
  • @Waqas: if you cannot implement seperation of concerns you have to replace the dal-instance with a dal factory method/delegate. See [the so dependency-injection question/answers](http://stackoverflow.com/questions/5171779/dependency-injection/5177090) as an example how it can be done. – k3b Mar 15 '11 at 08:21