.NET and me Coding dreams since 1998!

30Jul/087

Model View Presenter (MVP) – Tips from trenches (TFT) – Working with HttpContext (Part 2)

 


Intro


This is part 2 of blog post series where I am presenting solutions I came up with to some common problems developers are facing implementing the MVP pattern in real world applications.


Previously on tips from trenches:



Today’s hurdle: Using HttpContext without System.Web


(Source code used in today’s example can be downloaded from here)


One of the principles I really feel strong about can be formulated like this:”Presenter is not allowed to reference System.Web assembly at all”.


Main reason why I feel so strong about that, is based on the fact that once referenced System.Web enables developers in your team to use types from that assembly (HttpContext, Session, Query, Cache etc) and we all know what PITA those types can be when testing Presenters.


Here’s very simple example I’ll use in today’s post:



Imagine you have a presenter which based on value of some query parameter is performing some redirecting or updating UI elements.


The easiest way (referencing the System.Web into presenter) will enable very easy implementation of required functionality but testing that code will require things like creating fake web context which IMHO is good sign of of important web test smell.


Luckily, there’s a solution :)


Model View Presenter pattern combined with Adapter design pattern offers easy and effective way of tackling this problem and this post is showing how to do that.


Adapter design pattern


This pattern is one of patterns I recently rediscovered as maybe one of the most useful patterns in every day programing. The pattern itself is not very sexy, because it is very simple. It’s purpose is to handle the cases Adapter_realexamplewhenever we need to adapt the interface of one component to the interface we need.


Canonical example mostly used in explaining the pattern is the case of US and European power adapters. I am sure I am not the only one European who found himself shocked by the fact that power outlets in USA are totally different then the European one. In other words, European power sockets are wider and round while US are narrow and flat. Luckily, there’s Ebay where one can buy himself an adapter compatible with USA power outlets with entry holes compatible to European standards. That’s how you charge your laptop using original cable adapted to custom power outlet.


Adapter design pattern is exactly the same thing.



As we can see on above diagram, when client calls a Target object he would get instance of Adapter inheriting from Target which will delegate to SpecificRequest method of of Adaptee object all of the calls for Request() method (Adaptee object is containing instance of Adapter).
In other words, Adapter “implements via delegation” to Adaptee.



Building the TDD friendly HttpContext





 


Implementation of TDD friendly HttpContext will be based on couple of steps:



  • building System.Web agnostic interface which would:

    • perform the role of Facade by hiding most of the the members not important for MVP

    • perform a role of a service contract which would be used by IoC container where custom HttpContext service will be need

  • building special collection type which would enable us transparent intercepting interface members access

  • building HttpContext service adapter which would implement the interface by delegating all of the calls to interface members to System.Web.HttpContext

  • registering service into IoC container

Defining IHttpContextService


As previously mentioned, first step in implementing the TDD friendly http context is defining the feature list I am expecting to use in my Presenters. Based on some of my current experiences, that interface might look like this:


image


You can see from the interface definition to the left that (IMHO) important http context members are:



  • Redirect(url) method – When presenter andor controller are responsible for driving navigation (more about controller in upcoming post)

  • QueryString property – read only name-value collection property which contains collection of string pairs representing url parameter name and value

  • User property  - IPrincipal type doesn’t require usage of System.Web and defines a lot of useful things for implementing presenters

  • ContextItems  - read only property of custom name value collection type (more about that in second) which contains collection of string pairs representing name of httpcontext item and value that item carries

  • Session – read only property of custom collection type containing string pairs representing application session variable entries

Key point here is that none of the members is not returning types from System.Web and that there are no Response, Request etc members. Only a small subset of really needed things defined in “easy to mock” way.



One thing Web Client Software Factory failed


While we speak about interface definition I would like to mention here a thing I’ve been disappointed seeing how it is been implemented there.


WCSF has IHttpContextLocatorService implemented like this (taken from reflector)

public interface IHttpContextLocatorService
{
// Methods
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
IHttpContext GetCurrentContext();
}

and that IHttpContext interface look like this (part of)

public interface IHttpContext
{
// Methods
HttpApplicationState Application { get; }
HttpApplication ApplicationInstance { get; set; }
Cache Cache { get; }
HttpContext Context { get; }
ProfileBase Profile { get; }
HttpRequest Request { get; }
HttpResponse Response { get; }
}

