MVC Pattern/MS-Automation Model w/ CSLA

MVC Pattern/MS-Automation Model w/ CSLA

Old forum URL: forums.lhotka.net/forums/t/1738.aspx


SonOfPirate posted on Saturday, November 11, 2006

We are developing an application that will be a blend of the MVC design pattern and MS' Automation model (used in Office apps).  The challenge I have yet to overcome is figuring out to work the business rules that govern when the various "chrome" features are visible, enabled, etc.

For instance, we have a "File" menu with a "New" item that expands to show a "Project" sub-item.  To create the menu, we have the following code in our Application class:

void Application()
{
    _menus = new MenuList(this);
    MenuItem fileMenu = new MenuItem("File");
    _menus.Add(fileMenu);
    MenuItem newMenu = new MenuItem("New");
    fileMenu.Items.Add(newMenu);
    MenuItem projectItem = new MenuItem("Project");
    newMenu.Items.Add(projectItem);
}

This is pretty straightforward.  We would setup our default menus and items here with the collection exposes as the Menus property in the Application object so that other items can be added, removed, etc. by other code.  Where I have hit a roadblock is in implementing the necessary logic to handle the Visible and/or Enabled properties for the individual items.

In the example, the "Project" item's Visible property is based on the current user's security.  So, something like:

projectItem.Visible = Projects.CanAddObject();

At first, it seems like simply adding this statement to the Application object's constructor is a good approach.  But, we are dealing with a web-app, for one, and we have workflow affecting the object's state which may, in turn, change the value of the CanAddObject() call - okay, maybe not this one, but it would affect what the user is allowed to do.  For instance, a user may be allowed to perform a certain task only when the object is in a certain state - such as an Approve menu item which would only be applicable if the user had the required security to grant approvals AND the object was in the ApprovalPending state.  Furthermore, because we are using MVC with the Automation model, our UI components aren't responsible for any of this logic, only rendering based on what they get from the Application.Menus property.

We are looking at storing the Application object in Session so that it doesn't have to be completely reconstructed with each post-back.  However, by doing that, we need some other method to apply the rules that affect the visibility and enabling of each menu item becuase we can't assume that the visibility and/or enabling of the item stays the same since it was first instantiated.

Our logic (item behavior) can be broken down to:

  1. An item's visible property is based on the authorization rules applied to that item.
  2. An item's enabled property is based on the business rules applied to that item.

So, we can embed this logic into our MenuItem object such as:

public Boolean Enabled
{
    get
    {
        return ValidationRules.IsValid;
    }
}

We could do the same with the Visible property by using the AuthorizationRules collection (which in our case is slightly modified from the base CSLA because we use Rights-based security so we would be checking for the individual right, CanAddProjects, rather than a specific role - cuz more than one role could have this right).  Nonetheless, we could have an authorization rule that checks to make sure the current user has the specified right necessary to display the item.

What I see as being the benefit of this approach is that the rules are checked every time the Enabled or Visible property is read.  So when our UI component rebuilds itself and checks these properties, we get a return value that reflects the state of that menu item at that time.  This seems to take care of that problem - even with a web app where we've stored Application in Session - and allows us to stay consistent with MVC and keep the controlling logic out of the UI/View.

But...

Now we get to the question of responsibility.  I cannot see creating - I mean hard-coding - a separate business object for each and every menu item, toolbar button, etc. in the application so that we can follow this approach.  So, does that mean that it continues to be the Application object's responsibility to set all of this up?

void Application()
{
    _menus = new MenuList(this);
    MenuItem fileMenu = new MenuItem("File");
    _menus.Add(fileMenu);
    MenuItem newMenu = new MenuItem("New");
    fileMenu.Items.Add(newMenu);
    MenuItem projectItem = new MenuItem("Project");
    newMenu.Items.Add(projectItem);

    newItem.AddValidationRule(CommonRules.CollectionNotEmptyRule);
    projectItem.AddAuthorizationRule(Rights.CanAddProjects);
}

Obviously this is not consistent with CSLA because the AddValidationRule and AddAuthorizationRule methods are protected scope.

All of that being said, I am looking for a sanity check, alternative approaches, whole new ideas, etc. to accomplish this.  We can't be the first to walk this path, so any insight, guidance, suggestions and/or redirection is greatly appreciated.

Thanks in advance.

 

Bayu replied on Saturday, November 11, 2006

Hey,

Tough challenge .... I like it. ;-)

In CAB (Composite UI App Block) things like toolbars and menus are modeled as so-called UI Extension Sites. Your MainForm (master template ...?) defines and registers them somewhere where they are made available to all your views.

