Mandy
Mandy

Reputation: 31

elegant solving of a problem with design patterns C#

i have a problem.

i need to find a way to dynamically instantiate classes and dynamically activate methods in these classes according to some user permissions and also grouping that the user can ask for.

for example:

1. user permission "A"

invoke classes 1,4,6

invoke methods 2,7 in class 1.

invoke methods 1,2 in class 4.

invoke methods 1,2 in class 6.

2. user permission "B"

invoke classes 2,3,5

invoke method 2,7 in class 2.

invoke method 1,2 in class 3.

invoke method 1,2 in class 5.

i made these examples only with different permissions. but it can also contain grouping, which means that different classes and different methods (some kind of subset) could be invoked for each permission.

i can do everything with switch/case but i'm looking for a more elegant way to do it.

Notes:

  1. there are a lot of possibilities because of many classes-methods because of many different types of grouping that the user can ask for.

  2. i don'k know exactly what is the best way to pass permissions.

  3. i was thinking that maybe the command pattern or decorator could help here.

Thank you very much for your answers!

Upvotes: 3

Views: 253

Answers (4)

bencobb
bencobb

Reputation: 618

You could tie strings to class and method calls through using Func<>. It gives you a lot of flexibility in handling the many permutations you are dealing with. I have an example of code below, but you could use Enums instead of strings for the key.

This isn't necessarily a pattern, but it could be utilized with several of the patterns mentioned already.

public void Call(Stream str)
    {
        //Single Permission
        Generate["PermissionA"](str);

        //Say this user has multiple permissions, you can iterate over them
        IEnumerable<string> userPerms = GetUserPerms();
        foreach (var perm in userPerms)
        {
            Generate[perm](str);
        }
    }

    public static Dictionary<string, Func<Stream, object>> Generate
    {
        get
        {
            var ret = new Dictionary<string, Func<Stream, object>>();

            ret.Add("PermissionA",  (s) => 
                                        {
                                            Class1 cl1 = new Class1(s);
                                            Class4 cl4 = new Class4(s);
                                            Class6 cl6 = new Class6(s);

                                            cl1.Method2();
                                            cl1.Method7();
                                            cl4.Method1();
                                            cl4.Method2();
                                            cl6.Method1();
                                            cl6.Method2();

                                            cl1.DoXml();
                                            cl4.DoXml();
                                            cl6.DoXml();

                                            return "";
                                        });

            ret.Add("PermissionB", (s) => 
                                        {
                                            Class2 cl2 = new Class2(s);
                                            Class3 cl3 = new Class3(s);
                                            Class5 cl5 = new Class5(s);

                                            cl2.Method2();
                                            cl2.Method7();
                                            cl3.Method1();
                                            cl3.Method2();
                                            cl5.Method1();
                                            cl5.Method2();

                                            cl2.DoXml();
                                            cl3.DoXml();
                                            cl5.DoXml();

                                            return "";
                                        });

            return ret;
        }
    }

Upvotes: 0

Prisoner ZERO
Prisoner ZERO

Reputation: 14166

You might also look into the Factory Pattern.

Upvotes: 0

Kaleb Pederson
Kaleb Pederson

Reputation: 46479

Assuming you have access to the classes, one way would be to use proxy classes and attributes:

class PermissionVerifier {
    public void ExecuteIfHasPermission(Permission perm, Action action) {
        if (GetCurrentUser().HasPermission(perm)) // assumes singleton-like
                                                  // access or injected user
            action();
        throw CreatePermissionException(perm);
    }
}

class A {
    // make it obvious what permissions are required for execution
    [RequiresPermission(Permissions.CanExecuteClassAMethod1)]
    public virtual void Method1() {
        //...
    }

}    

class AProxy: A {
    private PermissionVerifier verifier;

    public override void Method1() {
        ExecuteIfHasPermission(
            GetCurrentMethodRequiresPermissionAttribute(), // reflection
            () => base.Method1());
    }
    private ExecuteIfHasPermission(Permission perm, Action action) {
        verifier.ExecuteIfHasPermission(perm, action);
    }
}

If instead of manually creating the proxies you used a dynamic proxy generator that intercepted all the methods, you could have the permissions check performed explicitly without the need to manually write a lot of boilerplate code.

Upvotes: 3

Tejs
Tejs

Reputation: 41236

It sounds like you are looking for something similar to CodeAccessPermissionAttribute - see here for details. I'd perhaps recommend a pattern similar to this; define objects with attributes to associate their permission states, and then your users would fall into roles that have or dont have permission to execute methods with specific attributes.

Upvotes: 0

Related Questions