5

I'm building an ASP.NET MVC 5 app, and following the example in this SO post to apply [Flags] to an enum:

[Flags]
public enum Role
{
    User = 1,
    Finance = 2,
    Management = 4,
    SystemAdmin = 8
}

Note that, the [Flags] attribute gives us a nice way to get multiple values as one, comma-separated string:

var roles = (Constants.Role.SystemAdmin | Constants.Role.Management).ToString();
// "SystemAdmin, Management"

The enum values will be used in the [Authorize] attribute on controllers and actions, such as this:

[Authorize(Roles = (Constants.Role.SystemAdmin | Constants.Role.Management).ToString())] 
public class SomeController : Controller
{ ... }

However, the above attribute generates this error:

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

Why can I use the .ToString() method and get a CSV of the enums in code but not when using the same statement in the [Authorize] attribute?

Alex
  • 34,699
  • 13
  • 75
  • 158
  • 2
    Because, as the error says *"An attribute argument must be a constant expression"*. That means you can't call a method (like `ToString()`) in an attribute because it's not guaranteed to be constant. – Matt Burland Jun 20 '17 at 14:39
  • Thanks, @MattBurland. Any ideas on how to get that working? Or is it simply not possible when used on an attribute like that? – Alex Jun 20 '17 at 14:41
  • It's not possible to use an attribute like that. What you could do is create an attribute that has a `RolesEnum` property that is of type `Role` that in it's setter will set the `Roles` string property to `value.ToString()`. That might work. – Matt Burland Jun 20 '17 at 14:43
  • Thanks again, @MattBurland. Mind throwing that into an answer and get some credit for it? – Alex Jun 20 '17 at 14:44

1 Answers1

8

Because attributes are metadata, they have the restriction that their initialization must be constant. As your error says:

An attribute argument must be a constant expression

ToString() is a method call and so can't be guaranteed to be constant. That's why you can use it.

To work around this, you might be able to subclass Authorize and do something like this:

public class MyAuthorizeAttribute : AuthorizeAttribute
{
     private Role roleEnum;
     public Role RoleEnum
     {
         get { return roleEnum; }
         set { roleEnum = value; base.Roles = value.ToString(); }
     }
}

And that you could use like this:

[MyAuthorize(RoleEnum = Constants.Role.SystemAdmin | Constants.Role.Management)] 

^ no need for ToString()

Matt Burland
  • 44,552
  • 18
  • 99
  • 171
  • I got an error in my controller class `error CS0246: The type or namespace name 'MyAuthorizeAttribute' could not be found` – Aska Apr 03 '21 at 11:23