1

I'm trying to encapsulate permissions logic for a particular view model in a way that the permission logic has access to the view model object, but is also exposed inside of it

Trivial Implementation:

public class ClientViewModel
{
    public Client Client { get; set; }

    /* permissions section */
    public bool CanVote => Client.Age > 18
    public bool CanDrink => Client.Age > 21
}

The implementation is pretty clean and simple. The view will need to make lots of decisions based on the set of properties available within the permissions. But there are going to be a lot of permissions so ideally I'd like to contain that logic somewhere else.

Right now I can access like this:

var vm= new ClientViewModel() { Client = myClient };
vm.CanVote

But I'd like to contain all the logic inside a single class and access like this:

vm.Permissions.CanVote

Circular Implementation

So I can put a property of type ClientViewModelPermissions on the ViewModel itself. It needs to have access to data objects on the ViewModel it's describing so I can pass in the instance of the model into the Permissions constructor and new it up during the construction of the model itself, like this:

public class ClientViewModel
{
    public ClientViewModel()
    {
        // create instance of permissions for current object
        Permissions = new ClientViewModelPermissions(this);
    }

    public Client Client { get; set; }

    public ClientViewModelPermissions Permissions { get; set; }
}

public class ClientViewModelPermissions
{
    public ClientViewModelPermissions(ClientViewModel clientVm)
    {
        // permissions must describe a particular view model
        ClientModel = clientVm;
    }

    private ClientViewModel ClientModel { get; set; }

    public bool CanVote => ClientModel.Client.Age > 18
    public bool CanDrink => ClientModel.Client.Age > 21
}

So each class contains a reference to the other as a property. Should this be avoided for any reason? Is there a cleaner way to evaluate properties for a given class, but keep that logic separate than actual class itself by decorating it somehow?

Here's an image with the above code showing the flow of dependencies across classes.

1

Answering your specific code example, I don't see a need for the circular dependency. ClientViewModelPermissions is dependent on Client in order to get the age, so why expose the whole ClientViewModel to it? Just restrict it to Client and you remove the circular dependency.

The circular dependency you describe though doesn't look like a problem though as ClientViewModel creates its own ClientViewModelPermissions and injects itself into it. So that circular dependency is only created at runtime. However, it's often worth pausing and questioning whether it need exist or whether less information is needed by one or other class to remove the dependency.

Problems arise when that circular dependency occurs at construction time (or even at compilation time) with both needing to know about each other at construction. This isn't the case here though.

One final thought: be careful of comparisons and hard-coding values. Your tests are only giving voting rights permissions to those 19 and over and drinking rights to those 22 and over. Here in the UK, the legal drinking age is five at home, 16 in a restaurant and 18 for buying it. In Scotland the voting age is 16. It's 18 elsewhere in the UK. Hard coding figures can make it hard to adapt code to changing laws and international variations.

  • Yeah, i simplified a lot of the permission implementation just to highlight the interdependency between viewmodel and permission classes. In reality, the permissions themselves are different (per hard coding drinking ages, which I definitely agree on). – KyleMit Jan 16 at 21:34
1

Your ViewModel shouldn't contain "business rules" to determine if someone can vote or drink. I'd model it something like this:

public class Client
{
    private readonly Permissions permissions;

    public Client(string name, int age, string country)
    {
        Name = name;
        Age = age;
        Country = country;
        permissions = new Permissions(country);
    }

    public string Name { get; }
    public int Age { get; }
    public string Country { get; }
    public bool CanDrink => Age >= permissions.MinimumDrinkingAge;
    public bool CanVote => Age >= permissions.MinimumVotingAge;
}

public class Permissions
{
    public Permissions(string country)
    {
        switch (country)
        {
            case "YourCountry":
                MinimumVotingAge = 19;
                MinimumDrinkingAge = 16;
                break;

            default:
                MinimumVotingAge = 18;
                MinimumDrinkingAge = 18;
                break;
        }
    }

    public int MinimumVotingAge { get; }

    public int MinimumDrinkingAge { get; }
}

With a structure like this, in your ViewModel you can simply call client.CanVote.

  • I agree when you say "no buisness rules in the viewmodel", so +1 for that. On the other hand, at my current work I model permissions and all kinds of logistical rules. In that perspective, I am more inclined to make the permissions more dissociated from the client. Of course, this adds complexity, but in the context of heavy buisness logic management, I prefer using factories to make my objects and extract the buisness logic in some buisness related objects, that would know themself how to check if X can drink or not. You could then have some LegalPermissions, MedicalPermissions ... – Pierre-Antoine Guillaume Jan 16 at 16:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.