It is then up to your views to make use of these sites when they would like to do so. Programming this in your view is ugly, so usually you manage these kinds of things in the Presenters (aka Controllers in MVC terminology, what's in a name ....) of your views. These Presenters have OnActivated and OnDeactivated events and can hook up in these to add and remove elements from the extension sites as they see fit.

What I mean to indicate by this exampe is this:
- by programming this in your presenter you keep your BOs clean from UI stuff
- using the extension sites you avoid a single holistic 'super' mediator between your BOs and UI
- your presenters then neatly decompose the logic into view-specific logic (hence BO specific logic, since views display BOs .... assuming neatly organized BOs that are normalized by behavior).

This is not a complete answer, I don't have one yet. This is an interesting topic though and I hope more people will engage in the discussion and that together we can build towards a nice solution.

Good weekend!
Bayu

RockfordLhotka replied on Sunday, November 12, 2006

There are a couple issues here.

First, and most importantly, the business logic for validation and authorization rules should be in the model, not the view or presenter/controller. This is why those methods are protected - they should NOT be called by the UI layer, as that would break down the seperation of concerns.

The view/controller/presenter comprise the UI layer. They are responsible for user interaction, and things like "chrome". They should not implement business rules - they should react to them.

Second, for the non-static methods, there are formal interfaces defined by .NET for interacting with the model. These are the data binding interfaces, and CSLA implements all of them for you already. Using these interfaces, you should be able to abstract any interaction with instances of business objects, probably from within your controller/presenter.

Look at Windows Forms, and you'll see that these interfaces provide for a very rich and interactive experience between the UI and business layers, without any tight coupling to specific business types.

That just leaves the four static autho methods. Those have been a thorn in my side since day one. I have considered a couple possible solutions, but haven't arrived at one that makes me happy as yet.

However, for your purposes, the solution (in general terms) is to implement the four static autho methods in a base class and have them somehow delegate to the appropriate type (or a proxy for that type) to answer the four questions (CanAddObject, CanGetObject, CanDeleteObject, CanEditObject).

Putting the static methods in a base class isn't hard. But implementing them in a meaningful way is the challenge. Somehow you need to acquire the answer from either a Dictionary of answers, or from the actual object type.

Since your base class is generic, T is the type of the real object in question, so your UI code would be along this line:

bool canAdd = MyBusinessBase<Person>.CanAddObject();

So the CanAddObject() static method in MyBusinessBase at least knows you want the answer for the Person type. Without instantiating an instance of Person, it may be that reflection is required to call a method on the Person class to get the answer.

Or (I think) you could use the static constructor in Person so Person could add its answers to a static Dictionary contained in MyBusinessBase, and MyBusinessBase could just answer the question out of that Dictionary.

These are ideas anyway - mostly unexplored. So if you find something that works, please let us know, because it would help others as well. Thanks!

SonOfPirate replied on Monday, November 13, 2006

This sentance:

RockfordLhotka:
First, and most importantly, the business logic for validation and authorization rules should be in the model, not the view or presenter/controller. This is why those methods are protected - they should NOT be called by the UI layer, as that would break down the seperation of concerns.

is exactly what has me confused.  Are you saying that our MenuItem objects should be BOs as well?

And, I did not think that our security/authorization process was more complicated than the typical CSLA app, but it isn't necessarily the four basic autho methods that I am having trouble with.  These will be straightforward and the static methods will work fine.  The two areas I am having difficulty with are:

  1. Who is responsible for knowing which method applies to which menu item: the menu item itself, the menu, the Application object, ???
  2. How to deal with per instance logic beyond the basic four autho methods?  In my previous post I mentioned that we will have an Approve menu item.  This button will be visible if the current user has the necessary rights to grant approvals; BUT, will only be enabled if the current object is in the ApprovalPending state.

To accomodate the requirement to have rights beyond the basic four (Add, Get, Delete and Edit), we have a SecurityManager class that handles our authorization responsibilities via its Authorize method.  It accepts the specific right that we are authorizing and handles the rest.  This is slightly different from the core CSLA implementation in that we've externalized the authorization process (at least the part where we check if the current user has the requested right) and check against the users specific rights.  So, for instance, our CanAddObject method in our Project class looks like:

public static System.Boolean CanAddObject()
{
    return SecurityManager.Authorize(Rights.CanAddProjects);
}

Part of the reason that we've used this approach is because our users have the ability to administer their own security.  So they can add/remove/modify users and groups/roles as well as how users are assigned to each.  To hard-code what "roles" are authorized to perform a specific task would negate this feature.  We use individual, task-based rights in lieu of roles so that our objects can remain hard-coded and security is enforceable in a dynamic setting.  This way, when the end-users create a new group/role, they assign the specific rights they want that group/role to have and the application continues working like a charm.

We do continue to use the property-level authorization within our objects as well but the AuthorizationRules object delegates to the same SecurityManager to check for the required rights.

That being said, our overall architecture includes a web control that renders the menus and items based on the structure defined in our object model (for lack of a better way to refer to it) - via the Application.Menus property.  Basically, it iterates over the collection(s) and constructs the UI elements based on the structure and properties found in the object model (a sort of manual data-binding).  Our object model version of a menu item (MenuItem) simply defines the item's name and whether it is visible and/or enabled.  It is up to the UI component, during rendering to implement these properties, then, in the case of our web app, it is up to the Theme, CSS, skin, etc. to handle the actual presentation.  We have successfully implemented this approach using Windows.Forms.Menu, WebControls.Menu and Infragistics.UltraWebMenu interfaces thus far based on our object model.  I believe this is consistent with MVC.  But, we are at a roadblock when it comes to properly implementing this kind of logic into this model.

The issue that has led me to post this topic is back to how we determine the Visible and Enabled properties for each MenuItem (object model, not UI element).  Who's responsibility is it to set these properties or, in other words, who is it that must possess the knowledge of what criteria are used to determine the value for each property?

In the case of the Approve menu item:

Visible = SecurityManager.Authorize(Rights.CanApproveProjects);

Enabled = (currentInstance.State == ProjectState.ApprovalPending);

You can see that the enabled property is based on the current instance and current state of that instance.  So, to further complicate things, we can't just have this statement when the menu item is created unless we plan on recreating it each and every time we need to evaluate these properties.  This is why I thought it would be better to encapsulate these conditions within the MenuItem itself so that the conditions were re-evaluated each time the property was called.

If you are suggesting that our object model MenuItem class should be a business object itself, then wouldn't it be consistent and logical for it to have its own validation and authorization rules?  And, as such, having these conditions within the Visible and Enabled properties would be a good way to accomplish our goals?

But, that brings us back to the question of settings this up.  If we create our MenuItem class as a BO, with AuthorizationRules and ValidationRules collections, then we either need to create a separate class for each and every menu item in our application, such as ApproveProjectMenuItem, so that we can define the rules or we need some way for another object to define them.  At this point, we have more than 50 menu items possible in our application with a design that allows us to extend this as the application is extended.  Isn't there a better way than creating 50 individual menu item classes?

I hope this explanation makes what we are doing and thinking a bit clearer.  Thanks for the feedback and continued assistance.

RockfordLhotka replied on Monday, November 13, 2006

Let's look at it this way. You need to maintain seperation of concerns, and you need to preserve the integrity of both the UI (controller/view) and business (object) layers.

There's no reason in the world that you can't have MenuItem objects - but they'd be part of the UI layer, not the business layer. Nothing wrong with that - the UI layer should be object-oriented too (that's why you are using the MVC pattern - it is all about making the UI become OO).

