C# generics basic knowledge? - c#

I have following two classes
public class CommandFetcher : ICommandFetcher
{
private readonly Dictionary<TypeAndVersion, Type> _configuration;
public CommandFetcher(Dictionary<TypeAndVersion, Type> configuration)
{
_configuration = configuration;
}
public ICommand FetchFrom(MessageEnvelope messageEnvelope)
{
TypeAndVersion typeAndVersion = new TypeAndVersion(messageEnvelope.MetaData.MessageType,
messageEnvelope.MetaData.MessageTypeVersion);
return (ICommand)JsonConvert.DeserializeObject(messageEnvelope.MessageData, _configuration[typeAndVersion]);
}
}
and
public class MessageDeserializer : IMessageDeserializer
{
private readonly IDictionary<TypeAndVersion, Type> _configuration;
public MessageDeserializer(IDictionary<TypeAndVersion, Type> configuration)
{
_configuration = configuration;
}
public IMessage Deserialize(string messageData, IMetaData metaData)
{
var typeAndVersion = new TypeAndVersion(metaData.MessageType, metaData.MessageTypeVersion);
if (!_configuration.ContainsKey(typeAndVersion))
throw new InvalidOperationException("Invalid version");
return (IMessage) JsonConvert.DeserializeObject(messageData, _configuration[typeAndVersion]);
}
}
i rewrite the configuration part in both class
but now i want to get that configuration from MessageDeserializer class into CommandFetcher class
how can i do it ?
Thank you !

No idea if I am reading your question correctly...but it sounds like you are wanting to instantiate a CommandFetcher from within the MessageDesrializer?? If this is correct you could try making the Dictionary on the CommandFetcher an IDictionary instead of a Dictionary

There are multiple problems in your question:
You are not saying anything about the dependencies between the classes. Does one use the other?
You are not sharing what configuration actually is. Does each class need their own configuration?
So here is my guess: Your two classes actually use the same _configuration. In that case, this has nothing to do with generics. All you need to do is pass the same Dictionary to both object constructors.

If you are attempting to make a single generic method that handles both those cases it would look something like this:
public class GenericDeserializer<T> : IGenericDeserializer
{
private readonly IDictionary<TypeAndVersion, Type> _configuration;
public GenericDeserializer(IDictionary<TypeAndVersion, Type> configuration)
{
_configuration = configuration;
}
public T Deserialize(string messageData, IMetaData metaData)
{
var typeAndVersion = new TypeAndVersion(metaData.MessageType, metaData.MessageTypeVersion);
if (!_configuration.ContainsKey(typeAndVersion))
throw new InvalidOperationException("Invalid version");
return (T)JsonConvert.DeserializeObject(messageData, _configuration[typeAndVersion]);
}
}
That said, you would need to normalize ICommand and IMessage as well as create a generic interface for ICommandFetcher and IMessageDeserializer.

Related

How can I avoid repeated derived class constructors that are identical to the base class?