As you can see by the fact that interface has members of types defined in System.Web, in order to use IHttpContextLocatorService I am still required to use System.Web. In other words, to get url query parameter I would still have to use System.Web.HttpRequest.


I might be missing something pretty big here, but IMHO there is no sense at all in how P&P team implemented this service. Testing pain I felt using WCSF related to this made me thinking about better solutions and this post is result of that :)


HookableNameValueCollection


Now when you saw interface definition and heard where from inspiration for this post came, let’s talk about the custom collection I used in interface while defining type of Session and ContextItems properties.


Design goal behind the decision for creating this collection is to provide the same simple feeling working with http context adapter as the one we are used to it while using the real HttpContext.


Here are some simple examples of  what behavior I wanted to get:



  • var x=httpContextService.Session[“SOME_KEY”]    

  • httpContextService.Session[“SOME_KEY”] =”123”; 

  • httpContextService.Session.Add(“SOME_KEY”,123); 

  • httpContextService.Session.Remove(“SOME_KEY”); 

And here is what I was trying to avoid:



  • var x= httpContextService.GetSessionValue(“SOME_KEY”)

  • httpContextService.UpdateSessionItemValue(“SOME_KEY”,”123”)

  • httpContextService.RemoveSessionItem(“SOME_KEY”)

One way to do that is to play again with Adapter pattern and transform HttpSessionState to IDictionary based adapter class and use that adapter type, but that would be solution specific only to this problem and (if there is an option) I always try to solve problem with reusable solutions. The way I have picked for this blog post is simply to create custom name value collection type where I am going to override Add/Remove/Set methods and raise appropriate events informing listeners that certain activity occurred.


Something like this:


image


Here’s the same diagram given through plain old c# code  

namespace Vuscode.Framework.Abstractions
{
using System;
using System.Collections.Specialized;

public class HookableNameValueCollection : NameValueCollection
{
public EventHandler<HookItemChangedEventArgs> ItemAdded;
public EventHandler<HookItemChangedEventArgs> ItemSet;
public EventHandler<HookItemRemovedEventArgs> ItemRemoved;

public override void Add(string name, string value)
{
base.Add(name, value);
if (ItemAdded != null)
ItemAdded(this, new HookItemChangedEventArgs(name, value));
}

public override void Set(string name, string value)
{
base.Set(name, value);
if (ItemSet != null)
ItemSet(this, new HookItemChangedEventArgs(name, value));
}

public override void Remove(string name)
{
base.Remove(name);
if (ItemRemoved != null)
ItemRemoved(this, new HookItemRemovedEventArgs(name));
}
}
}


 


 



Building HttpContext service adapter


Once we have IHttpContextService and HookableNameValueCollection implemented, implementing httpcontext adapter is very simple implementation of  the context interface.


Due to the fact that we would have to reference System.Web in order to adapt certain properties, I will create new component called Framework.Adapters and put the adapter class implementation there.


Implementation in general would look like this:



  • Redirect method, QueryString collection property and User property would just delegate their calls to HttpContext.Current instance

  • HttpContextServiceAdapter class subscribe to ContextItems and Session add/update/set events and performs appropriate calls to HttpContext.Current.Session and HttpContext.Current.Items

Let’s take a peek at how this implementation looks like in the C# code …

#region

using System.Collections.Specialized;
using System.Security.Principal;
using System.Web;
using Vuscode.Framework.Abstractions;
using Vuscode.Framework.Abstractions.Web;

#endregion