If you follow me thus far, then you need to ask the MenuItem object what information it needs to do its job. Its job, of course, is to turn on/off the menu glyph/text/whatever it represents. And the information it needs to know is probably the type of business object its menu option uses, and what action the menu option represents.

One of the most interesting comments in David West's 'Object Thinking' book is where he talks about the MVC pattern and points out that "controller" is a terrible word. It implies that the controller is in control, which can not be in a real OO model. Objects don't control other objects. He suggests using the word coordinator, to better convey that the "C" is merely there to coordinate interactions between the View and Model.

So I suggest that there's nothing wrong with the MenuItem (part of the View) object interacting with the Model when the Controller/Coordinator suggests that such an interaction is needed.

This is fundamentally the same as the View using data binding to interact with the Model at the appropriate time.

You just need to create your MenuItem such that it interacts with the Model in as abstract a way as possible, so you can minimzie the amount of code required to implement those MenuItem objects.

SonOfPirate replied on Monday, November 13, 2006

So, if I'm understanding you correctly, you are saying that we should be putting the logic necessary to set the Visible and Enabled properties based on the object's authorization and validation rules in the menu item because it is the MenuItem's responsibility to determine these values?  I agree with that but have struggled with the best way to do it.  As you said, we want to do this in the most abstract way as possible to not only minimize the amount of code but to allow for reuse of the code with other applications.

Would this be a good candidate for the use of the new System.Predicate<T> delegate?  I first looked into this a while ago but have yet to implement it anywhere.  My understanding would be that we could define an external method to use to determine these properties from another class, such as our MainForm or Application class when the MenuItem is instantiated.  For instance,

_menuItem = new MenuItem("Approve", new System.Predicate<Project>(CanApproveObject));

where CanApproveObject is a static method in our Project class that accepts an instance of Project and returns a boolean value based on the authorization rules defined for the object.  This would allow us to implement business rules, such as checking the current state of the object, and keep all of that within the Project class itself.

Is this a correct and appropriate way to use a Predicate?  And do you agree that this is a good approach to use for our situation?

