简体   繁体   中英

Unity - How to avoid circular reference?

I'm trying to implement dependency injection in my ASP.NET MVC Project using Unity and would like some advice on how to avoid circular references.

At my work we used to implement the service locator pattern, which returned a singleton for each individual service of the application.

public class ServiceWrapper 
{
  private UserService _userService;
  private ProductService _productService;


  public UserService User
  {
    if(_userService == null) 
    {
      _userService = new UserService();
    }
    return _userService;
  }

  public ProductService Product
  {
    if(_productService == null) 
    {
      _productService = new ProductService();
    }
    return _productService;
  }
}

Then in the controller, you could easily access all the services by instantiating the ServiceWrapper and calling methods, like:

private ServiceWrapper _services = new ServiceWrapper();

public ActionResult Index()
{
  List<Product> products = _services.Product.GetProducts();
  return View(products);
}

Setting up DI using Unity was a breeze. I created a container in Application_Start() (global.asax), like so:

var container = new UnityContainer();
container.RegisterType<IUserService, UserService>(new ContainerControlledLifetimeManager());
container.RegisterType<IProductService, ProductService>(new ContainerControlledLifetimeManager());
container.RegisterType<IServiceWrapper, ServiceWrapper>(new ContainerControlledLifetimeManager());
DependencyResolver.SetResolver(new UnityDependencyResolver(container));

The ServiceWrapper is registered as a Singleton. And implemented constructor injection as follows:

public class ProductController: Controller
{
  private IServiceWrapper _services;

  public ProductController(IServiceWrapper services)
  {
    _services = services;
  }

  public ActionResult Index()
  {
    List<Product> products = _services.Products.GetProducts();
    return View(products);
  }

That worked beautifully. But then I came accross the problem.

We like every service to also have a property containing the ServiceWrapper, so that you can easily access the other services from within another , like so:

public class ProductService
{
   private IServiceWrapper _services;

  public ProductService(IServiceWrapper services)
  {
    _services = services;
  }

  public IServiceWrapper Services { get { return _services; } }
}

But when I implemented constructor injection of the ServiceWrapper in the individual services, it resulted in a stackoverflow exception due to circular referencing.

I read that Unity does not support circular referencing. Is there a (solid) way around this. Or should I implement a different architecture? If so, could you recommend a solution?

The way this is typically done is to declare just the services you need and have them ctor-injected. Don't inject a "ServiceWrapper" which just contains everything. Inject what you need. As the container builds up your type you don't have to worry about providing the services. They will be just there.

The development workflow often goes like this:

  1. Add a new dependency injected field
  2. Delete the existing ctor
  3. Regenerate the ctor using Resharper: alt+ins, generate ctor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM