Help working around circular dependencies

MattNorman

Well-known member
Joined
May 22, 2021
Messages
98
Programming Experience
1-3
I am currently in the process of writing some Windows Services to replace logic that is currently done within a WPF app.

There will be several service projects and a class library project for utilities/helpers.

I am having some issues figuring out the best way to structure the class library and at the moment it has circular dependencies causing stack overflows.

I am struggling to understand how to strip out the dependencies to resolve this while maintaining the functionality that I need.

An example of one of the dependencies is as follows:

Windows Service -> DataManagerLogs -> DataHelper -> RegistryManager -> DataManagerLogs

DataManagerLogs: Contains methods for logging to database
DataHelper: Contains methods for getting database connection info
RegistryManager: Contains methods for getting settings from registry

The RegistryManager ultimately loops back to creating a DataManagerLogs class as it needs to log errors itself.

In the WPF app these were all static classes however I have now changed them to non-static so that each windows service can spawn their own instances for logging to different files etc.

Can anyone offer any advice on how I can restructure this?
 
One thing I have tested works but I am guessing it would be bad practice.

I create a wrapper class for each service.

The wrapper class creates an instance of each utility class that is needed.

For each utility class, it's required classes are then set as references from the wrapper.

Example:

C#:
public class UtilsWrapper
{
    public Data DataUtils { get; set; } = new Data();
    public Registry RegistryUtils { get; set; } = new Registry();

    public UtilsWrapper()
    {
        DataUtils.RegistryUtils = RegistryUtils;
        RegistryUtils.DataUtils = DataUtils;
    }
}
 
Presumably this all used to work because you used to have singletons, but now you have to actually instantiate the objects?

It may be time to break up one or two of the classes.
 
Logging and config are perhaps good examples of aspects of software; perhaps some reading on aspect oriented programming will help. They're also things that, these days, are often handled by dependency injection; it should be the service that decides where it logs to, rather than the serivce using the logger class and the logger deciding where it logs to. The service can be responsible for creating loggers and giving them to the logging framework; it doesn't care where they put them. In this way the service and its components use the loggers given to them by elsewhere rather than making their own. The logger isn't reliant on anything further up the tree; the further up the tree thing gets the thing the logger needs and gives it to the logger. Config is perhaps simpler in this regard because it's nearly universally a read-thing; every level of a complex hierarchy can read its config

I'd say take a look at how we do config and logging in a modern, dependency injected .net core app and ponder on why these cycles don't arise so much
 
Logging and config are perhaps good examples of aspects of software; perhaps some reading on aspect oriented programming will help. They're also things that, these days, are often handled by dependency injection; it should be the service that decides where it logs to, rather than the serivce using the logger class and the logger deciding where it logs to. The service can be responsible for creating loggers and giving them to the logging framework; it doesn't care where they put them. In this way the service and its components use the loggers given to them by elsewhere rather than making their own. The logger isn't reliant on anything further up the tree; the further up the tree thing gets the thing the logger needs and gives it to the logger. Config is perhaps simpler in this regard because it's nearly universally a read-thing; every level of a complex hierarchy can read its config

I'd say take a look at how we do config and logging in a modern, dependency injected .net core app and ponder on why these cycles don't arise so much

I have re-designed things so that the service spins up a logger and then tells the logger where to log to. I have also stripped out the loggers dependency on the data methods such as creating the connection string. This info is obtained in the service and passed to the logger when something needs logging to the database.

With this new structure I probably could have stuck with static classes. I tend to use static classes a lot which is where my lack of structuring comes from with non-static classes.

Appreciate the feedback.
 
"I tend to use static classes a lot which is where my lack of structuring comes from with non-static classes."

Yea, but static is generally the abomination that destroys decent OO principles; you're in a better place for having avoided it
 

Latest posts

Back
Top Bottom