namespace Framework.Adapters.Web
{
public class HttpContextServiceAdapter : IHttpContextService
{
private readonly HookableNameValueCollection _context
= new HookableNameValueCollection();

private readonly HookableNameValueCollection _session
= new HookableNameValueCollection();

public HttpContextServiceAdapter()
{
InitSessionVariables();
InitContextVariables();
}

#region IHttpContextService Members

public NameValueCollection QueryString
{
get { return HttpContext.Current.Request.QueryString; }
}

public void Redirect(string url)
{
HttpContext.Current.Response.Redirect(url);
}

public IPrincipal User
{
get { return HttpContext.Current.User; }
set { HttpContext.Current.User = value; }
}

public HookableNameValueCollection Session
{
get { return _session; }
}

public HookableNameValueCollection ContextItems
{
get { return _context; }
}

#endregion

private void InitContextVariables()
{
if (HttpContext.Current.Items != null)
foreach (string itemsKey in HttpContext.Current.Items.Keys)
{
_context.Add(itemsKey,
HttpContext.Current.Items[itemsKey].ToString());
}

_context.ItemAdded += ((sender, e)
=> HttpContext.Current.Items.Add(e.Name, e.Value));
_context.ItemSet += ((sender, e)
=> HttpContext.Current.Items[e.Name] = e.Value);
_context.ItemRemoved += ((sender, e)
=> HttpContext.Current.Items.Remove(e.Name));
}

private void InitSessionVariables()
{
if (HttpContext.Current.Session != null)
foreach (string sessionKey in HttpContext.Current.Session.Keys)
{
_session.Add(sessionKey,
HttpContext.Current.Session[sessionKey].ToString());
}

_session.ItemAdded += ((sender, e)
=> HttpContext.Current.Session.Add(e.Name, e.Value));
_session.ItemSet += ((sender, e)
=> HttpContext.Current.Session[e.Name] = e.Value);
_session.ItemRemoved += ((sender, e)
=> HttpContext.Current.Session.Remove(e.Name));
}
}
}


Key points:



  • Constructor calls two methods:

    • InitContextVariables – which iterates through all of the  current Httpcontext.Current.Items and populate with their values custom context collection. After that, there’s code which implements event handlers for events published from context custom collection by using the lambda expressions. That’s how when ItemAdded event would be raised it would result with _httpContext.Items.Add method execution

    • InitSessionVariables – same story here. Code first populate custom session collection with the entries already stored in session and then hooks up custom events with appropriate HttpContext Session methods

  • Redirect method just delegates to _httpContext.Response.Redirect() method

  • User property delegates implementation to _httpContext.User

  • QueryString delegates implementation to _httpContext.Request.QueryString

IoC container context service registration


Now when we have service contract (IHttpContextService) and service (HttpContextServiceAdapter), the only thing left to be done is registering them into IoC container so presenters can use them in decoupled manner.


Doing that is very simple… First we add a reference to Framework.Adapters to web application project in order to get access to HttpContextServiceAdapter class. Then we create a simple class called BootStrapper.cs into web application root folder looking something like this

using Framework.Adapters.Web;
using Vuscode.Framework;
using Vuscode.Framework.Abstractions.Web;

namespace Vuscode.Web.WebSite
{
public class Bootstrapper
{
public static void Init()
{
ServiceLocator.Register
<IHttpContextService, HttpContextServiceAdapter>();
}
}
}


At the end we just add call to Bootstrapper Init method into Application_Start event handler of global.asx so our IoC container would be populated at the beginning of web application life cycle.  


Solution in action


Now when infrastructure is in place, implementing HttpContext related logic in presenter  is very trivial

using Vuscode.Framework;
using Vuscode.Framework.Abstractions.Web;
using Vuscode.Framework.ModelViewPresenter;

namespace Presenters
{
public class DefaultViewPresenter : Presenter
{
private readonly IHttpContextService _httpContextService;

#region .ctors
public DefaultViewPresenter()
: this(ServiceLocator.Retrieve<IHttpContextservice>()){ }

internal DefaultViewPresenter(IHttpContextService httpContextService)
{
_httpContextService = httpContextService;
}
#endregion

public void SomeMethod()
{
string urlParam = _httpContextService.QueryString[“param”];
if (!string.IsNullOrEmpty(urlParam))
View.Parameter =urlParam;
if (urlParam == “nikola”)
_httpContextService.Redirect(“vuscode.com”);
}
}
}


At the beginning of the class we have standard poor man dependency injection combined with service locator thing.
(In case you are not familiar with what I just said go and check one of my Design For Testability (DFT) posts)


After we would inject the http context service it’s usage is exactly the same as it would be usage based on HttpContext.Current (which was one of the design goal) so everyone in your team should be able to start using it immediately 


Unit testing HttpContext related presenter code


The test og SomeMethod given above can be now written before the SomeMethod implementation and it doesn’t require  any Web reference.
Here is the fragment of the test illustrating how simple now is to test the HttpContext related things in Presenters (complete test fixture code can be found in code sample archive attached at the beginning of this post)

        [TestMethod]