I'm using .NET 7 Preview with ASP.NET to wrap a bunch of WCF services so they're REST. Each service has its own controller and I'm using dependency injection with the constructor.
Each WCF service is automatically generated with its own client and a couple methods that I use delegates on the base class (MyBaseController) to handle all the logic and things.
The problem is I need the injected dependencies, but if I change the base constructor, I have to modify 40+ derived classes.
Below is the basic concept I'm using, but ideally the derived classes would only contain delegate overrides and the class definition providing the generics.
You can see for derived classes A/B, I have to have a constructor.
Questions:
Is there another method of dependency injection where I don't have to declare them in the constructor? This would allow me to handle it in the base class and then keep a simple constructor in the derived classes.
Can I inherit the base constructor somehow? - I don't think there is with older versions of .NET so I was hoping .NET 7 might have some new magic I didn't know about.
Should I be moving all of my constructor needs into a service class and then just passing that everywhere to the controllers?
Code:
[ApiController]
[Route("[controller]")]
public abstract class MyBaseController<DerivedClient, MyRequest, MyResponse> : ControllerBase
where DerivedClient : HttpClient, new()
{
protected DerivedClient _derivedClient;
protected readonly ILogger _logger;
public IConfiguration _configuration;
protected IOptions<MyOptions> _options;
public abstract Func<MyRequest, Task<MyResponse>> MyClientDelegate { get; }
protected MyBaseController(ILogger<DerivedClient> logger, IOptions<MyOptions> options, IConfiguration configuration)
{
// I need these dependencies though, and with a simple constructor (i.e. MyBaseController()),
// I can't access them.
_derivedClient = new();
_logger = logger;
_options = options;
_configuration = configuration;
}
[HttpGet, Route("GetTheData")]
public Task<MyResponse> GetTheData(MyRequest request)
{
return MyClientDelegate(request);
}
}
public class A : MyBaseController<AClient, string, string>
{
// How can I avoid having this in every derived class when they're all essentially identical?
public A(ILogger<AClient> logger, IOptions<MyOptions> options, IConfiguration configuration) : base(logger, options, configuration) { }
// I only want my derived classes to have the delegate
public override Func<string, Task<string>> MyClientDelegate => _derivedClient.GetDataA;
}
public class B : MyBaseController<BClient, string, string>
{
// How can I avoid having this in every derived class when they're all essentially identical?
public B(ILogger<BClient> logger, IOptions<MyOptions> options, IConfiguration configuration) : base(logger, options, configuration){ }
// I only want my derived classes to have the delegate
public override Func<string, Task<string>> MyClientDelegate => _derivedClient.GetDataB;
}
public class AClient : HttpClient
{
public AClient() { }
public Task<string> GetDataA(string request)
{
return Task.FromResult($"A Request: {request}");
}
}
public class BClient : HttpClient
{
public BClient() { }
public Task<string> GetDataB(string request)
{
return Task.FromResult($"B Request: {request}");
}
}
I don't think there's a way to avoid having all the constructors with the same declarations.
I believe it's a language design decision, since depending on how it is implemented it could bring some other issues*, although I feel it would be nice to have some other way to do it.
A possible improvement might be to encapsulate all of your dependencies in a new class, so that would be the class injected everywhere. If any new dependency appears you'd only change that class.
Something like this:
public abstract class Base<DerivedClient> : where DerivedClient : HttpClient, new()
{
protected DependencyContainer _dependencyContainer;
protected DerivedClient _derivedClient;
protected MyBaseController(DependencyContainer<DerivedClient> dependencyContainer)
{
_dependencyContainer = dependencyContainer;
_derivedClient = new();
}
}
The DependencyContainer would be:
public class DependencyContainer<DerivedClient> : where DerivedClient : HttpClient
{
public readonly ILogger<DerivedClient> logger;
public IConfiguration configuration;
public IOptions<MyOptions> options;
public DependencyContainer(
ILogger<DerivedClient> logger,
IOptions<MyOptions> options,
IConfiguration configuration,
... future new ones)
{
this.logger = logger;
this.options = options;
this.configuration = configuration;
... future new ones
}
}
And every derived class would remain like this:
public A : Base<AClient>
{
public A(DependencyContainer<AClient> dependencyContainer) : base(dependencyContainer) { }
public void Method()
{
_dependencyContainer.logger.log(":)");
_dependencyContainer. ... all other dependencies ...
_derivedClient.GetDataA("test"); // Method from AClient is accessible because we inherit from Base<AClient>
}
}
Then you should remember to add the new DependencyContainer to the service collection in Program.cs:
builder.Services.AddScoped(typeof(DependencyContainer<>), typeof(DependencyContainer<>));
I don't love it, but it makes only one class change when you want to inject something new.
* I kept digging into this and found a comment in another question that links to a MSDN post that might explain this better

Can we call a parameterized constructor from a parameterless constructor?

