Enter into Catharsis - adding new Entity
This article is next step in Catharsis
documented tutorial. Catharsis is web-application framework gathering
best-practices, using ASP.NET MVC 1.0, NHibernate 2.1. All
needed source code you can find on
http://www.codeplex.com/Catharsis/

Model layer
This story is based on the version 1.0 and in comparison with previous (some almost half a year old) it would be correct even in the future versions. The framework has grown a lot and at this moment covers all features and layers in the real best-practice manner. This circumstance was essential for this article about Model
layer.
What is the Model layer
Model
layer – ours current topic – is the part of the complex MVC
design pattern. In fact, all these lines could be true even without ASP.NET MVC
infrastructure, because it is about the Model-View-Controller design pattern. I have experience with three MVC
implementations and at least this allows me to say: “lucky .NET developers how can finally implement MVC
design pattern on ASP.NET MVC
framework!”.
The Catharsis place in this world is simple. Put all available best-practice solutions into one compact, reliable framework. If you spend some time using Catharsis, adjust it her, understand her, you would come up with only one result: why to implement it another way? Everything you need Catharsis has. And what is more: She’s not only open-source – she’s distributed as open source code which can be CHANGED for any special project needs.
Model place in the MVC frame
MVC
ver. MVP
. I guess that many readers and users of MVC will recruit from the MVP practice based on ASP.NET web-forms. It leads to an assumption: If I do know MVP than only P (presenter) is the difference, so I would learn only C (controller). Wrong? We will see.
MVC circle or subsequence
MVC
is more the subsequence then a circle. Yes, user interacts with MVC
and all these items are called over and over again. But if any rounded comparison should be used then better is a spiral. I simply would like to say: Let’s try to describe the MVC
as the directed process with the named beginning and the end.
Well than, first of all, we should name who is playing the supplier’s role and who the consumer’s role. Why? It will not only help us to find out were the beginning and where the end is. It also clarify how (and for whom) to design the Model
. The answer is simple: View consumes all the information, previously supplied by controller. Therefore the View needs will decide how to design the IModel
interface. And of course, next it will force the controller to fill it.
As we will see in the next chapter, the View
, in fact, sees nothing but IModel
interface. Really, take a look on references. No Models
project, no Controllers
project. Only the interfaces exposed in Common
library.
MVC
ver. MVP
. The consequences are so significant that the MVP coders should firstly stair and shake theirs heads. The standalone View is 100% dependent on the IModel
interface - only. In fact, the get {}
accessors only, because the next step (final stage) is the rendered page. Setting anything into the IModel
is senseless.
The similar, upside-down, approach is on the controller side. There is the known interface IModel
which should be supplied (using set{}
) with values and than passed to the View
. Wait a second. Why View
? Why not IView
!
The answer is simple again. There is NO relationship between the Controller
and View
. View
(as we’ve already seen) is an orphan, cooperating with the get {}
accessors from its known IModel
. Controller
is the simple-minded (do not tell him!) workhorse, reading the Forms & QueryStrings coming from response, calling IFacades
and filling the IModel
.
- There is none handsome “presenter” patiently filling the
IView
. - There are no
IView
set {}
accessors available. - There is independent, self-sufficient, smart
View
, reading the IModel
information, which is next rendered and provided to the user’s browser.
MVC
ver. MVP
? Is anybody still in a position that they differ only in the P ver. C?
Catharsis IModels battery
Catharsis has built in IModel
battery, which is displayed on the snap.
These interfaces create the link, the glue of the whole framework. The contract they grant is the core element of the simplicity for the project development, your day-to-day real coding.
Now in the more detail:
When you run the Guidance first time and create the solution, you can than run the DB SQL scripts, click F5 and see the Home
screen (View).
Even If you run the Guidance recipe to generate the new entity structure, create the related table in the DB, extend the “Menu.config
” with new entity access rights, append Str.Controllers.Entity
const, click F5 – you can access the new entity Search
, Detail
and List
views.
That all is working because of the IModel
interfaces battery. The base classes (e.g. EntityController
, MasterBase
…) simply knows the contract granted by ProjectBase.Core.Web.Models
interfaces. They are filled (by controllers
) and read & rendered (by views
) and therefore provide the “allover same application stuff”.
Every page (better is the View
) needs (and gets) the contracted IModels
to create the TreeView
menu, BreadCrumb control, Buttons, Page title, Action links and so on.
I believe that the naming of these IModels
and the comments appended to theirs property declarations are all self-describing. Some of them (e.g. ITreeViewModel
) are so interesting that I wish to dedicate them separate article (we will see).
But in general their meaning is really simple. The information set needed on user-friendly View is demanded via the IModel
interface contract. The workhorse (controller
) must contact all the IFacades
and Providers
to supply the contracted information.
Well, it could take some time to get in the Catharsis implemented code (which is mainly nested in the ProjectBase
). But trust me: There are no tricks! Calls are simple as described above: Controller
is calling IFacade
, which asks IDao
to get data. Returned values are supplied to the IModel
. ASP.NET MVC
framework than calls the View
to be rendered with passed IModel
. Howgh.
Catharsis IModel usage example
The best suitable for an example is the IActionsModel
. This interface grants only one property (except the base ICoreModel
implementation see below):
[ConcreteType("ProjectBase.Mvc.Web.Models.Master.ActionsModel, ProjectBase.Mvc")]
public interface IActionsModel : ICoreModel
{
IList<IActionItem> Actions { get; set; }
}
The IActionItem
declaration:
public interface IActionItem
{
string ActionName { get; set; }
string ControllerName { get; set; }
int? ActionValue { get; set; }
string Text { get; set; }
string TextLocalized { get; set; }
string Href { get; set; }
string Target { get; set; }
string OnClick { get; set; }
}
So, for every Action
you want to be available in the rendered View
(as a hyperlink) append an IActionItem
to the Model.MasterModel.ActionsModel.Actions
collection. Some are appended by default by the Catharsis framework. For example the default View
for every controller
- “List
” - calls the OnBeforeList()
method which among others calls extension method to append some basic actions:
protected virtual void OnBeforeEdit(int id)
{
...
this.AddAction(Constants.Actions.Common.New, Url)
.AddAction(Constants.Actions.Common.Search, Url)
.AddAction(Constants.Actions.Common.List, Url
, Constants.Actions.Targets.Self);
...
}
Even if the IActionItem
is really rich (8 properties declared), the developer’s built-in laziness leads to simple call: .AddAction(ActionName, UrlHelper)
. It will supply the Action
interface with all needed values, but on a very rough level.
Of course, you can extend them. Them means, virtual OnBeforeList()
or controller
dependent override OnBeforeList()
, or the extension method AddAction(). That is upon you. The goal: supply the IActionsModel
with information must be fulfilled anyway. The consumer awaits it.
The consumer in this example of that IActionsModel
interface is the Master
piece - WebControl named ActionsWC.ascx
. This one is so simple that we can take a closer look on its whole implementation:
<%@ Control Language="C#" AutoEventWireup="true"
CodeBehind="ActionsWC.ascx.cs"
Inherits="Firm.Product.Web.Controls.Master.Blocks.ActionsWC" %>
<div>
<%
if ( ActionsModel.Is()
&& ActionsModel.Actions.Count > 0 )
{
foreach (var action in ActionsModel.Actions)
{
string href = action.Href ??
Url.Action(action.ActionName, action.ControllerName
, new { id = action.ActionValue });
string text = action.TextLocalized ??
GetLocalized(action.Text);
string onclick = string.IsNullOrEmpty(action.OnClick)
? string.Empty
: " onclick=\"" + action.OnClick + "\""; %>
<p><a href="<%= href %>" title="<%= text %>"
<%= onclick %> ><%= text %></a></p>
<% }
} %>
</div>
ActionsWC is a smart control in the manner of the IActionsModel. It checks if there are any actions to be rendered. Than for every item in the collection tries to consume its declared properties and provide them to the user. Nice and easy. And simple.
The simplicity is the gift coming form the strict separation of concern. There are no mixed operations in the Model-View-Controller instances.
- Model declares
get {}
and set {}
accessors and does not provide any operation! - Controller does its best to supply all these hungry
set {}
properties - View (the band front man) shows the friendly face to user by consuming the
IModel
information.
MVC
ver MVP
. MVC approach is maintainable and reliable by its nature. The responsibility is so pure and separated, that the bug-hunting is usually the question of seconds (Ou, I see, I forgot to fill “that IModel
property” in that “Controller
” and even to append the fundamental .Is()
check on the “View
” consumer). You’ll like it.
Catharsis ICoreModel
Ancestor of every IModel
in the Catharsis framework is the ICoreModel
interface (ProjectBase.Core.Mvc.ICoreModel
). Its declaration contains
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ProjectBase.Core.Mvc
{
public interface ICoreModel
{
IList<ApplicationMessage> Messages { get; set; }
}
}
Spartan, but the fundamental pillar. There are two main impacts of the ICoreModel
interface:
1) Every model in the Catharsis framework is created via Factories e.g. ModelFactory.CreateModel<IActionsModel>()
. For security reasons (to disable returning let’s say IActionsFacade
) there is a check on the provided generic ‘T
’ template (in our case IActionsModel
).
public static T CreateModel<T>()
where T : ICoreModel
2) ICoreModel
, as the granted Ancestor, provides the Messages
collection. This is so crucial element of the Catharsis framework that it needs separate article (in the future). For now just briefly:
Is there any trouble you have to solve? Business error, incorrect date-time format coming from UI in the Forms collection, unauthorized access … Put the Message
in the Messages
collection. Messages
can have three types of severity: Information
, Warning
and Error
(including Exception
).
When the framework founds any message in the collection – renders the localize content to the user (red background for Error
, orange for Warning
and green for Information
).
What’s more, if the controller’s action was decorated with the [Transaction]
attribute and Messages
collection contains at least one Message
with severity Error
– transaction is rolled back. Simple, effective, easy to learn and use. And reliable.
More detailed this concept will be described in the special article (in the future). Last note goes two the IFacade.Messages
ver. IModel.Messages
. They must be the same instance. Therefore if you are creating any IFacade
using factory, you are forced to provide Messages
collection – provide the Model.Messages
. This is MUST.
Catharsis IMyEntityModel
Catharsis guidance is helpful in times, when you are extending your application with the new entities (Person
, Debtor
, Contract
, License
…). To recapitulate the impact of these generators on the Models layer (project) let’s mention two events:
1) The Common
project is extended with a new interface IMyEntityModel
. This is the right place for extending the contract demanded by View and supplied by Controller.
2) The Models
project is extended with a new class called MyEntityModel.cs
implementing the IMyEntityModel
. Example shows the simple LanguageModel
.
public class LanguageModel : BaseEntityModel<Language>, ILanguageModel
{
public LanguageModel()
: base()
{
ExportModel.ShowExportAction = true;
}
public new LanguageSearch SearchParam
{
get { return base.SearchParam as LanguageSearch; }
set { base.SearchParam = value; }
}
}
First look reveals that two obvious settings are there: 1) Enabling the MS Excel export Action
on the “List
” View
, 2) casting base.SearchParam property to more specialized (and declared) LanguageSearch
. Others can be also uncovered: 3) the “base()
” call which for you fills all the nested models with ready to use instances (e.g. ItemModel
). 4) On a different place (controller’s AOP filter
) there is provided the crucial Messages
“store & restore in session management”. For now count on it (or observe it), it will be explained elsewhere.
If your entity will need any information, which is not presented in the base implementation, simply extend IMyEntityModel
. Then use Controller
to supply data and let View to consume them. And of curse extend the MyEntityModel
with implementation of the newly declared properties.
IModels instances on Views and Controllers
Where to find the model instances and how to access them in the Catharsis framework?
Controller
Every controller
in the application is derived from the ICoreController
, which declares the property ICoreModel Model {get; set; }
.
If you are using the Guidance to create the infrastructure for new entities, than you are by default provided with the casting mechanism. Every MyEntityController
declares the new Model
property which exposes the IMyEntityModel
properties and hides the base. Therefore you can access all the properties declared on IMyEntityModel
via the controller’s property Model
. Easy and practical, because the base classes can still interact with their known interfaces (e.g. IEntityModel
), which are the same instance of course.
The real added value is hidden in the base Controllers
implementation. The base classes like WebController
and EntityController
know its IModels
and can do lot of common stuff for you. It means fill the ButtonsModel
, ItemModel
, TreeViewModel
, ActionsModel
etc. (but you can still change it by overriding OnBeforeActions()
etc.)
View
The View must provide the type of the IModel needed for correct behavior in the generic declaration of its CodeBehind:
public partial class ActionsWC : ViewWebControlBase<IWebModel> { }
Current Implementation of the ASP.NET MVC RC1
provides this strongly typed instance in the property named Model
. (It’s expectable, but not presented in previous versions. The Catharsis framework had this feature always). That’s very handy, because you can again access the IMyEntityModel
properties via calling the strongly typed property Model
on any View
(page or control).
Some Models
are nested e.g. the ActionsModel
can be navigated by Model.MasterModel.ActionsModel
. Therefore there are two special base classes for your CodeBehind
implementation:
ViewWebControlBase
(non entity Views
)
ViewEntityControlBase
(derived from ViewWebControlBase
)
They provide some properties and methods for easier handling of the IModels
instances. Because they are again strongly typed
public class ViewWebControlBase<TModel> : ViewUserControl<TModel>
where TModel : class, IWebModel
they can access and exposed and known interface in a smart way like:
public IActionsModel ActionsModel { get { return Model.MasterModel.ActionsModel; } }
The guidance automatically uses these ControlBase
classes for generated code. If you append new Control
manually (which could be quite usual) do not forget to append them. They can help you a lot (the more we will see on the View
layer chapter).
And it does not have to be an end. You can, for example, create for some group of entities special middle-base-class with more precious interface like IMyColoredHavingEntityModel
and so on. There are now boundaries for generalization (inheritance) and you as a best-practice applying developer should use it.
Models summary
MVC
ver. MVP
. The Models
in these abbreviations are only the homophone. They sound same, but they are totally different.
Catharsis provides the solution which leads you, as a developer, to the best-practice coding concepts. Layers – even the parts of the whole MVC
layer – are separated (proven above). They do depend on contracts provided via IModels
. The Views
concern than on their “show-performance” for user, consuming the stored information from the IModels
. Controller
’s, these lovely simply-minded workhorses, link ants carefully round around to get all needed cargo and store it in the IModels
. As in reality, division of labor is effective, but the cream is only for few – visible Views
.
Enjoy Catharsis
Radim Köhler
Sources
All needed source code you can find on
http://www.codeplex.com/Catharsis/
How do I see the MVC ver. MVP:
http://www.codeproject.com/KB/aspnet/AspNetMvcMvp.aspx
History