1

Assuming that we have the following code (which a rather extensive specification of the access conditions) I wanted to refactor it. There's a bunch of such policies very similar to each other, with only a tiny variation in a special claim.

services.AddAuthorization(options =>
{
  options.AddPolicy("ExtensivePolicy_A",
    config => config.RequireClaim("special_claim", "dedicated_value_to_A")
     .RequireClaim("claim1", "value1") ...
  );
  ... 
  options.AddPolicy("ExtensivePolicy_Z",
    config => config.RequireClaim("special_claim", "dedicated_value_to_Z")
     .RequireClaim("claim1", "value1") ...
  );
}

The attempt based on e.g. this, gave me this.

services.AddAuthorization(options =>
{
  options.AddPolicy("ExtensivePolicy_A", ConfigPolicyA);
  ...
  options.AddPolicy("ExtensivePolicy_Z", ConfigPolicyZ);
}

private static void ConfigPolicyA(AuthorizationPolicyBuilder builder) { ... }
...
private static void ConfigPolicyZ(AuthorizationPolicyBuilder builder) { ... }

It's much cleaner but still screams parameterization, as the only difference in the config delegates (actions, funcs whatever they call it), is a tiny detail. Optimally, I'd like my privates to look something along the lines of the following.

private static void ConfigPolicy(AuthorizationPolicyBuilder builder, string special) { ... }

And the call to it would pass a parameter.

options.AddPolicy("MarketingPolicy", ConfigPolicy("a"));

However, I can't get it to work. The compiler complains about the action type being wrong. The original intellisense tells me that I'm supposed to pass something of type Action<AuthorizationPolicyBuilder>, which is kind of against my method's signature (being void). However, it seems to compile whereas the version that returns said type gets the compiler whining about error converting method group to AuthorizationPolicy (which is misleading because that type is a signature of another overloaded method).

My best attempt based on this blog (actions with lambda expression) went as far as this.

private static Action<AuthorizationPolicyBuilder, string> test1
  = builder => { ... };

However, trying to introduce the extra string parameter fails miserably.

private static Action<AuthorizationPolicyBuilder, string> test2 
  = (builder, special) => { ... };

What should I google for to get relevant examples, which I'm sure there are a gazillion of out there? I've found examples on generics and methods as paameters but nothing that tipped me over to aha-side.

Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
  • `options.AddPolicy("MarketingPolicy", config => ConfigPolicy(config, "a"));`? – GSerg Jul 31 '21 at 11:08
  • Does this answer your question? [C# define function with partial application as delegate](https://stackoverflow.com/questions/40146859/c-sharp-define-function-with-partial-application-as-delegate) – GSerg Jul 31 '21 at 11:15
  • @GSerg That might be one way to go. However, I'd like to replace the **entire** content of the second parameter (i.e. `config=>blaha-blaha`) and assign it **some**thing that I declare below. **And** I want that something to be parameterized, so that I can pass a string to blaha-blaha but receive the final thingy. – Konrad Viltersten Jul 31 '21 at 11:15
  • @GSerg My last comment was to your first suggestion (not bad, to be honest). As for the second one, it resembles quite a lot the sample I show using definition of `Action`. That fails in my case due to the extra string passed in (see the edit I just made). A single parameter to the action works as expected, though. – Konrad Viltersten Jul 31 '21 at 11:18
  • @GSerg Are you claiming that I can't exchange `(config)=>blah for (config, "fix_value_here")=>blah` in C#? I'm comparing to (the principle of) calling a method `Hazaa(5)` while the signature is `void Hazaa(int,string param="")`. I was wishing to replace the passed in builder to config and restructure it to be `config,"my_fix_value"` and **then** pass it on to my – Konrad Viltersten Jul 31 '21 at 11:28

1 Answers1

2
private static Action<AuthorizationPolicyBuilder> ConfigBuilderFactory(string param)
{
  return builder => builder
    .RequireClaim("special_claim", param)
    .RequireClaim("claim1", "value1")
    ...;
}
options.AddPolicy("ExtensivePolicy_A", ConfigBuilderFactory("a"));
options.AddPolicy("ExtensivePolicy_Z", ConfigBuilderFactory("z"));
Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
GSerg
  • 76,472
  • 17
  • 159
  • 346
  • Yes, this is perfect. I'll take the liberty to change the name of the policy to more generic form that follows the formulation in the original question. I suspect that you picked it up from my comments where I posted the actual production code by quickstake. – Konrad Viltersten Jul 31 '21 at 11:45