如何彻底解决IoC循环引用?

发布于 2024-10-21 23:01:54 字数 2740 浏览 3 评论 0原文

可能的重复:
依赖注入可以防止循环依赖吗?

我正在开发一个框架将有各种服务,如 dal、与共享点集成、异常处理等。

我需要在 IoC 中完成它,并且我对这种方法很陌生。[似乎有关于我正在做的事情的循环引用]

所以在我看来,我们将有三种类型的项目

  • 接口:最好是一个单独的项目
  • 具体类项目(如异常、dal、集成等服务项目)实现接口
  • bootstrapper\configurator(配置器):最好是一个单独的项目,如果它驻留在“接口”项目中它将创建与具体类项目的循环引用,因为 IoC 需要接口和具体类的引用。

现在的事情是

  1. 具体类不应该引用任何其他具体类,因为这最终会创建循环引用。(如果存在循环引用,它是否会杀死 IoC 的整个目的,或者我错了这里?)。

  2. 其次,启动项目(单元测试、WCF服务等)应该首先加载引导程序以注册所有类型,所以我应该将引导程序项目添加到启动项目中,创建一个统一容器的实例[singleton]注册所有类型。为了解决这些类型,我需要在每个其他服务项目中使用相同的实例。

所以我必须将引导程序项目添加到服务项目中以进行类型解析。这种方法感觉不对,因为它会导致与我在第 1 点中提到的相同问题(每个服务项目都将包含服务项目的引用)。

该怎么办呢?我尝试在注册时通过属性注入将 UnityContainer 添加为每个具体类中的属性。我什至不确定这是否是正确的方法。我主要关心的是实现结果的最佳实践,因此,如果您能指导我完成此操作,我将非常感激...

提前感谢您!

还有一件事,您更喜欢哪种方式来提高性能、配置、代码内类型注册或实例注册?

如果需要,我可以上传演示项目。我可以解释一件事。 Dal 使用异常管理器,异常管理器使用转换器来获取用户友好的消息,转换器使用 DAL 来获取用户友好的消息。这是我们有循环引用的一种情况。但如果我们互相参考的话,可能会有很多。

[更新 - 包含示例代码] 我们还没有实现 IoC,所以你不会看到任何对它的引用 公共布尔更新() {
布尔结果=假;

        //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;
    }

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;
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

淡淡的优雅 2024-10-28 23:01:54

与任何循环引用一样,您需要查看代码本身的实际架构。将 IoC/DI 放在一边,看看循环引用发生在哪里并进行重构。这些参考资料真的需要存在吗?您可以使用更好的设计吗?

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?

最美不过初阳 2024-10-28 23:01:54

注意:我对 Unity 不太了解,但我与其他 ioc 容器一起工作过,

如果我理解正确的话,你想知道如何布局你的项目以避免循环引用。在我看来,您需要这些

  • 包含所有接口的项目(dll)Waqas.Base.dll。不依赖于 unity 或任何其他 Waqas.*.dll
  • 一个或多个 dll,其中包含仅依赖于 Waqas.Base.dll 的服务、dal、...(即 Waqas.Service.Payment.dll)的实现 不依赖于 unity
  • One知道 Waqas.Base.dll 和所有其他 Waqas.*.dll 的引导程序组件(最好只有一种方法)。它唯一的职责是连接系统。这是唯一知道统一的组件。
  • 您的主应用程序和集成测试使用引导程序。
  • 如果您有单元测试,您可以通过用模拟替换 seriveces、dal 等来手动连接测试。

(更新)示例

waqas.service. payment 需要访问 dal,而不引用 bootstrapper 或 unity:

将旧版本更改

    public class PaymentService
    {
        public PaymentService();

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

为新版本

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

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

bootstrapper 负责创建 Dal 和 PaymentService 并将它们相互连接。 IDal 在 Waqas.Base.dll 中定义。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文