Reputation: 2113
In Dot Net Core convention for configuring services is as follows.
Method that Requires Action<> As Parameter
public static IServiceCollection AddAsResourceServer(this IServiceCollection services, Action<AuthMiddlewareOptions> action = null)
{
if(action != null)
{
AuthMiddlewareOptions authOptions = new AuthMiddlewareOptions();
action.Invoke(authOptions);
}
...
return services
}
This allows us to configure our service in startup as follows.
Startup ConfigureServices Method
services.AddAsResourceServer((a) =>
{
a.Audience = "Long Audience";
a.Issuer = "provider.com/oauthprovider";
});
This is really cool! I like this pattern. It works very well for allowing anyone to overwrite base configuration options.
However this seems very cumbersome when you already have an instance of the object. How would I create an instance of an object, convert it to an action, and pass that to the .AddAsResourceServer
method?
I have tried:
Action<AuthMiddleWareOptions> auth = new Action<AuthMiddleWareOptions>()
/// The above way still requires a "target" in constructor so it doesnt work.
///so i still need to pass each
///property into it.
My consumers of the service may have just created an instance of AuthMiddleWareOptions and populated through appsettings!
They may have done something like this.
AuthMiddlewareOptions myoptions = new AuthMddlewareOptions();
Configuration.Bind("AuthMiddlewareOptions", myoptions);
Now that they have 'myoptions'. Is there a quick way to use that with the Action Parameter. Maybe like this?
AuthMiddlewareOptions myoptions = new AuthMddlewareOptions();
Configuration.Bind("AuthMiddlewareOptions", myoptions);
services.AddAsResourceServer((a) => SpecialThing(myoptions));
Upvotes: 1
Views: 1270
Reputation: 4553
You can simply bind your configuration to the options instance provided by the method.
services.AddAsResourceServer(options =>
{
Configuration.Bind("AuthMiddlewareOptions", options);
});
Upvotes: 3
Reputation: 2970
You may register multiple configuration delegates for a single option class:
services.Configure<AuthMiddlewareOptions>(Configuration.GetSection("AuthMiddlewareOptions"));
services.AddAsResourceServer(options => SpecialThing(options));
And AddAsResourceServer should call services.Configure
, as well:
public static IServiceCollection AddAsResourceServer(this IServiceCollection services, Action<AuthMiddlewareOptions> action = null)
{
if (action != null)
services.Configure(action);
// ...
return services;
}
Having this setup, AuthMiddlewareOptions is populated from the configuration section "AuthMiddlewareOptions", then the customization delegate (SpecialThing) has a chance to change the options filled at the previous step.
It's important that the order matters! If you swap the two lines, SpecialThing's changes will be overwritten by the values coming from the configuration.
Upvotes: 1
Reputation: 17034
You need to do it the other way arround.
I use for example the AddAuthorization
since I do not find your method:
services.AddAuthorization(c =>
{
c.DefaultPolicy = null;
});
This can be configured using the following method:
public static void Config(AuthorizationOptions configure, IConfiguration configuration)
{
configure.DefaultPolicy = null;
//Configuration.Bind("AuthMiddlewareOptions", myoptions);
}
That way you can do:
services.AddAuthorization(c => Config(c, Configuration));
The problem is, that in these Action<T>
methods you get the object T
, which is already instantiated. So you need to copy the custom created object to it. With above we change the API, so it is configured on the correct object.
Upvotes: 0
Reputation: 642
Quick answer to your question "Passing an Instance of an Object to a Method that takes an Action<> as Parameter" is "no, you can't"
But as a workaround, you could simply make a deepclone of your object, to swap the properties of the "inner" options.
Something like this :
static class Copy
{
public static void ObjectToAnother<T>(T source, T target)
{
foreach (var sourceProp in source.GetType().GetProperties())
{
var targetProp = target.GetType().GetProperty(sourceProp.Name);
targetProp.SetValue(target, sourceProp.GetValue(source, null), null);
}
}
}
And you could use that like this :
var obj = new Obj();
Foo.Bar((a) =>
{
Copy.ObjectToAnother(a, obj);
});
It should work
Upvotes: -1
Reputation: 2113
I tried many patterns, it wasn't until I hovered over a
in the method to realize that it wasnt of type Action<AuthMiddlewareOptions>
, but it was in fact AuthMiddleWareOptions
. so this very simple assignment worked!
services.AddAsResourceServer(a => a = myoptions);
Upvotes: -1