Of course, in order for this to work, our menu item would have to have a reference to the current Project instance to evaluate.

Still not quite there.........

 

RockfordLhotka replied on Monday, November 13, 2006

I don't know if that's a good use of Predicate or not - hard to say.

What I'm getting at is seperation of concerns. Or to put it another way, objects should operate on a "need to know" basis. The fewer objects that know facts, the easier it is to maintain your application.


The controller's job is merely to wire up the view to the model. I'd suggest that you need a ShellManager, or MenuManager, so the controller can tell this manager what object is currently active, thus allowing the manager to tell its children (the MenuItem objects). If a MenuItem actually cares about the given object type, then it can ask the object (or type) questions, like CanApproveObject.

The Application or controller object shouldn't know about these things. It would end up knowing too much. It should just connect concerned parties to each other, and let them work out the details.

SonOfPirate replied on Monday, November 13, 2006

I'm with you now.  Just have to think about how to implement.  And, I'd still like to find a way to accomplish it without having to create a separate class to represent each menu item, such as ApproveContractMenuItem.

Hafta give it some more thought, but you've definitely helped me with the concepts.

Any other thoughts on how to implement are appreciated.

 

RockfordLhotka replied on Monday, November 13, 2006

This was the intent of my first reply - your menu item objects should (where possible) use interfaces to do their work, thus keeping a high level of abstraction. The trick comes back to those darn static/Shared autho methods, which can't be interface-based. But if you use the Dictionary (or some other) technique to get those methods into a base class, then your menu item object could be coded, in the general case at least, to interact with interfaces and base class methods.
 
Then you'd only need to create custom code if a menu item needed to act on some non-standard method (perhaps like CanApproveObject).
 
Rocky


From: SonOfPirate [mailto:cslanet@lhotka.net]
Sent: Monday, November 13, 2006 10:39 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] MVC Pattern/MS-Automation Model w/ CSLA

I'm with you now.  Just have to think about how to implement.  And, I'd still like to find a way to accomplish it without having to create a separate class to represent each menu item, such as ApproveContractMenuItem.

Hafta give it some more thought, but you've definitely helped me with the concepts.

Any other thoughts on how to implement are appreciated.

 




SonOfPirate replied on Monday, November 13, 2006

It has occurred to me that the answer may have been staring me in the face the whole time!  The Document!

What I mean is, the menu items that I am having a problem resolving are using per instance rules and the difficulty has been trying to figure out how to get the menu item to "know" these rules when, as you said, they shouldn't.  But nothing else was apparent until it occurred to me that the "instance" in which we are referring is actually in the object model as the "document".  And, fact is, the document is what added the menu item to the default menus in the first place!  (At least that's how it works with MVC and context menus, right?)

So, all of my default menu items, those created by the main form or Application object are "global" in nature and only use per type rules such as CanAddObject().  These are easily captured and managed by the form or Application classes.  If we leave the responsibility of adding and managing context related items to the document to which they are related, the menu item doesn't need to know anything about the object or the rules.  Instead, the child form (or whatever) can apply the rules to determine if the item is to be added and, if so, whether it is enabled or not.

I will have a Project class which inherits from Document (and/or implements IDocument) that is rendered using the Project web control (or page) and manages the creation and handling of the Approve menu item whenever the current user has the necessary rights.  And, it will mark the menu item as enabled when the Project BO that is the data source for the document is in the Approval Pending state.

This has just occurred to me and I have some more thinking to do to work through it, but I think this may solve the problem and actually be even more in line with MVC, etc.  In fact, this may allow me to have the MenuItem be the single class I was looking for.  The document controls its creation and adds the hook for the event handler when it is clicked so that it can be handled correctly.

Make sense?

 

HappyJack replied on Thursday, February 14, 2008

SonOfPirate,

This thread is very interesting.  I was wondering if you use any databinding in your winforms for this MVC style?  My question is that originally when I tried something very similiar, It seemed that my UI classes had to implement a lot of interfaces for databinding that the internal CSLA object had implemented all ready.  There's really nothing wrong with this it was just took a lot of code to hook together.  I'm just wondering how you wired your UI objects to the CSLA business objects.

 

Thanks,

HappyJack 

skaue replied on Thursday, February 14, 2008

RockfordLhotka:

One of the most interesting comments in David West's 'Object Thinking' book is where he talks about the MVC pattern and points out that "controller" is a terrible word. It implies that the controller is in control, which can not be in a real OO model. Objects don't control other objects. He suggests using the word coordinator, to better convey that the "C" is merely there to coordinate interactions between the View and Model.


I read an article over at CodeProject that used the term Model-View-Presenter. I found that to be a good definition. But it seems people would rather think of MVP as Microsoft Most Valuable Professional :-P

Copyright (c) Marimer LLC