public void SomeMethod_InCaseOfNikolaParamValue_WouldRedirectToVuscode()
{
using (_mockRepository.Record())
{
// setting up the stage
SetupResult.For(_mockedHttpContextService.QueryString)
.Return(new NameValueCollection() { { “param”, “nikola” } });

// defining expected behavior
_mockedHttpContextService.Expect(x => x.Redirect(“vuscode.com”));
}
using (_mockRepository.Playback())
{
var presenter = new DefaultViewPresenter
(_mockedHttpContextService) {View = _mockedView};
presenter.SomeMethod();
}
}


As you can see it from code above, to get url needed for test set up all one need to do is to set QueryString property of mocked IHttpContextService to contain desired URL parameters.


Then I define expected behavior using new Rhino Mock 3.5 syntax for void methods where I said that I expect that redirection to www.vuscode.com would occur.


Once the recording is over, in playback part I inject the mocked http context service and mocked view and call SomeMethod.


Ain’ that piece of cake? :)


What’s next?


Today I showed how to implement TDD friendly http context and introduced new infrastructure component Framework.Adapters.
My next blog post would introduce the role of Application controller in MVP (as a ported solution from WCSF)


‘till then…


Filed under: Uncategorized 7 Comments
27Jul/087

Model View Presenter (MVP) – Tips from trenches (TFT) – Base types(Part 1)

 


 


Intro


RAD tooling style Microsoft is supporting last couple of years usually leads to the code where presentation and bossiness logic are mixed and tightly coupled which makes testability, maintainability and sustainability much more harder then they should be. In case you’ve had to work in the past with web pages containing couple of thousands lines in code behind you will know exactly what problems I am referring to here. In case not, please let me know what is the name of the place where you work :)


One way to tackle that is using the Model View Presenter UI design pattern which provides clean separation between UI and domain logic and as a result of that come testability of the “UI code”, SRP and SOC principles appliance, clean domain model etc…


In case you never heard about MVP pattern, before continuing reading this blog posts you might want to take some time and look at Model View Presenter (MVP) pattern (L100). In case you heard about it, but you are not familiar very much with what exactly it is, you might want to read about Supervising controller and Passive view. In case you are wondering what is the difference between MVP and “the one everyone talks about MVC”, I tried to explain that here. In case you are looking for advices on building new web site based on MVP pattern, the guys at Microsoft did great job with Web Client Software Factory, so check that out.In case you knew already all this but never had chance to apply MVP in real world and/or you face some problems applying it in real world, you are at the right place :)


Purpose of this blog post series is to share with community my experiences on the typical hurdles I was witnessing during the MVP based web site implementation.


Today’s hurdle: MVP wire up code noiseimage


(Source code used in today example can be downloaded from here)


Basically there are couple of ways to wire up  presenter and the view, but after some experiments with constructor based injection and after working for some time with Web Client Software Factory (WCSF) I kind a like setter based dependency injection style.


Let take a look at that code noise through an example of simple web site with just a single Default page which would have a separate class library project containing view interface (which btw I name following the rule IPageNameView ) and presenter (convention I follow here is PageNameViewPresenter)


The view interface could look for this example something like this:

namespace Presenters
{
public interface IDefaultView
{
int SomeValue { get; set; }
}
}

 


 


Here’s the presenter code example similar to a lot of presenters I’ve seen

namespace Presenters
{
public class DefaultViewPresenter
{
private IDefaultView _view;

public IDefaultView View
{
get { return _view; }
set { _view = value; }
}

public void SomeMethod()
{
if (View.SomeValue>0)
{
// do something
}
}

public void OnViewInitialized()
{
// do something on view init
}

public void OnViewLoaded()
{
// do something on view load
}
}
}


Interesting points of presenter code:



  • Presenter has a View property of IDefaultView type

  • how presenter uses  view inside of SomeMethod()

  • existence of two methods which are supposed to be called upon page load and init

Let’s take a peek now at how the view (default web page) would end wired up with the presenter

using System;
using System.Web.UI;
using Presenters;

namespace WebApplication1
{
public partial class _Default : Page, IDefaultView
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Presenter = new DefaultViewPresenter();
}

protected void Page_Load(object sender, EventArgs eventArgs)
{
if (!Page.IsPostBack)
{
Presenter.OnViewInitialized();
}
Presenter.OnViewLoaded();
}

private DefaultViewPresenter _presenter;

