I'm trying to use DI to bind a different implementation of my networking class. I've been able to do this successfully using a none generic version of the class. My implementation is as follows:
class MainClass
{
public static void Main(string[] args)
{
IKernel kernel;
// Hardcode here but will be managed by build system.
bool runningInProd = false;
if (runningInProd)
{
kernel = new StandardKernel(new RealNetworkModule());
}
else
{
kernel = new StandardKernel(new FakeNetworkModule());
}
Session session = kernel.Get<Session>();
session.Authenticate();
}
public class RealNetworkModule : NinjectModule
{
public override void Load()
{
Bind(typeof(IRequestSender)).To(typeof(RealRequestSender));
}
}
public class FakeNetworkModule : NinjectModule
{
public override void Load()
{
Bind(typeof(IRequestSender)).To(typeof(FakeRequestSender));
}
}
}
Class that uses my IRequestSender:
public class Session
{
IRequestSender requestSender;
[Inject]
public Session(IRequestSender requestSender)
{
this.requestSender = requestSender;
}
public void Authenticate()
{
Console.WriteLine(requestSender.Send("Hello There"));
}
}
The IRequestSender interface:
public interface IRequestSender
{
string Send(string request);
}
And the two different implementations:
public class RealRequestSender: IRequestSender
{
public string Send(string request)
{
return "RealRequestSender right back at you: " + request;
}
}
public class FakeRequestSender: IRequestSender
{
public string Send(string request)
{
return "FakeRequestSender right back at you: " + request;
}
}
This is very straightforward and it works; however, what I need is for my IRequestSender to use Generic types rather than string for input output:
public interface IRequestSender<RequestT, ResponseT> where RequestT: class where ResponseT: class
{
RequestT Send(RequestT request);
}
And the impl's:
public class FakeRequestSender<RequestT, ResponseT> : IRequestSender<RequestT, ResponseT> where RequestT : class where ResponseT : class
{
public RequestT Send(RequestT request)
{
throw new NotImplementedException();
}
}
public class RealRequestSender<RequestT, ResponseT> : IRequestSender<RequestT, ResponseT> where RequestT : class where ResponseT : class
{
public RequestT Send(RequestT request)
{
throw new NotImplementedException();
}
}
I've come across several examples that address this issue and I've tried to base my implementation on them but I have failed. Here are the two problems that I'm running into:
1) Binding: this is the main problem. Here is what my binding looks like based on solutions I have seen online:
public class RealNetworkModule : NinjectModule
{
public override void Load()
{
Bind(typeof(IRequestSender<>)).To(typeof(RealRequestSender<>));
}
}
VSCode gives me the error:
Program.cs(29,29): Error CS0305: Using the generic type 'IRequestSender<RequestT, ResponseT>' requires 2 type arguments (CS0305) (DI)
Based on this error and what I have read online it is still not clear to me what I need to do here.
2) Accessing IRequestSender: the solution to this might be clear once I know how to fix binding. In the original implementation I used [Inject] to get access to the IRequestSender I need in my Sessions class. However now in the generic version I imagine I will not be able to do this. If I were to use RequestSender without DI it would look like:
RequestSender <AuthRequest, AuthResponse> requestSender = new RequestSender<AuthRequest, AuthResponse>();
or
RequestSender <UserRequest, UserResponse> requestSender = new RequestSender< UserRequest, UserResponse >();
for any number of different types.
So I'm not sure how to go about accessing the RequestSender in this scenario.
Using the generic type 'IRequestSender<RequestT, ResponseT>' requires 2 type arguments
is significant... try changing your binding toBind(typeof(IRequestSender<,>)).To(typeof(RealRequestSender<,>));
(note the commas). - xander