For example I have class like this
public class ABC
{
private readonly IMemoryCache _cache;
private readonly IConfiguration _config;
private readonly IDistributedCache _distributedCache;
public ABC(IMemoryCache memoryCache, IConfiguration config, IDistributedCache distributedCache)
{
_cache = memoryCache;
_config = config;
_distributedCache = distributedCache;
}
public ABC() : this(IMemoryCache , IConfiguration ,IDistributedCache )
{
}
}
As you can see that I have tried to call a Parameterized constructor from a Parameter-less constructor, but that's not possible. Is there any other way to achieve this concept?
You need to pass in concrete implementations of those interfaces, It's just like calling a method. There is nothing magical about this() syntax apart from where it appears. For example if you have a default implementation of IMemoryCache implemented in class DefaultMemoryCache you can just 'new that up' and pass it in:
public ABC() : this(new DefaultMemoryCache(), etc.)
{
}
Alternatively, you can use a static factory method if constructing these dependencies is a bit too complicated:
public static ABC CreateNew()
{
var others = ...
var cache = new DefaultCache(others, etc.)
...
return new ABC(cache, etc.);
}
But if you want to be able to use the interface as your input, this is what you can do: (Now, this is just an example to make a point, I do not recommend doing this since it would be very confusing and fragile)
public ABC() : this
(
(IMemoryCache) Activator.CreateInstance
(
Assembly.GetExecutingAssembly().GetTypes().First
(
t => typeof(IMemoryCache).IsAssignableFrom(t) && !t.IsInterface
)
)
)
{
}
The reflection code snippet above, in essence, what a dependency injection library would do, and you might want to consider using one if your project is suitable for it.
One last thing, just to have a complete answer, of course, you can also implement a body in your overloaded contractors:
public class ABC
{
private readonly ICache _cache;
public ABC()
{
_cache = new Cache();
}
public ABC(ICache cache)
{
_cache = cache;
}
}
: this() syntax is only required if you want to call other constructors in the same class for code reuse.
use instances not types. create an instance of what ever class fulfills your Interface.
public class ABC
{
private readonly IMemoryCache _cache;
private readonly IConfiguration _config;
private readonly IDistributedCache _distributedCache;
public ABC(IMemoryCache memoryCache, IConfiguration config, IDistributedCache distributedCache)
{
_cache = memoryCache;
_config = config;
_distributedCache = distributedCache;
}
public ABC() : this(new MemoryCache(), new Configuration(), new DistributedCache() )
{
}
}

Autofac inject IEnumerable of generic interfaces

