Reputation: 1925
I used this accepted answer to create an Enum of Guids.
public enum AccessRoles
{
[EnumGuid("2ED3164-BB48-499B-86C4-A2B1114BF1")]
SysAdmin =1,
[EnumGuid("A5690E7-1111-4AFB-B44D-1DF3AD66D435")]
Admin = 2,
[EnumGuid("30558C7-66D9-4189-9BD9-2B87D11190")]
OrgAdmin = 3,
}
class EnumGuid : Attribute
{
public Guid Guid;
public EnumGuid(string guid)
{
Guid = new Guid(guid);
}
}
I try check if a Guid is part of an enum, it throws an exception System.InvalidOperationException even though userId = 2ED3164-BB48-499B-86C4-A2B1114BF1 is a valid guid.
if(Enum.IsDefined(typeof(AccessRoles), userId))
{
}
I tried converting it to string and checking, but that time it does not throw an error but does not go inside the if loop.
if(Enum.IsDefined(typeof(AccessRoles), userId.ToString().ToUpper()))
{
}
So how do I fix it? Or is there a better way? I want to avoid the multiple if statements or a case statement and so what to use it as enums so they are reusable.
Upvotes: 5
Views: 16340
Reputation: 169
Maybe passing the Guid values with System.ComponentModel.AmbientValueAttribute
like so :
using System.ComponentModel;
public enum AccessRoles
{
[AmbientValue(typeof(Guid), "749e73c0-ba25-4f69-9f81-ec21d9942e52")]
SysAdmin = 1,
[AmbientValue(typeof(Guid), "39cc7e3d-db5f-4619-a577-e24cb89de5a7")]
Admin = 2,
[AmbientValue(typeof(Guid), "93902f8d-46d3-4b43-b684-b0ee66bbf7de")]
OrgAdmin = 3,
}
With an extension to obtain the AmbientValue:
using System.Reflection;
public static class EnumExtensions
{
public static object GetAmbientValue(this Enum enumVal)
{
Type type = enumVal.GetType();
MemberInfo[] memInfo = type.GetMember(enumVal.ToString());
object[] attributes = memInfo[0].GetCustomAttributes(typeof(AmbientValueAttribute), false);
if (attributes == null || attributes.Length == 0)
return default;
return ((AmbientValueAttribute)attributes[0]).Value;
}
}
And finally obtaining the Guid value like so :
var valGuid = (Guid)AccessRoles.SysAdmin.GetAmbientValue();
Upvotes: 1
Reputation: 37
public enum AccessRoles
{
SysAdmin = 1,
Admin = 2,
OrgAdmin = 3
}
public class Attributes
{
public static Dictionary<int, Guid> Attribute = new Dictionary<int, Guid>()
{
{(int)AccessRoles.SysAdmin, Guid.Parse("6D18698C-04EC-4E50-84DB-BE513D5875AC")},
{(int)AccessRoles.Admin, Guid.Parse("32E86718-7034-4640-9076-A60B9B6CA51A")},
{(int)AccessRoles.OrgAdmin, Guid.Parse("2CA39E37-8AEA-463F-AE14-E9D92AC5FB5E")}
};
}
Console.WriteLine(Attributes.Attribute[(int)AccessRoles.SysAdmin]);
Console.WriteLine(Attributes.Attribute[(int)AccessRoles.Admin]);
Console.WriteLine(Attributes.Attribute[(int)AccessRoles.OrgAdmin]);
Upvotes: 2
Reputation: 82524
I would replace your enum with an immutable struct, and add a static class to hold all possible roles in the application:
public struct AccessRole
{
public AccessRole(Guid guid, int number, string name) : this()
{
Uuid = guid;
Number = number;
Name = name;
}
public Guid Uuid {get;}
public int Number {get;}
public string Name {get;}
}
Then you can add a static class for AccessRoles:
public static class AccessRoles
{
private static List<AccessRole> _roles;
static AccessRoles()
{
_roles = new List<AccessRole>();
// Here I populate it hard coded for the sample,
// but it should be populated from your database or config file
_roles.Add(new AccessRole(new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1"), 1, "SysAdmin"));
_roles.Add(new AccessRole(new Guid("A5690E7-1111-4AFB-B44D-1DF3AD66D435"), 2, "Admin"));
_roles.Add(new AccessRole(new Guid("30558C7-66D9-4189-9BD9-2B87D11190"), 3, "OrgAdmin"));
}
public static AccessRole GetRole(Guid uuid)
{
return _roles.Find(r => r.Uuid == uuid);
}
public static AccessRole GetRole(int number)
{
return _roles.Find(r => r.Number == number);
}
public static AccessRole GetRole(string name)
{
return _roles.Find(r => r.Name == name);
}
}
Now all you have to do is change the way the _roles
list is populated in the static constructor to either a database of a configuration file, and you're good to go.
Note that the AccessRoles provides static methods to get a search for a role by either property. It can be replaced with a single method that will get a predicate, but I think that this way it's more readable.
Upvotes: 6
Reputation: 1566
I would suggest a complete different approach, when working with fixed user roles.
Using an Enumeration you can achieve same and much more:
public abstract class UserRoleType : Enumeration<UserRoleType>
{
protected UserRoleType(int value, string displayName)
: base(value, displayName)
{}
public static readonly UserRoleType Unknown = new UnknownRoleType();
public static readonly UserRoleType Administrator = new AdministratorRoleType();
public static readonly UserRoleType System = new SystemRoleType();
public static readonly UserRoleType Moderator = new ModeratorRoleType();
public virtual bool CanCreateUser => false;
public virtual bool CanBlockUser => false;
public virtual bool CanResetUserPassword => false;
}
public sealed class UnknownRoleType : UserRoleType
{
public UnknownRoleType()
: base(0, "Unknown")
{ }
}
public sealed class AdministratorRoleType : UserRoleType
{
public AdministratorRoleType()
: base(10, "Administrator")
{}
public override bool CanCreateUser => true;
public override bool CanBlockUser => true;
public override bool CanResetUserPassword => true;
}
public sealed class SystemRoleType : UserRoleType
{
public SystemRoleType()
: base(20, "System")
{ }
public override bool CanBlockUser => true;
public override bool CanResetUserPassword => true;
}
public sealed class ModeratorRoleType : UserRoleType
{
public ModeratorRoleType()
: base(40, "Moderator")
{ }
public override bool CanBlockUser => true;
}
By setting abstract/virtual properties on the abstract UserRoleType, you system only have operate on the abstract class.
When your user context is being initialized (on login), you simply find the user role by
var roleTypeValueFromDatabase = 10;
var roleType = UserRoleType.FromValueOrDefault(roleTypeValueFromDatabase, UserRoleType.Unknown);
if (roleType.CanCreateUser)
{
// create user..
}
// Find roles with specific rights
var rolesThatCanResetPassword = UserRoleType.GetAll().Where(urt => urt.CanResetUserPassword);
About the Enumeration class, there are several implementation of them on github/nuget.
Mine is for .Net core v2 - https://github.com/microknights/Collections with Nuget: Install-Package MicroKnights.Collections
Headspring - https://github.com/HeadspringLabs/Enumeration source files only.
Upvotes: 2