Catharsis 1.0 part III - Access right management, Navigation
This article is the third step in a Catharsis
documented tutorial. Catharsis is web-application framework gathering
best-practices, using ASP.NET MVC 1.0, NHibernate 2.0.1. All
needed source code you can find on
http://www.codeplex.com/Catharsis/

Catharsis 1.0
Let me proudly announce the first alpha release of Catharsis 1.0
This web-app Framework now covers all layers, provides basic recipes and uses the full power of the ASP.NET 1.0
! There is also move to NHibernate 2.1
alpha, using its Castle
proxies (The LinFu
was making troubles in this alpha release, maybe in next it will replace Castle
). You can now create Entities
, CodeList
values and light version of ICodeList
. There is also smart “lazy-column-trick
” for list display, which can be found in the search.PropertyList
(Do you have large entity with columns containing files and large texts?, for list-view fill only the search.PropertyList
and the SQL Select
clause will use only these properties – very powerful and performance increasing). Messages
now also provides direct logging using Log4Net
and are more break-proctective (even if the incorrect format strings are provided, e.g. “Message 0}
” instead of “Message {0}
”, this is the must, because localized versions come from users)
But first of all, this is the real Catharsis 1.0
, covering all layers, all pieces (rights, menus, smart ajax…) and finally based on ASP.NET MVC 1.0
. The almost year effort now brings you the sweet fruit.
Enjoy Catharsis 1.0
Access right management, Navigation
Catharsis 1.0 (and higher?). This article was entirely rewritten to fully describe abilities of the version 1.0. And with small adjustments and extension it should be stable for all future generations.
Access right management
Access-rights do not belong to the MVC layers. In fact, rights are separated layer itself, dependent on different application needs (web part, batch importer etc.).
“Separation of concern for access-rights” is crucial for future application maintenance and extension. But as experience speaks, this is a bit (in fact very) difficult to understand for developers coming from any pre-AOP world. Their need to enjoy hard-coding on every Page_Onload
is hard to change...
Application in a Crystal view – 3D Matrix.
Imagine your application as an adjustable and flexible 3D matrix. It could be disassembled and described as nodes and links. These nodes are entities (Person
, Subject
, CodeList
) and links are all the CRUD operations (search & list, add, updated, delete). Entities and their CRUD operations are maintained similarly and therefore could be seen as a node and links if the 3D matrix (only as an example).
Catharsis will help you in this way. Every entity will have these operations - by default. Whenever you append new entity using the Guidance, you are provided with implemented ‘100% functional’ CRUD on all layers. Your next steps are ‘only’ to apply business checks (can be deleted? Are key properties provided? Is the new item unique? Extend searching, etc.)
Why the 3D matrix: because this crystal view has no dependency on rights and roles. In fact every operation is possible for any entity (if the business rules are met)
Filter the Crystal view
Users interact with application in the Actor roles. Administrator, Translator, Viewer – each needs different entities (nodes) and operations (links) to be accessible.
The 3D matrix example will resume in the semi filled matrix, where due to applied Actor-role-filter are some nodes and links removed (in fact hidden). The Filter is the right word. It could be adjusted, changed or not applied at all. But anyhow it is the separate layer, the AOP filter. Application still has all these nodes and links; they are not removed – when the filter is applied.
This approach will at the end allow Customer to decide who (Actor role) has the rights for which part (entity) and can use which action (e.g. only search & list for Viewer). And what’s more, this could (and will) be applied even during the application production deployment.
The benefit is awesome.
You can develop your application as there are no roles (create the full 3D matrix).
Than (when everything is done) append restrictions using the separate layer (access rights management) to meet your Customer needs.
And that’s Catharsis, that’s separation of concern in the essential form.
(I’ve tried to create some easy to read pictures with 3D Matrix, but I failed. Anyway, I do believe that this comparison was not confusing and that you’re still on the track. )
AOP
AOP
(aspect oriented programming) – is one of the ASP.NET MVC
built-in fundamental features. The C-layer (controller) allows you to decorate any controller’s action with attributes. They should implement some of the filter interface (e.g. IAuthorizationFilter
) to be called properly by ASP.NET MVC
framework.
Whenever an action is called every AOP
filter comes into play and its before or/and after operations are called properly. Every means that ASP.NET MVC
calls all filters which decorate: the action itself, its controller, and even the bases (base controllers or action ancestor if overridden).
Separation of concern
The Catharsis framework offers easy to use solution. It is based on a few elements for access rights management. If you’ll think about similar approach on another existing project, you can reuse only these small parts (classes):
The filter RoleAccessAttribute
(AOP)
The XML
reader called NavigationMenuProvider
(the name comes from its secondary use, see below)
The access-rights-definition file Menu.config
.
That’s all. Append it to your application and decorate all your base controllers with [RoleAccess]
attribute.

