Mono.Cecil: Getting Method Reference from delegate passed as Generic Parameter - reflection

I'm trying to get an understanding of which concrete types are providing the implementations of interfaces in an IOC (dependency injection) container. My implementation works fine when there are no delegates involved. However, I'm having trouble when a delegate method is passed as the type factory, as I can't get Mono.Cecil to give me the concrete type or a method reference to the factory back. I'm specifically in this case trying to build a component that can work with the IServiceCollection container for .Net ASP.Net REST APIs. I've created a 'minimised' set of code below to make it easy to explain the problem.
Consider the following C# code:
interface IServiceProvider {}
interface IServiceCollection {}
class ServicesCollection : IServiceCollection {}
interface IMongoDBContext {}
class MongoDBContext : IMongoDBContext
{
public MongoDBContext(string configName) {}
}
static class Extensions
{
public static IServiceCollection AddSingleton<TService>(this IServiceCollection services, Func<IServiceProvider, TService> implementationFactory) where TService : class
{
return null;
}
}
class Foo
{
void Bar()
{
IServiceCollection services = new ServicesCollection();
services.AddSingleton<IMongoDBContext>(s => new MongoDBContext("mongodbConfig"));
}
}
When successfully locating the 'services.AddSingleton' as a MethodReference, I'm unable to see any reference to the MongoDBContext class, or its constructor. When printing all the instructions .ToString() I also cannot seem to see anything in the IL - I do see the numbered parameter as !!0, but that doesn't help if I can't resolve it to a type or to the factory method.
Does anyone have any ideas on how to solve this?