So, I recognize StackOverflow is littered with this question, but frequently no one explains why they want to do this. I'm hoping that by doing so a better answer floats to the top.
This guy did something close to what I want: Resolving IEnumerable of generic interfaces from Autofac container But not quite.
I recognize IGenericInterface<ObjectA> is not equivalent to IGenericInterface<ObjectB>.
That being said, I'd love to inject every IService<T> into a single constructor so that I can build a lookup. Honestly, I'd like to build an implementation very similar to DbContext.Set<T>
A few key players in my problem.
public interface IService<TMessage> where TMessage: IContractDTO
{
IQueryable<TMessage> BuildProjection();
}
Currently I'm injecting these one at a time
public class SomeController : BaseODataController<SomeEntityDTO>
{
public SomeController(IControllerServiceContext context, IService<SomeEntityDTO> service)
: base(context, service)
{
}
//DO STUFF
}
IControllerServiceContext is a composite interface with DbContext, AppSettings, and a few other common goodies I want in every controller.
In most cases this is good enough. However occasionally in support of logic for EntityA, I might need to do a quick lookup on B. I'd rather use IService<SomeEntityB>'s implementation of BuildProjections() than building out a redundancy in Controller A. If I inject each one I have a few that would become an 8 or 9 param constructor this way, for example
SO I got to thinking what if I was able to add an IServiceLookup to IControllerServiceContext then I would have everything I needed.
I Started down this path:
public class ServiceLookup<TContract>: IServiceLookup where TContract: BaseClass, IContractDTO
{
public ServiceLookup(IEnumerable<IService<TContract>> services)
{
//Build _Services
}
private readonly IDictionary<Type, object> _services;
public IService<TMessage> Service<TMessage>() where TMessage : class, IContractDTO
{
return (IService<TMessage>)(GetService(typeof(TMessage)));
}
private object GetService(Type type)
{
_services.TryGetValue(type, out var service);
return service;
}
}
For obvious reasons this can't be done with the current constructor.
But is there a way to get the dictionary that I do want, either by IIndex or an IEnumerable that I can build that dictionary of <type, object> where object is my various IService<T>?
Service lookup was built based on reading the DbContext code and simplifying the logic for DbContext.Set, which is also driven by IDictionary<Type, object>.
If through some kind of resolver parameter I can get all the IService<T>s, Extract the T types, and add them to that list, I'm off to the races.
Edit: I recognize I could inject the parameters I need to build each service
into ServiceLookup and manually build my list, and that may even be the better answer... but if I can do it without all that, it would be a lot more robust, and I'm fundamentally curious if it is possible
Edit2: What I want to be able to do in implementation would look like this:
public SomeController(IControllerServiceContext context, IServiceLookup lookup)
: base(context, service)
{
public SomeMethod() {
var x = lookup.Service<EntityOneDTO>().BuildProjections().FirstOrDefault();
var y = lookup.Service<EntityTwoDTO>().BuildProjections().FirstOrDefault();
//Do Logic that requires both EntityOne and EntityTwo
}
}
Let's assume you have the following types :
public class MessageA { }
public class MessageB { }
public interface IService<TMessage> { }
public class ServiceA : IService<MessageA> { }
public class ServiceB : IService<MessageB> { }
And you have a controller and you want to get a IService<MessageA> based on whatever you want.
The first solution would be to inject all IService you may required :
public class Controller
{
public Controller(IService<MessageA> serviceA, IService<MessageB> serviceB)
{
this._serviceA = serviceA;
this._serviceB = serviceB;
}
private readonly IService<MessageA> _serviceA;
private readonly IService<MessageB> _serviceB;
public void Do()
{
IService<MessageA> serviceA = this._serviceA;
}
}
It works if you have few message type but not if you have more than few.
because IService<T> is generic and Do there is no easy way to mix both world. The first solution would be to introduce a non generic interface
public interface IService { }
public interface IService<TMessage> : IService { }
and register these type like this :
builder.RegisterType<ServiceA>().As<IService<MessageA>>().As<IService>();
builder.RegisterType<ServiceB>().As<IService<MessageB>>().As<IService>();
Then you can have an IEnumerable<IService>. Something like that :
public interface IServiceLookup
{
IService<TMessage> Get<TMessage>();
}
public class ServiceLookup : IServiceLookup
{
public ServiceLookup(IEnumerable<IService> services)
{
this._services = services
.ToDictionary(s => s.GetType()
.GetInterfaces()
.First(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(IService<>))
.GetGenericArguments()[0],
s => s);
}
private readonly Dictionary<Type, IService> _services;
public IService<TMessage> Get<TMessage>()
{
// you should check for type missing, etc.
return (IService<TMessage>)this._services[typeof(TMessage)];
}
}
and then inject IServiceLookup inside your controller.
The drawback of this solution is that it create instances of all your IService, to avoid that you can inject IEnumerable<Func<IService>>
Another solution would be to inject IComponentContext to ServiceLookup. ComponentContext is an Autofac type from where you can resolve services.
public class ServiceLookup : IServiceLookup
{
public ServiceLookup(IComponentContext context)
{
this._context = context;
}
private readonly IComponentContext _context;
public IService<TMessage> Get<TMessage>()
{
return this._context.Resolve<IService<TMessage>>();
}
}

Instantiating a class

