Since I already blogged about MVC.NET and loosely coupled design with Spring.NET, I decided to review the same architecture approach within the context of MVC.NET 3.
For some background refer my previous articles on this subject:
http://kbochevski.blogspot.com/2009/11/mvc-custom-authorization.html
http://kbochevski.blogspot.com/2010/03/mvcnet-and-ioc-using-spring-net.html
http://kbochevski.blogspot.com/2010/06/unit-testing-mvcnet.html
In generally the goals stay the same:
· Loosely coupling the building components of the MVC.NET application
· Achieving better granularity at code level and unit testing the components
· Achieving custom authorization at role and user level, fine-grained control over action methods
· Reviewing how the .Net framework v4 and the new features which I missed in MVC.NET helped me out to resolve architecture, data validation and security problems like XSS attacks
· Presenting cool thin client built with jquery grid
Tightly coupled vs. loosely coupled in the world of MVC.NET and inversion of control
Since MVC.NET as a framework implies to separation of concerns by its nature, the more accurate and reasonable question is : what are the surrounding components that build one MVC.NET application?
Beside the framework in a real life application we also have to deal with many more components like database, GUI frameworks (jquery plugins, extjs, YUI, etc.), web services, reports, etc. So, if we review the most common scenario we will have next components which we should handle:
· MVC.NET framework OB (out-of-the-box)
· Database
· Business logic. Let’s mark this one as a separate component which may be referred and used in our MVC.NET application
· GUI
Considering what our components are, we usually have to build an application which is cost-effective, extensible, maintainable, and testable. All those factors are in their nature quite subjective, but let’s review how the loosely coupled approach helps us to resolve some problems and makes our life (as developers) easier.
Tightly and loosely coupled architectures, and the Inversion of Control are very abstract as terminology and explanations. I won’t copy paste their definitions here, but I will try to give my explanation in the terms of MVC.NET application.
The tightly coupled approach will be to put all of the listed above components in one solution, or to make project reference between the MVC.NET web project and the rest of the projects (no matter how many they are, how they are grouped and managed). Doing so, all of our components will know about the rest of components at compile time, and will depend on them to compile and function properly.
Life is easier, future is dark… In fast growing and evolving enterprise application, inevitably we will end up facing problems like refactoring, functionality changes, and quality demands. If we put the all of the components within the same project, or hard reference them we will potentially have next problems:
· Logic leaks: Nobody and nothing can stop a developer from instantiating the database context within action method in a controller, querying it and rendering the result. Yes, no doubt it will be most likely faster to achieve, but we should ask ourselves – What controllers, database entities and database tables have in common? And the reasonable answer is – they have nothing to do with each other. Another scenario is the supporting of application once it goes life (hopefully…at the end we all code for this). Well, if we build our application as tightly coupled, changing one component will imply to changing all components that refer it and use its functionality, rebuilding all the projects and wondering how to deliver a patch which may not be related to most of the assemblies that we rebuilt. The scenarios here might be complex and scary…
· Code duplication: Referring and instantiating components across our application will lead to code duplication. This makes the refactoring and unit-testing unbearable burden. Imagine what one change request may bring…chaos and much iteration to validate it. For sure that will be neither cost effective, nor maintainable. The bodies of our methods become more longer, more messy and more mixed with database stuff, business logic, action results, etc.
The loosely coupled approach in our case will be to isolate the instantiating of the components from their functionality. The instances of the components will be launched run time, but they will communicate to each other based on their contracts (functionality contracts from business perspective, interfaces from development perspective). In the same time since they depend on each other based on their features (contracts), we can always replace one component with another as long as it provides the same functionality which the consumer expects.
In our case we can always replace the database layer, the business logic implementation and even the database. All these components don’t know about the others at compile time, but know how to consume the exposed by them functionality.
· Pros: Obviously we are safe in the terms of logic leaks, which is a very strong advantage. The components are more independent, hence easier maintainable and testable. The overall solution is more scalable and extensible because of the granularity of its components. Imagine how easier would be to build a web service on the top of our existing functionality rather than developing its logic from scratch (with copy\paste in most of the cases). And what if we decide to change our presentation layer. Should we redevelop all business logic, all persistence logic from scratch? We can develop only the UI, but to keep what we have in terms of logic implementation.
· Cons: This approach has its own learning curve. New to these concepts developers may face some problems at the beginning. Also the performance is worse in most of the cases.
Inversion of control and dependency injection
Spring.NET instantiates a component and injects it in another component (consumer) which uses its functionality. For example Spring.NET instantiates the UserService class, which provides functionality related to the user management and authentication, and injects it in Controller class, which on his behalf knows how to use it.
Don’t over-engineer your solution
Always consider as many as possible points of view when you design your application. At the end the ultimate goal of our work is to make the clients happy…and happiness has many aspects, most of them unfortunately not related to architecture, but to the functionality and the price. For smaller applications, which are unlikely to evolve, sophisticated approach like loosely-coupling the dependencies might be budget overkill.
Even though I prefer to design my applications as loosely-coupled even if I don’t use IoC frameworks. I just try to put the “right” design, which I can improve in the future. That would be my solid baseline.
Let’s dive into the technical aspects
We reviewed the pros and cons of the approaches, some valid cases which we better consider when designing our applications. Now let’s see how we implemented the loosely coupled approach with MVC.NET and Spring.NET as IoC framework.
Our code sample contains 10 projects, which form the set of components which are decoupled.
· The “Business” folder contains the domain objects and the business functionality of our application.
· “DataAccess” folder the data access layer implementation which is based on the repository pattern.
· WebPlatformMVCNet is our startup MVC.NET application.
· WebPlatform.Data contains the database layer based on Entity model.
· Platform.Contracts contains all contracts (interface) definitions which are referred by the rest components and define the functionality which will be exposed through them. This project should not refer any of the solution projects, because you will easily end up with circular dependency.
· WebPlatform.Core contains common functionality implementation and provides single location of reused logic and behavior among the projects in the solution.
· WebPlatformTests contains the unit tests based on NUnit framework.
Let’s quickly review the database diagram from our code-sample, which you can download at the bottom of this article.
It is designed to be extensible and quite granular. The “Modules” table holds the names of all modules in our application. The “Function” table contains the names of the functions (actions) which exist in the application. “Users” and “Roles” tables are straight-forward and self-explanatory. “AccessToModuleFunctions” is the most important table since it describes the mapping of users’ rights to the corresponding functionality within a certain module. If the user don’t have specific access right, then his role (if assigned) is been checked. Hence, one user can obtain access to certain functionality either through his username assignment or through his role.
Database backup can be found in the source code.
Spring.NET with MVC.NET 3
In the previous versions of MVC.NET we could download the MVCContrib.Extras.release, get the MvcContrib.Spring.dll and type few lines of code to plug the IoC framework in the controllers factories.
private void ConfigureIoC()
{
WebApplicationContext webApplicationContext = ContextRegistry.GetContext() as WebApplicationContext;
DependencyResolver.InitializeWith(new SpringDependencyResolver(webApplicationContext.ObjectFactory));
ControllerBuilder.Current.SetControllerFactory(typeof(IoCControllerFactory));
}
Well, this one doesn’t work any longer.
MVC.NET 3 presented IDependencyResolver and DependencyResolver for allocating components that we want to get injected by the underlying dependency injection container.
So, to make things work for us we implemented our own dependency resolver.
public class SpringDependencyResolver : IDependencyResolver
{
private Spring.Objects.Factory.Config.IConfigurableListableObjectFactory springFactory;
public SpringDependencyResolver(Spring.Objects.Factory.Config.IConfigurableListableObjectFactory factory)
{
this.springFactory = factory;
}
#region IDependencyResolver Members
public object GetService(Type serviceType)
{
var instances = this.springFactory.GetObjectsOfType(serviceType);
var enumerator = instances.GetEnumerator();
enumerator.MoveNext();
try
{
return enumerator.Value;
}
catch (Exception)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this.springFactory.GetObjectsOfType(serviceType).Cast<object>();
}
#endregion
}
Then, we need to register the resolvers in global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalFilters.Filters.Add(new CompressionFilterAttribute());
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
log4net.Config.XmlConfigurator.Configure();
IResource daoInput = new FileSystemResource(Server.MapPath("~/Config/DAO.xml"));
IObjectFactory daoFactory = new XmlObjectFactory(daoInput);
IResource servicesInput = new FileSystemResource(Server.MapPath("~/Config/Services.xml"));
IObjectFactory servicesFactory = new XmlObjectFactory(servicesInput, daoFactory);
IResource controllersInput = new FileSystemResource(Server.MapPath("~/Config/spring-config.xml"));
DependencyResolver.SetResolver(new WebPlatformMVCNet.Utils.SpringDependencyResolver(new XmlObjectFactory(controllersInput, servicesFactory)));
}
Now we are ready to inject dependencies, which we have defined in our xml config files
public abstract class BaseController : Controller
{
public abstract IUserService UserService { get; set; }
private const string cookieName = "AccessibleMenus";
protected override void OnException(ExceptionContext filterContext)
{
if (filterContext.HttpContext.IsCustomErrorEnabled)
{
//just sample logging
log4net.ILog log = log4net.LogManager.GetLogger(GetType());
log.Error(filterContext.Exception.Message, filterContext.Exception);
filterContext.ExceptionHandled = true;
ViewData["ErrorMessage"] = filterContext.Exception.Message;
string errorView = ((System.Web.Mvc.ViewResult)(filterContext.Result)).ViewName ?? "Error";
this.View(errorView).ExecuteResult(this.ControllerContext);
}
}
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
HttpCookie cookie = requestContext.HttpContext.Request.Cookies[cookieName];
if (cookie != null)
{
ViewData[cookieName] = Array.ConvertAll(cookie.Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries), m => Convert.ToByte(m)).ToList();
return;
}
AuthenticationWebPlatformPrincipal webPlatformPrincipal = requestContext.HttpContext.User as AuthenticationWebPlatformPrincipal;
if (webPlatformPrincipal == null)
return;
IList<byte> modules = this.GetAccessableModuleNames(webPlatformPrincipal.UserData.UserID);
ViewData[cookieName] = modules;
cookie = new HttpCookie(cookieName, string.Join(",", modules.ToArray()));
cookie.Expires = DateTime.Now.AddMinutes(20);
requestContext.HttpContext.Response.Cookies.Add(cookie);
}
}
Our abstract base controller class returns list of modules which the authenticated user has access to. It has injected “UserService” instance through which it requests the required functionality.
Regardless if the user sees the menus rendered in the output html, our custom authorize attribute prevents him from accessing functionality which he is not allowed to.
public class ActionAuthorizeAttribute : AuthorizeAttribute
{
public Modules Module { get; set; }
public Functions Permission { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
AuthenticationWebPlatformPrincipal webPlatformPrincipal = filterContext.HttpContext.User as AuthenticationWebPlatformPrincipal;
if (webPlatformPrincipal == null)
{
CloseConnection(filterContext);
return;
}
List<byte> functionIds = new List<byte>();
foreach (Functions function in Enum.GetValues(typeof(Functions)))
{
if ((Permission & function) == function)
functionIds.Add((byte)function);
}
BaseController controller = filterContext.Controller as BaseController;
if (controller == null || controller.UserService == null)
{
CloseConnection(filterContext);
return;
}
byte moduleId = (byte)Module;
if (!controller.UserService.IsUserAuthorized(webPlatformPrincipal.UserData.UserID, moduleId, functionIds))
CloseConnection(filterContext);
}
}
User “administrator” has no access to Product module, and even if he knows the url and tries to access it, he will get the next result:
Technical challenges
From technical point of view the biggest challenge which we have to handle is how to keep the components independent. We have to make them “speak” a language which is not strictly bound to their definition (object instances), but to their functionality features.
Application layers and components communicate through interfaces or generic collections, which are defined in the Platform.Contracts project.
The hardest task to achieve is to decouple the database from the business logic layer, because the database in our case is LINQ To Entities model, which every developer can regenerate at certain moment during the development life-cycle.
If we want our data access layer (built with Repository pattern) to expose the generic collections or interfaces which represent the entities from generated database model, we have to either create classes inheriting from the generated entity classes or to make the entities from Entity Framework to implement interfaces and to return these interfaces as return types. This approach will secure our loosely coupled design and will decouple the database from the rest of the application layers.
public interface IDBContext
{
IQueryable<IUser> Users { get; }
IQueryable<IAccessToModuleFunctions> AccessToModuleFunctions { get; }
IQueryable<IModulesFunction> ModulesFunctions { get; }
IQueryable<IModule> Modules { get; }
IQueryable<IFunction> Functions { get; }
IQueryable<IRole> Roles { get; }
IQueryable<IProduct> Products { get; }
IQueryable<IOrder> Orders { get; }
void AddToUsers(IUser user);
IUser CreateUser(Int32 id, String userName, String hash, String salt, String firstName, String lastName, String email);
void SaveChanges();
}
I defined contract called IDBContext, which will contain IQuerable<T> collections representing the Entity Framework entities. IDBContext will also contain all operations that we would like to perform against the database through the Entity Framework supported functionality.
Our entities from the Entity Framework on their behalf must also implement interfaces. The partial classes allow us to extend the behavior outside of the generated code.
public partial class ModulesFunction : IModulesFunction
{
}
public partial class Module : IModule
{
}
public partial class Function : IFunction
{
}
public partial class Role : IRole
{
}
public partial class Product : IProduct
{
}
public partial class Order : IOrder
{
}
All of the interfaces must have exactly the same properties as their corresponding generated entities.
If we define our Entity interfaces manually this becomes a boring and time consuming task. T4 templates could be decent choice to automate this in your projects.
You can see that generated entity’s class placed in the designer.cs has the same public properties as our interface IModule.
Another partial class which implements our IDBContext extends the Entity Framework generated database model.
Covariance which is one of the new features in .NET 4.0 allows us to return entities as IQuarable<Interface>, which indeed is great improvement compared to the previous versions.
In .NET 3.5 when we didn’t have covariance, we had to solve our problems with extension methods like this:
public static class Extensions
{
/// <summary>
/// Casts all objects inside an IQueryable<T> to their corresponding interface type
/// </summary>
/// <typeparam name="TClass">Type of the class</typeparam>
/// <typeparam name="TInterface">Interface to which to cast to</typeparam>
/// <param name="source">Source collection</param>
/// <returns></returns>
public static IEnumerable<TInterface> AsInterfaceEnumerable<TClass, TInterface>(this IQueryable<TClass> source)
where TClass : class, TInterface, new()
where TInterface : IEntity
{
foreach (var item in source)
yield return (TInterface)item;
}
}
The rest of the job is handled by Spring.NET, which reads its configuration files and injects IDBContext in our repositories.
Refer my previous post about deeper explanations about Spring.NET with MVC.NET.
The last thing which I will mention is about controlling the scope of the objects which we inject.
If we inject DBContext at application scope we may end up with weird messages about failed DBContext operations. The scope of the injected objects must be either session or request. We have to refer Spring.Web assembly to secure this.
XmlObjectFactory is defined in Spring.Core, and the “session” and “request” scopes maintenance are defined in Spring.Web. So, regardless if we put scope “request”, when we use XmlObjectFactory it won’t work.
That is why we have to use webApplicationContext.ObjectFactory and to make the configurations in our web.config which are related to Spring.
Since Spring.NET relies on HttpModules for loading the resources, hence we can access WebApplicationContext in Init() event in global.asax. The code sample has the code commented out in Init().
Validation
Always validate your inputs on every possible place: client side, code behind (business logic), even at database level. This becomes more valid in the loosely coupled context, because every of our components might be plugged in another application which doesn’t do any validations.
For client side validation i recommend you to check the article of Nikolay, who has many more cool posts about the client side development.
Refer Nikolay’s article for demonstrating how to prevent a MVC.NET application from XSS attacks.
GUI layer or polishing our views
JQuery grid gives us extremely flexibility, because it is easily extensible and comes with sorting, paging and searching functionality out-of-the-box.
In our sample we used it to list the products defined in our database.
The multi-criteria searching in this case is very flexible, because its rules are handled by expression trees.
Refer this link for deeper details http://www.codeproject.com/KB/aspnet/AspNetMVCandJqGrid.aspx.
The parameters which are specific to the jquery grid (page, sidx, sort, etc..) are passed through the layers by a single object instance. Doing so, we keep the parameters which are related to the presentation layer, but used even in our repositories (we need them for the paging, sorting and searching) wrapped within a single object.
Unit testing the components of loosely coupled MVC.NET application
The components that ideally we would like to have unit tested are:
· Repository logic – paging, filtering, sorting
· Business logic – the most important part of every application. Here are implemented all business rules and requirements.
· Controllers actions and their results –even JSON result can be unit tested
· Routing rules
MvcContrib.TestHelper.dll and Rhino.Mocks.dll come to help and to mock our external dependencies.
The code below displays how I mocked the database context generated from Entity framework. We have to override its IQuerable<T> properties, which we want to replace runtime with our custom (fake) object collections.
Refer the code sample for more details on the unit tests.
The related source code can be downloaded here.
Links and sources used:
http://www.springframework.net/
http://mvccontrib.codeplex.com/
http://www.trirand.com/blog/?page_id=6
http://trirand.com/blog/jqgrid/jqgrid.html
http://jqueryui.com/themeroller/
http://ayende.com/blog
http://www.nunit.org/?p=download
http://www.codeproject.com/KB/cs/stringenum.aspx
http://www.codeproject.com/KB/aspnet/AspNetMVCandJqGrid.aspx - many thanks to the guys for the deep and detailed explanations and for the code as well.
Thanks for sharing ! awesome work :)
ReplyDeleteHi !!!
ReplyDeleteIs there another way to get source code ? I am not getting it from SVN...
Thanks,
Marcelo.
Hi !!!
ReplyDeleteIs there another way to get source code ? I am not getting it from SVN...
Thanks,
Marcelo.
mmorpg oyunlar
ReplyDeleteinstagram takipçi satın al
Tiktok jeton hilesi
TİKTOK JETON HİLESİ
antalya saç ekim
referans kimliği nedir
İnstagram Takipçi Satın Al
MT2 PVP SERVERLER
INSTAGRAM TAKİPÇİ SATIN AL
perde modelleri
ReplyDeletesms onay
mobil ödeme bozdurma
Nft Nasıl Alinir
ANKARA EVDEN EVE NAKLİYAT
Trafik Sigortası
dedektör
web sitesi kurma
aşk kitapları
smm panel
ReplyDeleteSmm Panel
iş ilanları
İNSTAGRAM TAKİPÇİ SATIN AL
Hirdavatci Burada
beyazesyateknikservisi.com.tr
Servis
jeton hilesi indir
Good content. You write beautiful things.
ReplyDeletemrbahis
mrbahis
vbet
hacklink
hacklink
vbet
korsan taksi
taksi
sportsbet
Success Write content success. Thanks.
ReplyDeletebetpark
betturkey
kıbrıs bahis siteleri
kralbet
canlı slot siteleri
betmatik
deneme bonusu
dijital kartvizit
ReplyDeletereferans kimliği nedir
binance referans kodu
referans kimliği nedir
bitcoin nasıl alınır
resimli magnet
İAOH
hatay
ReplyDeletekars
mardin
samsun
urfa
QF2
amasya
ReplyDeletetokat
samsun
yozgat
zonguldak
7X6FW
شركة كشف تسربات المياه بالجبيل lVuTHi2tNo
ReplyDelete