Most likely your code is looking in the wrong place.
C# compiler will try to cache the conversion of lambda expression -> delegate.
if you look in sharplab.io you'll see that the compiler is emitting an inner class '<>c' inside your Foo class and in that class it emits the method '<Bar>b__0_0' that will be passed as the delegate (see opcode ldftn).
I don't think there's an easy, non fragile way to find that method.
That said, one option would be to:
Find the AddSingleton() method call
From there start going back to the previous instructions trying to identify which one is pushing the value consumed in 1 (the safest way to do that would be to consider how each instruction you are visiting changes the stack). In the code I've linked, it would be IL_0021 (a dup) of Bar() method.
From there, do something similar to 2, but now looking for the instruction that pushes the method reference (a ldftn) used by the ctor of Func<T, R>; in the code linked, it would be IL_0016.
Now you can inspect the body (in the code linked, Foo/'<>c'::'<Bar>b__0_0')
Note that this implementation has some holes though; for instance, if you call AddSingleton() with a variable/parameter/field as I've done (services.AddSingleton(_func);) you'll need to chase the initialization of that to find the referenced method.
Interestingly, at some point Cecil project did support flow analysis (https://github.com/mono/cecil-old/tree/master/flowanalysis).
If you have access to the source code, I think it would be easier to use Roslyn to analyze it (instead of analyzing the assembly).

Related

Differences between different methods of Symfony service collection

For those of you that are familiar with the building of the Symfony container, do you know what is the differences (if any) between
Tagged service Collector using a Compiler pass
Tagged service Collector using the supported shortcut
Service Locator especially, one that collects services by tags
Specifically, I am wondering about whether these methods differ on making these collected services available sooner or later in the container build process. Also I am wondering about the ‘laziness’ of any of them.
It can certainly be confusing when trying to understand the differences. Keep in mind that the latter two approaches are fairly new. The documentation has not quite caught up. You might actually consider making a new project and doing some experimenting.
Approach 1 is basically an "old school" style. You have:
class MyCollector {
private $handlers = [];
public function addHandler(MyHandler $hamdler) {
$handlers[] = $handler;
# compiler pass
$myCollectorDefinition->addMethodCall('addHandler', [new Reference($handlerServiceId)]);
So basically the container will instantiate MyCollector then explicitly call addHandler for each handler service. In doing so, the handler services will be instantiated unless you do some proxy stuff. So no lazy creation.
The second approach provides a somewhat similar capability but uses an iterable object instead of a plain php array:
class MyCollection {
public function __construct(iterable $handlers)
# services.yaml
App\MyCollection:
arguments:
- !tagged_iterator my.handler
One nice thing about this approach is that the iterable actually ends up connecting to the container via closures and will only instantiate individual handlers when they are actually accessed. So lazy handler creation. Also, there are some variations on how you can specify the key.
I might point out that typically you auto-tag your individual handlers with:
# services.yaml
services:
_instanceof:
App\MyHandlerInterface:
tags: ['my.handler']
So no compiler pass needed.
The third approach is basically the same as the second except that handler services can be accessed individually by an index. This is useful when you need one out of all the possible services. And of course the service selected is only created when you ask for it.
class MyCollection {
public function __construct(ServiceLocator $locator) {
$this->locator = $locator;
}
public function doSomething($handlerKey) {
/** #var MyHandlerInterface $handler */
$handler = $serviceLocator->get($handlerKey);
# services.yaml
App\MyCollection:
arguments: [!tagged_locator { tag: 'app.handler', index_by: 'key' }]
I should point out that in all these cases, the code does not actually know the class of your handler service. Hence the var comment to keep the IDE happy.
There is another approach which I like in which you make your own ServiceLocator and then specify the type of object being located. No need for a var comment. Something like:
class MyHandlerLocator extends ServiceLocator
{
public function get($id) : MyHandlerInterface
{
return parent::get($id);
}
}
The only way I have been able to get this approach to work is a compiler pass. I won't post the code here as it is somewhat outside the scope of the question. But in exchange for a few lines of pass code you get a nice clean custom locator which can also pick up handlers from other bundles.

Mediatr handlers are they singletons?

I am using the Mediatr in my .Net Core project and I was wondering if the handler's in the Mediatr are singleton's or are the new instances for every Send request; I know the Mediatr is a Singleton' but for the handlers it uses for a command or query, I am not very sure.
I tend to think they would also be singletons; but just wanted to double confirm.
In fact, lifetime of all those things are it's well documented
https://github.com/jbogard/MediatR.Extensions.Microsoft.DependencyInjection/blob/master/README.md
Just for reference: IMediator is transient (not a singleton), IRequestHandler<> concrete implementations is transient and so on so actually it's transient everywhere.
But be aware of using Scoped services with Mediatr handlers, it works not as expected, more like singletons, unless you manually create a scope.
For the handlers, after following the source code, it looks like they are all added as Transient.
https://github.com/jbogard/MediatR.Extensions.Microsoft.DependencyInjection/blob/1519a1048afa585f5c6aef6dbdad7e9459d5a7aa/src/MediatR.Extensions.Microsoft.DependencyInjection/Registration/ServiceRegistrar.cs#L57
services.AddTransient(#interface, type);
For the IMediator itself, it looks like it is lifetime by default :
https://github.com/jbogard/MediatR.Extensions.Microsoft.DependencyInjection/blob/1519a1048afa585f5c6aef6dbdad7e9459d5a7aa/src/MediatR.Extensions.Microsoft.DependencyInjection/Registration/ServiceRegistrar.cs#L223
services.Add(new ServiceDescriptor(typeof(IMediator), serviceConfiguration.MediatorImplementationType, serviceConfiguration.Lifetime));
Note that the service configuration is a configuration object that unless somehow you change it along it's default path, will be set to transient too :
public MediatRServiceConfiguration()
{
MediatorImplementationType = typeof(Mediator);
Lifetime = ServiceLifetime.Transient;
}
Using core you can manually register your handlers and use whatever scope you want. So for example:
services.AddScoped<IPipelineBehavior<MyCommand>, MyHandler>();
We actually wrap Mediatr so we can add various bits and bobs so it ends up being a registration extension like this (CommandContect/QueryContext holds various stuff we use all the time and ExecutionResponse is a standard response so we can have standard post handlers that know what they are getting):
public static IServiceCollection AddCommandHandler<THandler, TCommand>(this IServiceCollection services)
where THandler : class, IPipelineBehavior<CommandContext<TCommand>, ExecutionResponse>
where TCommand : ICommand
{
services.AddScoped<IPipelineBehavior<CommandContext<TCommand>, ExecutionResponse>, THandler>();
return services;
}
Which is used like this:
services.AddCommandHandler<MyHandler, MyCommand>();
We have similar for queries (AddQueryHandler<.....)
Hope that helps

Injecting logger into middleware dependency

I have a middleware library I intend on using in multiple projects. The middleware itself looks something like:
public SdkMiddleware(RequestDelegate next, ILogger<SdkMiddleware> logger, ISdk sdk)
{
this.next = next;
this.logger = logger;
this.sdk = agentSdk;
this.sdk.Init();
...
}
Thanks to DI, I can simply inject my logger:
// Would rather this class be internal...
public class Sdk: ISdk
{
private ILogger<Sdk> logger;
public Sdk(ILogger<Sdk> logger)
{
this.logger = logger;
}
public void Init() {
this.logger.Info(...) // Do some logging
}
The downside to this is my class needs to be registered in every ASP.Net project's Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ISdk, Sdk>();
Is the best/only route? Every time I want to inject a logger into a class, I need to register that class for DI in my composition root?
There is nothing wrong in having the consumer of your library compose the dependencies for this library in the composition root. That's how dependency injection works. You could of course provide some default implementations and a custom extension method that would register those default implementations into the DI and then let the consumer simply call your extension method.
There are a few things that I feel need clarification here:
Dependency injection/inversion of control
To understand what is the benefit of dependency injection(DI) it is better to look at the principle of inversion of control(IoT) that DI implements.
In your case you want SdkMiddleware class to contain a reference to ILogger implementation. The simplest way to do this is for SdkMiddleware class to create an instance of a class that implements ILogger interface. The downside of such approach is that SdkMiddleware needs to know which class implements ILogger interface and how to instantiate it. In other words, SdkMiddleware has control over the creation of ILogger object. The inversion of control happens when the responsibility of knowing which class implements ILogger and how to create an instance of it is taken away from SdkMiddleware to some other class (dependency container in DI) and the instance if it is given to SdkMiddleware to use (through injection in DI). In this case the control over the creation of ILogger object is outside of SdkMiddleware. Since this changes the direction of control, it is called "Inversion of control".
The benefit of this approach is when you will need to provide another implementation of ILogger or change the way you create an instance of that class, you don't need to change SdkMiddleware at all.
Bootstrapping
So now that we clarified why we are using DI, lets take a look at what do we need to actually use it.
The object that creates all instances, controls which object is injected into which and gives away ready to use objects is usually called DI container or IoT container. In asp.net core "IServiceCollection services" is used as such a container. But it still needs to know how to create objects and which implementation to inject for which interface. This is where bootstrapping comes in.
In a bootstrapper class or method you need to specify how objects are built from classes and how classes relate to interfaces. As an example of the former, imagine that you need to pass a connection string for a database from your configuration to a class that creates a db connection. As for the latter, that is exactly what your line "services.AddTransient()" does.
The answer
I am sorry it took so long to get to the actual answer for your question but I wanted to provide some overview first.
Do you need to specify a relation between a class and an interface to inject logger into your class? No. Your class may not even have an interface to begin with and DI container will inject all the dependencies in it by default if you ask for an object of a class instead of an instance of an interface. You can also use or define some convention over configuration solution so that binding of classes and interfaces will happen automatically.
The bottom line is that registration of a class and the actual injection are not connected. But the code you provided is the default way to do this.

Groovy mixin on Spring-MVC controller

I'm trying to use Groovy mixin transformation on a spring-mvc controller class but Spring does not pickup the request mapping from the mixed in class.
class Reporter {
#RequestMapping("report")
public String doReport() {
"report"
}
}
#Mixin(Reporter)
#Controller
#RequestMapping("/a")
class AController {
#RequestMapping("b")
public String doB() {
"b"
}
}
When this code is run .../a/b url is mapped and works but .../a/report is not mapped and returns HTTP 404. In debug mode, I can access doReport method on AController by duck typing.
This type of request mapping inheritance actually works with Java classes when extends is used; so why it does not work with Groovy's mixin? I'm guessing it's either that mixin transformation does not transfer annotations on the method or that spring's component scanner works before the mixin is processed. Either way, is there a groovier way to achieve this functionality (I don't want AController to extend Reporter for other reasons, so that's not an option) ?
You can find below the responses I got from Guillaume Laforge (Groovy project manager) in Groovy users mailing list.
Hi,
I haven't looked at Spring MVC's implementation, but I suspect that
it's using reflection to find the available methods. And "mixin"
adding methods dynamically, it's not something that's visible through
reflection.
We've had problems with #Mixin over the years, and it's implementation
is far from ideal and bug-ridden despite our efforts to fix it. It's
likely we're going to deprecate it soon, and introduce something like
static mixins or traits, which would then add methods "for real" in
the class, which means such methods like doReport() would be seen by a
framework like Spring MVC.
There are a couple initiatives in that area already, like a prototype
branch from Cédric and also something in Grails which does essentially
that (ie. adding "real" methods through an AST transformation).
Although no firm decision has been made there, it's something we'd
like to investigate and provide soon.
Now back to your question, perhaps you could investigate using
#Delegate? You'd add an #Delegate Reporter reporter property in your
controller class. I don't remember if #Delegate carries the
annotation, I haven't double checked, but if it does, that might be a
good solution for you in the short term.
Guillaume
Using the #Delegate transformation did not work on its own, so I needed another suggestion.
One more try... I recalled us speaking about carrying annotations for
delegated methods... and we actually did implement that already. It's
not on by default, so you have to activate it with a parameter for the
#Delegate annotation:
http://groovy.codehaus.org/gapi/groovy/lang/Delegate.html#methodAnnotations
Could you please try with #Delegate(methodAnnotations = true) ?
And the actual solution is:
class Reporter {
#RequestMapping("report")
public String doReport() {
"report"
}
}
#Controller
#RequestMapping("/a")
class AController {
#Delegate(methodAnnotations = true) private Reporter = new Reporter
#RequestMapping("b")
public String doB() {
"b"
}
}
When you map requests with annotations, what happens is that once the container is started, it scans the classpath, looks for annotated classes and methods, and builds the map internally, instead of you manually writing the deployment descriptor.
The scanner reads methods and annotations from the compiled .class files. Maybe Groovy mixins are implemented in such a way that they are resolved at runtime, so the scanner software can't find them in the compiled bytecode.
To solve this problem, you have to find a way to statically mixin code at compile time, so that the annotated method is actually written to the class file.

Unity and constructors

Is it possible to make unity try all defined constructors starting with the one with most arguments down to the least specific one (the default constructor)?
Edit
What I mean:
foreach (var constructor in concrete.GetConstructorsOrderByParameterCount())
{
if(CanFulfilDependencies(constructor))
{
UseConstructor(constructor);
break;
}
}
I don't want Unity to only try the constructor with most parameters. I want it to continue trying until it finds a suitable constructor. If Unity doesn't provide this behavior by default, is it possible to create an extension or something to be able to do this?
Edit 2
I got a class with two constructors:
public class MyConcrete : ISomeInterface
{
public MyConcrete (IDepend1 dep, IDepend2 dep2)
{}
public MyConcrete(IDepend1 dep)
{}
}
The class exists in a library which is used by multiple projects. In this project I want to use second constructor. But Unity stops since it can't fulfill the dependencies by the first constructor. And I do not want to change the class since the first constructor is used by DI in other projects.
Hence the need for Unity to try resolving all constructors.
Unity will choose the constructor with the most parameters unless you explicitly tag a constructor with the [InjectionConstructor] attribute which would then define the constructor for Unity to use.
When you state a suitable constructor; that is somewhat contingent on the environment. If for instance you always want to guarantee that a certain constructor is used when making use of Unity use the attribute mentioned previously, otherwise explicitly call the constructor you want to use.
What would be the point of Unity "trying" all constructors? It's purpose is to provide an instance of a type in a decoupled manner. Why would it iterate through the constructors if any constructor will create an instance of the type?
EDIT:
You could allow the constructor with the most params to be used within the project that does not have a reference to that type within its container by making use of a child container. This will not force the use of the constructor with a single param but it will allow the constructor with 2 params to work across the projects now.
You could also switch to using the single constructor across the board and force the other interface in via another form of DI (Property Injection), not Constructor Injection...therefore the base is applicable across the projects which would make more sense.

Resources