Below is my sample code. I have this class whose constructor takes an IConfigurationRoot parameter and uses it to set a private field:
public class MyClass
{
private IConfigurationRoot _configuration;
public class MyClass(IConfigurationRoot configuration)
{
// I believe this has been injected
_configuration = configuration;
}
}
Now I want to instantiate that class:
public class AnotherClass
{
private IConfigurationRoot _configuration;
private MyClass myclass;
public SomeMethod()
{
// My _configuration here gets null in the debugger
MyClass myclass = new MyClass(_configuration);
// Rest of method omitted...
}
}
How do I properly instantiated that class so that it doesn't end up being null?
Follow this process:
1.) What I have done is map a section of the AppSettings.json file to an object.
A.) Add the configuration settings to json file.
"MyConfiguration": {
"DBServer": "MyDBServer",
"DBName": "MyDatabase"
}
B.) Create a class to use strongly typed configurations.
public class MyConfiguration
{
public string DBServer { get; set;}
public string DBName { get; set;}
}
C.) Map the JSON configurations to the MyConfiguration object in the Startup class.
public class Startup
{
//Make sure you add this.
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
...
var configSection = Configuration.GetSection("MyConfiguration");
services.Configure<MyConfiguration>(configSection);
//Use one of the following.
Services.AddScoped<MyClass>();
Services.AddTransient<MyClass>();
Services.AddSingleton<MyClass>();
Services.AddInstance<MyClass>();
...
}
}
See this link for an explanation of the differences between
`AddSingleton()`
`AddScopped()`
`AddInstance()`
`AddTransient()`
2.) Change MyClass to have MyConfiguration object as a parameter of the MyClass constructor.
//add this using statement and corresponding package
//"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.1"
using Microsoft.Extensions.Options;
public class MyClass
{
private MyConfiguration _configuration;
public MyClass(IOptions<MyConfiguration> configuration)
{
_configuraiton = configuraiton.Value;
}
}
3.) Add MyClass as a parameter of the AnotherClass constructor. Dependency Injection will create the MyClass or reuse it depending on the scope of the object and how you setup that up in the Startup.ConfifureServices() method.
public class AnotherClass
{
private MyClass _myclass;
public AnoherClass(MyClass myclass)
{
_myclass= myclass;
}
public SomeMethod()
{
//Use myClass here and you don't need to instantiate it.
_myclass
....
}
}
You doing a couple of things.
1 - You are re-declaring your class variable myclass as a local variable in your SomeMethod. You should use the myclass variable you already declared as a class variable. To do that, make this line
MyClass myclass = new MyClass(_configuration);
Like this
myclass = new MyClass(_configuration);
2 - You are not instantiating your IConfigurationRoot, so it is null before inject it at all. You should be able to instantiate it however you want (ConfigurationBuilder like #Sach suggested, or _configuration = ConfigurationBuilder.Build() as #Eldho suggested), but you need to instantiate it before you inject it if you dont want it to be null.
Here, it would be best if you use an IOC container like Autofac or Unity or the built-in container in ASP.NET core(if you are using core). You would need to register your IConfigurationRoot interface and its implemented class with the IOC container. After this, inject your MyClass object using the IOC container(in the constructor, or in the method, as per your best scenario). This way, you would never face a problem.

Castle Windsor - passing Type as constructor parameter

I have a class that takes Type as a constructor parameter. How can I register this in the Windsor container?
public Class NLogLogger : ILogger
{
private NLog.Logger _logger;
public NLogLogger(Type type)
{
_logger = NLog.LogManager.GetLogger(type.FullName);
}
...
}
I am trying to register it this way:
container.Register(Component.For(typeof(ILogger))
.ImplementedBy(typeof(NLogLogger))
.LifestyleTransient()
.DependsOn(new Hashtable
{
{"type", ???}
}));
I need to fill in the ???. I could not figure out how I can pass the calling class's Type there.
Update
Going by your update you want to inject the type so that you can use it for logging. There are two solutions.
public class ClassDependentOnLogger
{
private ILogger _logger;
public ClassDependentOnLogger(ILogger logger)
{
_logger = logger;
}
....
}
1 - Use a Windsor SubDependancyResolver. The example below shows how to return and instance of an ILog but you could easily adapt it to return a Type instead if that is what you wanted to do:
public class LoggerResolver : ISubDependencyResolver
{
private readonly IKernel kernel;
public LoggerResolver( IKernel kernel )
{
this.kernel = kernel;
}
public object Resolve( CreationContext context, ISubDependencyResolver contextHandlerResolver, Castle.Core.ComponentModel model, DependencyModel dependency )
{
return NLog.LogManager.GetLogger(model.Implementation.FullName);
}
public bool CanResolve( CreationContext context, ISubDependencyResolver contextHandlerResolver, Castle.Core.ComponentModel model, DependencyModel dependency )
{
return dependency.TargetType == typeof( ILogger );
}
}
//Register the sub dependency resolver. This looks cleaner if you do it via a
//Facility but that's a whole other class
Container.Kernel.Resolver.AddSubResolver( new LoggerResolver( Kernel ) );
2 - Use the Windsor LoggingFacility
There is no need for the NLoggerClass described in your example.

Categories

Resources