Adjust the Menu.config
settings and you’re done. Let’s see how it works in a more detail.
Menu.config
There is one XML
configuration file called Menu.config
. This is in fact the central and only point for your access right management. (You can distribute it as a plain xml
or an embedded resource with some adjustments, but nevertheless – roles are separated and other layers independent)
='1.0'='utf-8'
<menu xmlns='http://ProjectBase/Config.xsd' >
<controllerOrNode name='CodeLists' >
<roleGranted name='Administrator' />
<roleGranted name='RegisteredUser' />
<roleGranted name='Viewer' isReadOnly='true' />
<controllerOrNode name='Country' parent='CodeLists' >
<roleGranted name='Administrator' />
<roleGranted name='RegisteredUser' />
<roleGranted name='Viewer' isReadOnly='true' />
</controllerOrNode>
...
</controllerOrNode>
</menu>
No alchemy, you’ll see
controllerOrNode & roleGranted elements
Root element “menu” can contain child elements “controllerOrNode
”.
Node is only a hierarchical element and has no impact on right management. It only allows nest group of controllers to one parent node e.g. CodeLists
parent for Country
, Currency
, ContentType
…
Controller
on the other hand is the gateway to MVC
layer.
In the above snippet you can see that Country
controller is accessible for roles RegisteredUser and Viewer. This is done via “roleGranted
” elements, connected to application roles using attribute name=”RoleName”
. Any not mention role is denied.
There is also interesting switch isReadOnly with some crucial impacts.
IMasterModel.IsReadOnly
is set to true (and you can use this information on other places – independently on access rights)[Transaction]
attribute, which Commits the “NHibernate data changes” to the database, will always RollBack the transaction if the IMasterModel.IsReadOnly
. - Every controller’s action decorated with
[Transaction]
attribute is prohibited - Every Action or Button stored in the
IMasterModel.ActionsModel
& IMasterModel.ButtonsModel
and decorated with [Transaction]
attribute is removed (why to show them, if they are prohibited anyway).
One small step for controller, but the giant impact for application.
Granular settings with action attribute
For some purposes could be handy if you can set only some actions for specific controller to be granted. Or prohibited. Therefore every element “roleGranted
” can contain the list of “action
” elements with the self explaining “name
” attribute.
<roleGranted name='Anonym' accessForListed='grant'>
<action name='List'/>
</roleGranted>
As you can see role Anonym in this example has granted access to the action List. Any other action of this controller is forbidden.
You can also turn the list behavior by setting the accessForListed="deny"
. It will grant access to all actions of that controller except the listed.
WriteActionList.config
There is a complementary list for Menu.config
, the WriteActionList.config
file.
='1.0'='utf-8'
<menu xmlns='http://ProjectBase/Config.xsd' >
<writeActionList>
<action name='New'/>
<action name='Edit'/>
...
</writeActionList>
</menu>
Catharsis creates its own WriteActionList
by reflection of the C-layer (controllers.dll
). Every action which is decorated with [Transaction] attribute is handled as Write action.
But there are some actions that only act as a pre-steps for these write actions. For example the “New
” action which gathers the form information and than calls the “Add
” action. “New
” action does not use transaction because does not store any changes. The check would be applied only on the next step “Add
”.
But why should we show and provide the “New
” action to someone (e.g. Viewer) who does not have the access to “Add
”. To avoid these situations, there is the WriteActionList.config
. Put any other action you do not want to allow or show when the IsReadOnly
switch is turn on.
AppRoleProvider
As we’ve already seen above, the access rights setting for every role is trivial. In the Catharsis framework you are only adjusting Menu.config
file.
And where do the roles which are evaluated come from?
RoleAccess
filter attribute asks the roleProvider
encapsulated in the ApplicationRoleProvider
object. This static instance is creates ASP.NET runtime using standard roleProviders setting in the web.config
section:
<roleManager enabled='true' defaultProvider='AppRoleProvider'>
<providers>
<clear />
<add name='AppRoleProvider' applicationName='Firm.Product.Web'
type='Firm.Product.Common.Providers.AppRoleProvider, Firm.Product.Common' />
<add name='CommonProvider' applicationName='Firm.Product.Web'
type='Firm.Product.Common.Providers.CommonProvider, Firm.Product.Common' />
</providers>
</roleManager>
There are already two role providers existing in Catharsis: AppRoleProvider
and CommonProvider
.
AppRoleProvider
AppRoleProvider is inherited from WindowsTokenRoleProvider
provider and uses Catharsis entities AppRole
and AppUser
. Any user is authenticated as domain\user
and then AppRoleProvider
reads its identification from application database (object AppUser
and its set of AppRoles
).
AppRoleProvider
allows you to manage the users in the application using its interface (all standard CRUD operations). This is very handy for intranet scenarios and applications which needs user’s entities for other entity handling (e.g. Subjects
are managed by unique AppUser
)
CurrentRole
The Catharsis framework introduces another role based feature – CurrentRole
.
AppRoleProvider
is derived from RoleProvider
(due its base WindowsTokenRoleProvider
) and that’s why it can be used as an ASP.NET provider. Such a RoleProviders
in common is able to answer question “IsUserInRole
()
”, which leads to mishmash for users with many roles. These users (with many roles) are provided with almost every application features, regardless if they need them in current scenario or not.