public DefaultViewPresenter Presenter
{
get { return _presenter; }
set
{
_presenter = value;
_presenter.View = this;
}
}

protected void Something_Clicked(object sender, EventArgs eventArgs)
{
Presenter.SomeMethod();
}

// Here goes implementation of IDefaultView

}
}


Key points regarding view code:



  • OnInit method sets the Presenter property value to new DefaultViewPresenter instance

  • Inside of Presenter property setter View property of the presenter gets web page pointer casted to IDefaultView.
    Effectively, presenter gets injected with a view implicitly cast to view interface

  • Inside of page load method, presenter OnViewInitialized method is get called if the page is not postbacking itself

  • Inside of page load method, presenter OnViewLoaded method is get called regardless of postback

  • Last interesting moment here is how Presenter is get called  from a view in Something_Clicked event handler

Hurdle summary


Writing all of this code for every web page and every control (I will speak about this in later posts) is very tedious and repetitive task. Using WCSF helps a bit because code similar to this gets generated but still that’s a lot of lines written just in order to enable us to start to work on a page.


Luckily, there’s a solution :)


The solution of today’s hurdle would be encapsulating all of the code noise in set of base classes.


The design goals here are:



  • define generic presenter which would be using generic view interfaces

  • define generic view which would perform automatic wire up to generic presenter

Let’s see one way how this can be done….


(My solution is based on Mario Szklanny’s Web Client Software factory solution, which I adopted for use outside of WCSF)


Generic presenter


The code related to this goal will be stored in a class library which I call Framework.


Purpose of Framework assembly is to contain all the basic functionality required for most of the code regardless of it is web/UI related or not. image

That’s why beside the MVP related code there would be (in my case):



  • ServiceLocator type (with code similar to what was described in  DFT Unity  blog post)

  • BaseClass and BaseCollection (very light, providing only basic functionality I personally use in debugging. Definitely NOT supposed to be  god class

  • More other things I won’t mention here (I would be adding them in the upcoming posts so I don’t want to spoil the surprise :))

(In case you are puzzled with reasons behind having Rhino.Mocks reference in Framework, check this out)


Key concern related to this class: No heavy dependencies and definitely no System.Web related references. This component is supposed to be able to be referenced by any component in application


The IPresenter interface defines very simple generic presenter attributes

namespace Vuscode.Framework.ModelViewPresenter
{
public interface IPresenter
{
object View { get; set; }

void OnViewInitialized();

void OnViewLoaded();
}
}


OnViewInitialized and OnViewLoaded are methods we saw in above code as the ones handling calls from Page_Load method. The reason behind the fact that View  is of object type is that we can box any class to object type so we can store reference to boxed form of any view


Generic Presenter class implementing the IPresenter interface could look like this

namespace Vuscode.Framework.ModelViewPresenter
{
public abstract class Presenter<TView> : IPresenter
{
public TView View { get; set; }

#region IPresenter Members

object IPresenter.View
{
get { return View; }
set { View = (TView) value; }
}

public virtual void OnViewInitialized()
{
/* do nothing*/
}

public virtual void OnViewLoaded()
{
/* do nothing*/
}

#endregion
}
}


Looking at the code above one could realize next things:



  • Presenter class is abstract generic class accepting  TView generic parameter and implementing IPresenter interface

  • The two methods are implemented as virtual because we don’t want to enforce implementing this methods in each one of presenters inheriting generic presenter because some of them might not need some of those methods

  • The object View property defined by IPresenter interface is implemented explicitly which effectively hides it from the classes inheriting generic presenter

  • The fact that TView View property is public, combined with mentioned explicit implementation of the object View property effectively constrained View to TView

Generic viewimage


One of the main design principles I am trying to stay with is that Presenter assembly is not allowed to be dependable on System.Web directly or indirectly and therefore due to the fact that Presenters will reference the Framework, I can not put there generic view. 


The reason why I can not do that is based upon the fact that each one of the pages would inherit from that base generic view, so generic view needs to inherit from System.Web.UI.Page


All of the “base web UI” functionality I would keep in component called “Web.Base”


From the solution explorer snapshot on the right side, we can see that project consists of 3 base views: page, control and master page. (Yes, I am applying MVP pattern even on the master page)

using System;
using Vuscode.Framework.ModelViewPresenter;

