How to correctly implement dependency injection in an ASP.NET Core project? There is an authentication service in the project, and I need to create two implementations. First with fake data and second works with database.
Interface:
public interface IAuthenticationService<TRequest, TResponse> : IService
where TRequest : IRequest
where TResponse : IResponse
{
Task<TResponse> Auth(TRequest request);
}
Two implementations like this:
public class DummyAuthenticationService<TRequest, TResponse>
: IAuthenticationService<TRequest, TResponse>
where TRequest : AuthenticateRequest
where TResponse : AuthenticateResponse
{
public Task<TResponse> Auth(TRequest request)
{
throw new NotImplementedException();
}
}
Controller:
[HttpPost]
public async Task<IResponse> AuthenticationViaYouTube(AuthenticateRequest parr)
{
AuthenticateResponse response = (AuthenticateResponse) await _authenticationService.Auth(parr);
return response;
}
Startup.cs
:
public void ConfigureServices(IServiceCollection services)
{
#if DEBUG
services.AddSingleton<IAuthenticationService<IRequest, IResponse>>
(new DummyAuthenticationService<AuthenticateRequest, AuthenticateResponse>());
#elif Release
services.AddSingleton<IAuthenticationService<IRequest, IResponse>>
(new DBAuthenticationService<AuthenticateRequest, AuthenticateResponse>());
#endif
}
But I get a compiler error:
Error CS1503 Argument 2: cannot convert from 'DummyAuthenticationService<AuthenticateRequest, AuthenticateResponse>' to 'System.Func<System.IServiceProvider, IAuthenticationService<IRequest,IResponse>>'
CodePudding user response:
You are getting a compile error for the same reason as this code would give you a compile error:
IAuthenticationService<IRequest, IResponse> service =
new DummyAuthenticationService<AuthenticateRequest, AuthenticateResponse>();
The C# compiler is telling you that the created instance is not convertible to IAuthenticationService<IRequest, IResponse>
.
This has to do with variance. Covariance and contravariance is a complicated topic, which is hard for me to explain in a few sentences. There's is actually great Microsoft documentation on this topic, which I encourage you to check out.
Although to support variance interfaces can be marked with in
and out
parameters, that not get your code to compile. Instead, to get this compiling, you must change the code to the following:
IAuthenticationService<AuthenticateRequest, AuthenticateResponse> service =
new DummyAuthenticationService<AuthenticateRequest, AuthenticateResponse>();
And, therefore, your ConfigureServices
method to the following:
services
.AddSingleton<IAuthenticationService<AuthenticateRequest, AuthenticateResponse>>(
new DummyAuthenticationService<AuthenticateRequest, AuthenticateResponse>());
Or, alternatively:
services.AddSingleton(
typeof(IAuthenticationService<,>),
typeof(DummyAuthenticationService<,>));
CodePudding user response:
I believe you are getting a compile error because IRequest and IResponse cannot be resolved. I do not think you can provide interfaces as generics when trying to bind using the DI. Try providing concreate classes.
services.AddSingleton<IAuthenticationService<AuthenticateRequest, AuthenticateResponse>>
(new DummyAuthenticationService<AuthenticateRequest, AuthenticateResponse>());
As for your "if debug" problem - there are 1000 different ways to solve this problem. I personally prefer letting the appSettings decide rather than debugger comments.
Here is how I would do it.
- Have two appsettings.json files, one for development and one for production.
- Add a boolean called "MockServices" or something.
- Change your bindings depending on the boolean.
The advantage of this is you can easily mock services in a production environment if needed.
Let me know if you need me to expand on anything.