To explicitly show the disadvantage, let’s use the Actor approach view. Actors are accessing our application in different scenarios with different needs. E.g. ‘FormDesigner’ creates forms to be filled by ‘Evaluator’ and viewed by ‘Assessed’. But some person can play more then one role (e.g. personnel department manager) and we simply have to distinguish it.
Our application cannot confuse user’s by providing all actions and entities using “IsUserInRole()
” or “GetRolesForUser()
”
Solution provided by Catharsis is simple and efficient. One of the roles provided by “GetRolesForUser()
” is simply converted into the CurrentRole
. The UI then fits needs of selected role – Actor role. Nothing else is displayed then the Actor’s selected filter needs.
If user needs to change CurrentRole
, and to play as another Actor - there is the CurrentRole
switch. It’s displayed on the master page in the left bottom corner or as an action of the HomeController
. CurrentRole
is than persisted in the database and reused in the next session.
IAppRoleProvider
To allow this behavior and management there is en extension to ASP.NET abstract RoleProvider
interface (interface provided by abstract
class
, shame it is not an interface!)
The IAppRoleProvider
interface:
interface IAppRoleProvider
{
AppUser User { get; }
IList<AppRole> GetRolesForCurrentUser();
AppUser ChangeCurrentRole(AppRole role);
AppUser ChangeCurrentRole(string roleName);
string ApplicationName { get; set; }
void CreateRole(string roleName);
bool DeleteRole(string roleName, bool throwOnPopulatedRole);
string[] FindUsersInRole(string roleName, string loginToMatch);
void AddUsersToRoles(string[] logins, string[] roleNames);
string[] GetAllRoles();
string[] GetRolesForUser(string userName);
string[] GetUsersInRole(string roleName);
bool IsUserInRole(string userName, string roleName);
bool IsUserInRole(string roleName);
void RemoveUsersFromRoles(string[] usernames, string[] roleNames);
bool RoleExists(string roleName);
}
All this functionality is exposed by static AppRoleProvider
instance accessible via ApplicationRoles
(similar to ASP.NET Roles
).
- RoleAccess filter asks
ApplicationRoles.CurrentRole
- RoleAccess filter next reads the
Menu.config
to know the rights for this role - RoleAccess filter grants access or denies it – the action is canceled and user is provided with this sad information.
CommonProvider
The web.config
roleProvider
setting contains also the CommonProvider
. Its purpose is to bridge your own independent RoleProvider to IAppRoleProvider. In fact it will be very very handy in scenarios you are using some common e.g. AcitveDirectoryRoleProvider
.
How to do it? Append your RoleProvider
definition into the web.config providers section and mark it as defaultProvider. And don’t remove CommonProvider
.
From this moment your ActiveDirectoryRoleProvider
will provide GetRolesForUser()
etc. CommonProvider will extende with the CurrentRole stuff and cooperate with the ApplicationRoles
. User’s will be authenticated with your provider, will be able to select one of their roles as the CurrentRole
and then act with application using authorization based on Menu.config role settings.
If your external provider returns strange strings instead of “nice” roleNames e.g. GF_BR_ADMIN1
instead of Administrator you can extend the Str.Roles
constructor and adjust appSetings
to create new mapping. Application gains another plus – separation of the external Role provider naming “quasi-standards” …
<appSettings>
<add key='DefaultListRowCount' value='25'/>
...
<add key='Administrator' value='GF_BR_ADMIN1 ' />
...
</appSettings>
And adjust the constants in Common
project
public partial class Str : Constants
{
public partial class Roles
{
protected Roles() { }
public const string Administrator = "Administrator";
public const string Translator = "Translator";
public const string Viewer = "Viewer";
public const string RegisteredUser = "RegisteredUser";
public const string Anonym = "Anonym";
public static readonly IList<string> RoleList;
static Roles()
{
RoleList = new List<string>()
{
{ Administrator },
{ RegisteredUser },
{ Viewer },
{ Translator },
{ Anonym },
};
}
}
}
RoleProvider summary
Catharsis allows and may be forces you to use the separated access rights management. What ever could be done on one separate place, it must be done separately. You can than reuse it and adjust it without no impacts to other parts of your application. That’s the pure AOP
.
Navigation
There is a built-in webControl
in Catharsis TreeView
. This webControl
is 100% MVC
and should be described more detailed. Maybe next time…