namespace Vuscode.Web.Base
{
public abstract class ViewBasePage<TPresenter> : LegacyBasePage
where TPresenter : IPresenter, new()
{
private TPresenter _presenter;

protected ViewBasePage()
{
Presenter = new TPresenter();
}

public TPresenter Presenter
{
get { return _presenter; }
set
{
_presenter = value;
_presenter.View = this;
}
}

protected virtual void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Presenter.OnViewInitialized();
}
Presenter.OnViewLoaded();
}

}
}


Interesting moments here are:image



  • ViewBasePage is  abstract generic page where the generic parameter is constrained to type implementing IPresenter interface

  • ViewBasePage inherits from LegacyBasePage
    Most of us have some base page already in our web sites. This illustrates that the ViewBasePage should inherit from that page and then all of the MVP pages would therefore get access to that legacy base page and inherit all of the MVP related code

  • Rest of the code is the same code we had on default page just pulled out to base page level

Code for generic view of control and master page is exactly the same as the page one with only difference from which base type they would inherit (UserControl or MasterPage)



Solution in action


Having Framework and Web.Base component built, would enable us to make changes in presenter and view which would cause them to look like this at the end


View (Default web page)

using System;
using System.Web.UI;
using Presenters;
using Vuscode.Web.Base;

namespace WebApplication1
{
public partial class _Default : ViewBasePage<DefaultViewPresenter>
, IDefaultView
{
protected void Something_Clicked(object sender, EventArgs eventArgs)
{
Presenter.SomeMethod();
}

// Here goes implementation of IDefaultView

}
}


 


The page just inherited form ViewBasePage<DefaultViewPresenter> and all of the plumbing code is gone from the page


Looking much better, isn’t it? :)


Presenter


Presenter is even simpler

using Vuscode.Framework.ModelViewPresenter;

namespace Presenters
{
public class DefaultViewPresenter : Presenter<IDefaultView>;
{
public void SomeMethod()
{
if (View.SomeValue>0)
{
// do something
}
}
}
}


All presenter had to do is to inherit from Presenter<IDefaultView> in order to get View injected and potential to override OnViewXXX methods


Looking much better, isn’t it? :)


What’s next?


Today I showed how to remove code noise from the MVP related types and also set up the foundations of two components: Web.Base and Framework. My next blog post would be expanding a bit framework component in order to show how to work with HttpContext related concepts and values without referencing System.Web into presenters


‘till then…

























 

Filed under: Uncategorized 7 Comments
6Jul/083

Model View Presenter (MVP) – Tips from trenches (TFT) – Announcement

I have blogged already in the past about MVP basics, MVP vs MVC, MVP Passive View and MVP Supervising Controller but recently I had some interesting experiences in applying MVP into real world applications and from that endeavor I learned couple of things and get answers on couple of common questions which I would like to share with community.

To me, the most interesting part of this experience was that some of my MVP based coding was done using Web Client Software Factory but part of MVP coding was done without it, so I had to “port” WCSF features to standard asp net application. I would describe pieces of that port which (I guess) would be interesting for the ones not being able to sell WCSF to their managers but still wanting to use MVP in their ASP NET development.

Another thing I would try to explain is something a lot of people don’t know: Microsoft MVC .NET framework consist of two separate parts: MVC and routing engine. In other words, routing engine is not part of MVC design pattern and it can be used with WebForms too…

Another very important thing in real world MVP development I would try to demo is how to introduce MVP pattern usage in legacy components where the legacy model is not written in decoupled manner (Separate interface, Adapter and Translator design patterns)

Last, but not the least, I would show how MVP pattern is looking combined with ServiceLocator I presented in Design For Testability blog post series and show examples on how to test MVP

Once I finish presenting all this, I would use presented concepts in showing how “one interesting "real world" example” would look like done with MVP pattern and standard WebForms

So, MVP fans stay tuned for the posts to come very fast. People not interested in MVP, please be patient… I just need to nail down MVP , “once for all” :)

Disclaimer: The purpose of this blog post series will not be showing that MVC based web development is worst then the MVP one. MVC is awesome but unfortunately requires too big investments to be introduced in existing large web forms web applications (most noticeably the need for redesigning all code which relies on page event life cycle). For those brownfield scenarios, I found MVP much easier to be implemented and adopted by webform developers then the MVC.

Filed under: Uncategorized 3 Comments