Captive Dependency in .NET Core

In this article, I will show you how to handle captive Dependency in the .net core application. Before going into code, let’s get familiarize with some terms.

What is captive Dependency?

A service should not depend on a service with a lifetime shorter than its own. For example, A service registered with a singleton, then it should not depend on the transient.

Dependency Injection lifetime

.NET core DI system supports three types of lifetime

  • Singleton

Singleton lifetime services are created when they’re requested first time.Register service with AddSingletion{alertInfo}

  • Transient

Transient lifetime services are created each time they’re requested from the service container.Register Service with AddTransient{alertInfo}

  • Scoped

For web applications, a scoped lifetime indicates that services are created once per client request (connection). Register scoped services with AddScoped.{alertInfo}

How to know its captive Dependency

.NET core, by default, verifies the scope in development while its skip in production because of performance issue. When you wrongly registered the Dependency in your application, .net core will throw the following error.

Cannot consume scoped service from singleton service.

DI

Let’s understand this with a real-world example.

void Main()
{
	var container = Startup.Configure();
	var customerService = container.GetService<ICustomerService>();
	customerService.GetData();

}

public class Startup
{


	public static ServiceProvider Configure()
	{
		var provider = new ServiceCollection()
					.AddScoped<IDataService, DataService>()
					.AddLogging(fs => fs.AddConsole())
					.AddSingleton<ICustomerService, CustomerService>()
					.BuildServiceProvider();
		return provider;
	}

}

IDataService

public interface IDataService
{
	void GetData();
}

ICustomerService

public interface ICustomerService
{
	void GetData();
}

public class DataService : IDataService
{
	private readonly ILogger _logger;

	public DataService(ILogger<DataService> logger)
	{
		_logger = logger;

	}

	public void GetData()
	{
		_logger.LogInformation("Getting Data From DataBase");

	}

}

public class CustomerService : ICustomerService
{
	private readonly ILogger<CustomerService> _logger;
	private readonly IDataService _dataService;
	public CustomerService(ILoggerFactory loggerFactory, IDataService dataService)
	{
		_logger = loggerFactory.CreateLogger<CustomerService>();
		_dataService = dataService;
	}

	public void GetData()
	{
		_dataService.GetData();
	}
}

If you run the application, you will get the output. But we can see that our code has captive Dependency. Let’s enable to validate scope. Open Startup.cs and add the following line.

	.BuildServiceProvider(validateScopes:true);

If you run the application, you will get the following error.

Cannot consume scoped service ‘IDataService’ from singleton ‘ICustomerService’.

How to solve it

There are two ways to solve the problem.

  • Implementation factory
  • Changing the Code
  • Disable the scope validation - Not Recommended
public class CustomerService : ICustomerService
{
	private readonly ILogger<CustomerService> _logger;
	private readonly IServiceProvider _serviceProvider;
	public CustomerService(ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
	{
		_logger = loggerFactory.CreateLogger<CustomerService>();
		_serviceProvider = serviceProvider;
	}

	public void GetData()
	{
		using (var scope = _serviceProvider.CreateScope())
		{
			var _dataService = (IDataService)scope.ServiceProvider
			  .GetRequiredService(typeof(IDataService));
			_dataService.GetData();

		}

	}
}

After making the above changes, if you run the application, it will not throw any error.

References

Please do not post any spam link in the comment box😊

إرسال تعليق (0)
أحدث أقدم