This control is used on a master page and serves as the main navigation gate for the user. From its hierarchical nature it contains nodes with theirs nested content – controller’s links. Click and users are navigated to asked controller. There are Action
’s links and Buttons
, which allows other interaction (of course based on access-rights).
How to fill this Navigation TreeView
webControl
? Are there needed information for this TreeView
already stored somewhere or do we have to create new source. Foolish we would be, if we won’t use the Menu.config
once again…
Menu.config – smart source for navigation
Customer needs were, as described above, fairly transferred into the Menu.config
access rights setting. This is the best and very smart source for our navigation control. We can easily reuse the known role-based-conditions and there for build up the navigation links menu.
The already mentioned NavigationMenuProvider
will do this job. It will read the nodes and controllers and correctly supply the TreeView.
To have the TreeView
well looking we can extend Menu.config
settings with some other attributes. These have no impact on CurrentRole
access rights management, but manage the TreeView look.
Config.xsd
To help you with filling these elements and attributes there is an XML Schema
for you: Config.xsd
. It has no validation impact (at least it’s not used for that), it only supports the InteliSense which is always nice to have. (I’m missing this for Log4Net, if you have any…)
Smart attributes for Menu.config
Snippets below reveal the full strength of this file setting.
<controllerOrNode name='Home' expanded='true' >
<roleGranted name='Administrator' isVisible='false' />
...
</controllerOrNode>
Attribute isVisible="false"
helps you to hide some controllers from the navigation menu (without any impact on RoleAccess!!!)
<controllerOrNode name='CodeLists' href=''
imagePath='/Content/img/currency.gif' expanded='true' >
Above example shows another attribute “href
”. It can be filled with the specific Url
, or by leaving it unused, the ActionLink
based on controller
“name
” will be created for you. The provided empty value in the example is a trick how to disable the link at all (nodes does not have targets). The second attribute imagePath
provides the relative path to the image which can decorate your node
<controllerOrNode name='Currency' imagePath='.' parent='CodeLists' >
<roleGranted name='RegisteredUser' />
<roleGranted name='Viewer' isReadOnly='true' />
</controllerOrNode>
Parent attribute is essential for the correct parent-child relations. The imagePath
is set to special sign “dot” imagePath="."
this provides smart abbreviation for the engine to create the path using controllerOrNode
“name
” attribute => “/Content/img/menu/ + name + .gif”
<controllerOrNode name='Country' text='State' parent='CodeLists' >
<roleGranted name='RegisteredUser' />
<roleGranted name='Viewer' isReadOnly='true' isVisible='false' />
</controllerOrNode>
In the last snippet the different text will be rendered then the controllerOrNode
name attribute.
Play with, and if not sufficient, adjust it.
TreeView
overall look can be also adjusted in the NavigationWC.ascx
control using TreeViewSettings
:
<pbwc:TreeView ID='NaviTV' runat='server' ControllerActionUrl='/Home.mvc/NaviTV'
ViewDataKey='MasterModel.NaviTVModel' >
<TreeViewSettings
DoLocalize='true'
ShowExpandCollapse='true'
ImgExpandPath='/Content/img/menu/expand.gif'
ImgCollapsePath='/Content/img/menu/collapse.gif'
ShowAnchors='true'
ShowImages='true'
ImageNodeClosedPath='/Content/img/menu/closed.gif'
ImageNodeOpenedPath='/Content/img/menu/opened.gif'
ImageLeafPath='/Content/img/menu/leaf.gif'
/>
</pbwc:TreeView >
For example, the switch DoLocalize
(if set to true
) will call the ResourceProvider
to get localized names from global resources. That's new feature of Catahrsis 0.9.8 - Localizer's are directly connected to ASP.NET ResourceProviders, but it's another story.
Summary
The Catharsis framework, as we’ve seen above, provides very powerful solution for your application for the access rights management. Once correctly set - immediately reused for navigation menu. It is easy to adjust, possible to extend. And easy to learn, use and maintain! You never know how the Customer needs will look like tomorrow…
Enjoy Catharsis
Appendix
I cannot finish this chapter without saying thanks. Thank to MS for the Linq
. Especially the Linq to XML
- it is the tool which changed development for me in surprising way. Old school hard-coding with Xml readers, writers, serializers etc. could be fun. But the Linq to XML
is the real Catharsis. Great. Thanks.
Source code
Catharsis source code: http://www.codeplex.com/Catharsis/
History