Marcelo Castagna
Marcelo Castagna

Reputation: 31

Invoking Generic extension with dynamically generetad lambda

Currently I have a few of these calls

app.CreatePerOwinContext<BasicUserManager>(BasicUserManager.Create);
app.CreatePerOwinContext<ADUserManager>(ADUserManager.Create);
...

Those "Create" methods are static members of each class. So basically it's registering a handler that's going to get called as soon as I request a BasicUserManager object from the owinContext.

And I want to replace it with something like this:

var types = AppDomain.CurrentDomain.GetAssemblies()
                     .SelectMany(s => s.GetTypes())
                     .Where(p => typeof(AbstractUserManager).IsAssignableFrom(p) && !p.IsAbstract);

foreach (var type in types)
{
    app.RegisterUserManagers(type);
}

No problem so far. RegisterUserManagers is an extension which is defined as follows:

public static void RegisterSRTUserManager(this IAppBuilder app, Type type)
{            
    var createPerOwinContextMethod = typeof(AppBuilderExtensions).GetMethods().Where(p => p.Name == "CreatePerOwinContext" && p.GetParameters().Count() == 2).FirstOrDefault().MakeGenericMethod(type);

    var createMethod = type.GetMethod("Create", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);

    var optionsType = typeof(IdentityFactoryOptions<>).MakeGenericType(type);

    var delegateType = typeof(Func<,,>).MakeGenericType(optionsType, typeof(IOwinContext), type);                                  

    var body = Expression.Call(createMethod, Expression.Parameter(optionsType, "options"), Expression.Parameter(typeof(IOwinContext), "context"));            

    var func = Expression.Lambda(delegateType, body, Expression.Parameter(optionsType, "options"), Expression.Parameter(typeof(IOwinContext), "context")).Compile();

    createPerOwinContextMethod.Invoke(null, new object[] {app, func });
}

After compiling the lambda expression, I get an exception:

Additional information: variable 'options' of type 'Microsoft.AspNet.Identity.Owin.IdentityFactoryOptions`1[SeguridadAuth.Login.BD>.AdminOrgUserManager]' referenced from scope '', but it is not defined.

I understand that params should be passed by reference here but I'm not able to figure how to do it in this scenario.

Any help is really appreciated.

Upvotes: 2

Views: 42

Answers (1)

Marcelo Castagna
Marcelo Castagna

Reputation: 31

Got it just after posting the question. Just needed to pass the same parameter reference to both methods.

var optionsPar = Expression.Parameter(optionsType, "options");
var contextPar = Expression.Parameter(typeof(IOwinContext), "context");

var body = Expression.Call(createMethod, optionsPar, contextPar );

var func = Expression.Lambda(delegateType, body, optionsPar, contextPar).Compile();

Upvotes: 1

Related Questions