1

I have a IItemProcessor class which takes each item from a list and send it to a web API (IApiService). The processing is done asynchronously, on another thread.

If web API responds with 'user not authorized', app needs to logout. For this, I have an IApp which has LogoutUser() method.

Currently, the ItemProcessor implementation catches errors thrown by IApiService and if the error is 'not authorized', it calls IApp:LogoutUser.

The issue is in the implementation of IApp:LogoutUser I need to call IItemProcessor:Stop to stop processing. Which means there's a circular dependency between App and `ItemProcessor.

I'm using Dependency Injection in the c-tor and this gives me infinite recursive construction of the concrete objects:

public class App : IApp 
{
   public App(IItemProcessor itemProcessor)
   {
    ...
   }

   public void Logout() 
   {
       _itemProcessor.Stop(); 
   }
}

public class ItemProcessor : IItemProcessor 
{
    public ItemProcessor (IApp app)
    {
      ...
    }

    public void Stop() {
      ...
    }

    void Run() 
    {
        ... for each item in list ..
         try
         {
            ... try send item ....
         }
         catch(UserNotAuthorizedException)
         {
             _app.Logout();
         }
    }
}

How can I fix this?

IApp needs to know about IItemProcessor to start and stop it on user login and logut. But I feel like IItemProcessor breaks SRP, it shouldn't actually call Logout, but rather somehow inform "someone" about the error, and that "someone" has in turn the responsability to call IApp:LogoutUser. But what should this "someone" be? Should it be a listener to the item processor errors?

I'm having a hard time figuring out how to split responsibilities.

I tried to use command pattern by having a LogoutCommand

public class LogoutCommand
{
    readonly IApp _app;

    public LogoutCommand(IApp app)
    {
        _app = app;
    }

    public void Execute()
    {
        _app.UserLogout();
    }
}

the ItemProcessor implementation could call logoutCommand.Execute(). This would decouple ItemProcessor from knowing about App, but I have the same issue because when App c-tor calls ItemProcessor c-tor which calls LogoutCommand which calls App c-tor.

Another (bad) idea: I thought a factory could alleviate this issue. I thought having a ILogoutCommandFactory factory which creates the LogoutCommand. As long as I didn't create the LogoutCommand in the c-tor of ItemProcessor, I thought it could work. But the fact that I can't do that, feels to me like code smell.

To me DI in c-tor seems to start looking like an issue.

  • Does App tell IItemProcessor to process? Catch the notauthorized exception from the code the calls Run and call logout then. Alternately you can have a NotAuthorized event on the IItemProcessor interface. App hooks into it and calls Logout. – Andy May 2 '17 at 22:46
4

Technically, there is no cyclic dependency. When I understood you correctly, App depends on the interface IItemProcessor, and not on its implementation ItemProcessor. Also, ItemProcessor depends on IApp, and not on App. However, you will need to switch to property injection for at least one of the classes, this will look like

public class App : IApp 
{
   public App(IItemProcessor itemProcessor)
   {
      itemProcessor.TheApp = this;
   }
}

public class ItemProcessor : IItemProcessor 
{
    public ItemProcessor ()
    {
      ...
    }

    public IApp TheApp{get;set;}

}

However, to decouple your components even more, or if your DI framework still has problems with this, IApp could provide a publisher/subscriber mechanism (AKA observer pattern) for something like a "BeforeLogout" event. In a similar manner, IItemProcessor could provide a publisher/subscriber mechanism for "not authorized" events it gets from the IApiService. For example, in C# this could look like

interface IItemProcessor
{
    void SubscribeToUserNotAuthorized(Action<Exception> observer);
}

and

public ItemProcessor() : IItemProcessor
{
    List<Action<Exception>> notAuthorizedObservers;

    public void SubscribeToUserNotAuthorized(Action<Exception> observer)
    {
        notAuthorizedObservers.Add(observer);
    }

    // and somewhere below

    // ...
         catch(NotAuthorizedException ex)
         {
            foreach(var observer in notAuthorizedObservers)
               observer(ex);
         }
}
| improve this answer | |
  • ninja'ed. pub/sub observer is something i have use in the past and was typing up a reply with. – RubberChickenLeader May 2 '17 at 18:56
  • I edited my question. Issue is I am using DI in c-tor which gives me infinite creation of the objects. – Daniel May 2 '17 at 18:59
  • What does "technically" mean? If technically there is no cyclic dependency, why does the DI gets in the way? I feel like cyclic dependency is a sign of bad design. Like I mentioned, I think in my case, the processor shouldn't know to call logout, it breaks SRP. Or maybe it doesn't? HELP! :) – Daniel May 2 '17 at 19:15
  • I edited it again. I tried to use command pattern but with same result. – Daniel May 2 '17 at 19:31
  • @DonBox: see my edit. – Doc Brown May 2 '17 at 20:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.