MVP implementation questions
-
I'm currently looking into using the MVP pattern for creating web applications and have some questions: - If state needs to be recorded I presume its done in the model, if the model classes are in an assembly separate from the actual pages do you still use session or some other form of state management? - How is UI logic such as "disable this button unless condition is met" handled? is the logic embedded in the view ( or the page code behind), presenter or model. Can any body can provide some detail/thoughts in relation to these areas?
Lowest of the Low wrote:
MVP pattern for creating web applications
IMO, MVP is most suitable for stand-alone applications and MVC is more suitable for web applications.
Lowest of the Low wrote:
If state needs to be recorded I presume its done in the model, if the model classes are in an assembly separate from the actual pages do you still use session or some other form of state management?
If the model is in separate assembly and to use session, you need a reference to
System.Web
assembly and hence making it strongly coupled. To avoid this, you can wrap the state management in well defined interfaces and inject to the model using dependency injection. So that your model will be isolated.Lowest of the Low wrote:
How is UI logic such as "disable this button unless condition is met" handled? is the logic embedded in the view ( or the page code behind), presenter or model.
Passive View approach will be obvious for this. Here are few links which will help 1 - Passive view - A .NET approach[^] 2 - MVP in ASP.NET[^] Hope this helps :)
Navaneeth How to use google | Ask smart questions
-
Lowest of the Low wrote:
MVP pattern for creating web applications
IMO, MVP is most suitable for stand-alone applications and MVC is more suitable for web applications.
Lowest of the Low wrote:
If state needs to be recorded I presume its done in the model, if the model classes are in an assembly separate from the actual pages do you still use session or some other form of state management?
If the model is in separate assembly and to use session, you need a reference to
System.Web
assembly and hence making it strongly coupled. To avoid this, you can wrap the state management in well defined interfaces and inject to the model using dependency injection. So that your model will be isolated.Lowest of the Low wrote:
How is UI logic such as "disable this button unless condition is met" handled? is the logic embedded in the view ( or the page code behind), presenter or model.
Passive View approach will be obvious for this. Here are few links which will help 1 - Passive view - A .NET approach[^] 2 - MVP in ASP.NET[^] Hope this helps :)
Navaneeth How to use google | Ask smart questions
Thanks for the response. MVC is not currently an option for us (new technology...risk...etc, etc) but changing our existing webforms development to use MVP is something that could be done. I looked at Phil Haack's ASP.NET Supervising Controller (Model View Presenter) From Schematic To Unit Tests to Code[^] which looks good. I still have other questions like where is validation done? And in relation to your comment on injecting state via interface I'm being a bit thick today but how? Surely if I use session I'd still need a reference to System.Web? or are you suggesting that I could provide access to session through another object?
-
Thanks for the response. MVC is not currently an option for us (new technology...risk...etc, etc) but changing our existing webforms development to use MVP is something that could be done. I looked at Phil Haack's ASP.NET Supervising Controller (Model View Presenter) From Schematic To Unit Tests to Code[^] which looks good. I still have other questions like where is validation done? And in relation to your comment on injecting state via interface I'm being a bit thick today but how? Surely if I use session I'd still need a reference to System.Web? or are you suggesting that I could provide access to session through another object?
Lowest of the Low wrote:
MVC is not currently an option for us (new technology...risk...etc, etc)
Well, I was not talking about the ASP.NET MVC framework. I was talking about the MVC concept.
Lowest of the Low wrote:
I still have other questions like where is validation done?
For trivial validations, view is the appropriate place. But if you have very complex business validations, you probably need put it outside of the view.
Lowest of the Low wrote:
And in relation to your comment on injecting state via interface I'm being a bit thick today but how?
You define an interface with the necessary properties and methods. Implement this interface in the same project where you have access to session. Then inject this interface instance to model(or whatever area). Read about dependency injection[^].
Navaneeth How to use google | Ask smart questions
-
Lowest of the Low wrote:
MVC is not currently an option for us (new technology...risk...etc, etc)
Well, I was not talking about the ASP.NET MVC framework. I was talking about the MVC concept.
Lowest of the Low wrote:
I still have other questions like where is validation done?
For trivial validations, view is the appropriate place. But if you have very complex business validations, you probably need put it outside of the view.
Lowest of the Low wrote:
And in relation to your comment on injecting state via interface I'm being a bit thick today but how?
You define an interface with the necessary properties and methods. Implement this interface in the same project where you have access to session. Then inject this interface instance to model(or whatever area). Read about dependency injection[^].
Navaneeth How to use google | Ask smart questions
Query for you on the Dependency injection, does that not violate the OOP "Dependency Inversion Principle"?
-
I'm currently looking into using the MVP pattern for creating web applications and have some questions: - If state needs to be recorded I presume its done in the model, if the model classes are in an assembly separate from the actual pages do you still use session or some other form of state management? - How is UI logic such as "disable this button unless condition is met" handled? is the logic embedded in the view ( or the page code behind), presenter or model. Can any body can provide some detail/thoughts in relation to these areas?
The general goal behind MVP is to isolate as much logic from the "view" as possible, just like with MVC. The benefits of MVP over MVC are primarily realized when a complete rewrite of an existing WebForms app into an MVC framework can't be done (which sounds like your situation). I've implemented MVP a couple times for existing ASP.NET WebForms sites, and its been quite successful. In terms of managing state, etc. There are a lot of different kinds of state, and it depends on what state your talking about. ASP.NET WebForms state should probably be keept in the same locations it would have been keept before for basic stuff. If you had a ViewState property on a Page that held a CustomerID, for example, you should probably keep it in the Page ViewState. As for logic...put as much as humanly possible in the Presenter. The presenter is like the controller from MVC, and one of the main reasons for having it is to allow you to maintain SoC, separation of concerns. A view is just a representation of data, and it really shouldn't contain logic. In the case of WebForms, it will probably need to contain a little bit to handler data set on it by the presenter and render it, but keep it minimal. The presenter should handle all the logic of processing your page, it should contain event handlers to handle events on the view (including events inherited from Page and Control), it should validate input, and decide when to enable/disable controls. The view should be a standard WebForms .aspx page with codebehind. However, in addition, you will need to create and implement an interface that represents your view. This interface is the access point for the presenter. The proper form of either Passive View or Supervising Controller MVP is that the presenter does not maintain any direct references to the view, only to an interface that represents the view. This allows the presenter to be used for multiple similar views. The view itself should handle the process of creating the presenter, and passing itself to the presenter (thats how the presenter gets a reference to the views interface). This view interface should contain all properties and events on the view, as well as exposing common stuff from the Page class as well, such as the standard page events (OnInit, OnLoad, OnPreRender, etc.) If you need any more help, I'd be glad to offer it. I have a small MVP framework that I've written that is very lightweight and easy to integrate into existing apps a view at a time, with little configuration. I have considered writing an
-
The general goal behind MVP is to isolate as much logic from the "view" as possible, just like with MVC. The benefits of MVP over MVC are primarily realized when a complete rewrite of an existing WebForms app into an MVC framework can't be done (which sounds like your situation). I've implemented MVP a couple times for existing ASP.NET WebForms sites, and its been quite successful. In terms of managing state, etc. There are a lot of different kinds of state, and it depends on what state your talking about. ASP.NET WebForms state should probably be keept in the same locations it would have been keept before for basic stuff. If you had a ViewState property on a Page that held a CustomerID, for example, you should probably keep it in the Page ViewState. As for logic...put as much as humanly possible in the Presenter. The presenter is like the controller from MVC, and one of the main reasons for having it is to allow you to maintain SoC, separation of concerns. A view is just a representation of data, and it really shouldn't contain logic. In the case of WebForms, it will probably need to contain a little bit to handler data set on it by the presenter and render it, but keep it minimal. The presenter should handle all the logic of processing your page, it should contain event handlers to handle events on the view (including events inherited from Page and Control), it should validate input, and decide when to enable/disable controls. The view should be a standard WebForms .aspx page with codebehind. However, in addition, you will need to create and implement an interface that represents your view. This interface is the access point for the presenter. The proper form of either Passive View or Supervising Controller MVP is that the presenter does not maintain any direct references to the view, only to an interface that represents the view. This allows the presenter to be used for multiple similar views. The view itself should handle the process of creating the presenter, and passing itself to the presenter (thats how the presenter gets a reference to the views interface). This view interface should contain all properties and events on the view, as well as exposing common stuff from the Page class as well, such as the standard page events (OnInit, OnLoad, OnPreRender, etc.) If you need any more help, I'd be glad to offer it. I have a small MVP framework that I've written that is very lightweight and easy to integrate into existing apps a view at a time, with little configuration. I have considered writing an
You've hit my situation on the head, said I was being a bit thick earlier today couldn't even explain the situation I'm in very well. In work we have moved to an agile way of working involving a lot of TDD and that is one of the main drivers for looking to try and move to a MVP style of development. The state issue is a concern because we do use session for storing some info and currently we have to reference
System.Web
in our existing equivilant of the model and this is one of the main issues I need to try and overcome before being able to implement MVP. Any thoughts you've got would be appreciated. -
You've hit my situation on the head, said I was being a bit thick earlier today couldn't even explain the situation I'm in very well. In work we have moved to an agile way of working involving a lot of TDD and that is one of the main drivers for looking to try and move to a MVP style of development. The state issue is a concern because we do use session for storing some info and currently we have to reference
System.Web
in our existing equivilant of the model and this is one of the main issues I need to try and overcome before being able to implement MVP. Any thoughts you've got would be appreciated.I would be glad to help. There is a lot of rave these days about MVC, partially because of greater TDD movements, partly because of ASP.NET MVC. MVC is definitely nice, but its not the solution to every presentation problem. I would like to get a bit more information about your exact scenario. From a rigid design perspective, your Model should be abstracted away from the views as much as possible, completely isolated even. The "bridge" between view and model is the presenter/controller. It depends on the scale of the application, but model could actually be a full Domain Model. Its also possible that you have a domain, but it is isolated by a set of services. Sometimes people share their domain accross the wire from services, but going back to the core principals of programming...Separation of Concerns, Single Responsibility, Isolation, etc. it might be best to have a presentation-specific model that you create from your domain or whatever your services return to give you an added degree of separation and testability. Anyway...if you can give me a concrete example (you can keep it simple) of how your view, presenter, and model are interacting now (or would), and note where your storing state or having state issues, I'll see what I can do to help you organize it better. Sometimes its just a matter of the wrong class doing something useful...and splitting the class in two and putting the other part in a different namespace/project solves the problem.
-
I would be glad to help. There is a lot of rave these days about MVC, partially because of greater TDD movements, partly because of ASP.NET MVC. MVC is definitely nice, but its not the solution to every presentation problem. I would like to get a bit more information about your exact scenario. From a rigid design perspective, your Model should be abstracted away from the views as much as possible, completely isolated even. The "bridge" between view and model is the presenter/controller. It depends on the scale of the application, but model could actually be a full Domain Model. Its also possible that you have a domain, but it is isolated by a set of services. Sometimes people share their domain accross the wire from services, but going back to the core principals of programming...Separation of Concerns, Single Responsibility, Isolation, etc. it might be best to have a presentation-specific model that you create from your domain or whatever your services return to give you an added degree of separation and testability. Anyway...if you can give me a concrete example (you can keep it simple) of how your view, presenter, and model are interacting now (or would), and note where your storing state or having state issues, I'll see what I can do to help you organize it better. Sometimes its just a matter of the wrong class doing something useful...and splitting the class in two and putting the other part in a different namespace/project solves the problem.
ok here's the details: The current application effecively has View and model but no presenter but the app does generally follow good OOP with SoC, Single Responsibility, Create don't use etc. All business logic and db access is handled in the model which is in a seperate assembly and has been created as a domain model. A fair amount of model information is accessed through properties which store their data in session (the model is closer to a desktop type app than a web app). The code behind's of the pages mostly data bind to the properties exposed by the model although there is a lot of logic around controlling the UI (including a hack of the treeview to add a link to child nodes). Whilst ViewState is not disabled it is generally not used for storing of any particular stateful information. One reason for the need to store the stateful information is that the application is generally driven by meta data so that when different clients access the application the app points to a different database and calls different stored procedures when working the data. We use code from Phil Haack for simulating HttpSession to allow us to perform unit tests on the model, and we have fairly good coverage over the classes. The application works well enough but it seems a good candidate for refactoring as its fairly simple but meaty enough to present a challenge.
-
ok here's the details: The current application effecively has View and model but no presenter but the app does generally follow good OOP with SoC, Single Responsibility, Create don't use etc. All business logic and db access is handled in the model which is in a seperate assembly and has been created as a domain model. A fair amount of model information is accessed through properties which store their data in session (the model is closer to a desktop type app than a web app). The code behind's of the pages mostly data bind to the properties exposed by the model although there is a lot of logic around controlling the UI (including a hack of the treeview to add a link to child nodes). Whilst ViewState is not disabled it is generally not used for storing of any particular stateful information. One reason for the need to store the stateful information is that the application is generally driven by meta data so that when different clients access the application the app points to a different database and calls different stored procedures when working the data. We use code from Phil Haack for simulating HttpSession to allow us to perform unit tests on the model, and we have fairly good coverage over the classes. The application works well enough but it seems a good candidate for refactoring as its fairly simple but meaty enough to present a challenge.
Ok, before I dive into anything else...I think a critical distinction is that Model is most definitely not state. In your case...your model is storing both business data and state. Thats a blending of concerns, and a fairly critical one at that. Its very important to maintain a separation between business modeling facilities, and user state facilities. User state is transient, it lasts for the duration of the users visit and then dissapears. Model state is, generally, persistant...regardless of where it is stored. The purpose of state data and model data is also generally very different. You have connected two concerns into your model objects that, before anything else, should be separated into isolated facilities that serve just one function. So you need one system to manage state, and another to manage business. Management, or orchestration, of the two...state and business data, would then be done by a third facility...quite possibly the presenters, or maybe another system that the presenters use. But I would say its very, very important to separate state from your model...otherwise I am not sure that a viable implementation of an MVP can really be achieved. A good way to put it is that state is part of context. Context always exists, sometimes its not very obvious. Context also exists at various levels...application, thread, call, etc. Another important aspect about context is that it is a cross-cutting concern...it spans layers and levels of code. This should clarify why state (context) doesn't belong in a model object. If you can separate these concerns properly, you should be able to avoid even having to simulate HttpSessionState for unit testing, as you should be able to create your own custom session object that would in turn delegate to either HttpSessionState (for an actual representation), or possibly just a dictionary or hashtable (for a mock representation). Is there any way you can show an example of one of your model objects? I may be able to help you separate state out of them, but still allow you to achieve the kind of muti-tennancy you need (if you don't know this term, it pretty much referrs to the way you store data in different databases for different customers).
-
Ok, before I dive into anything else...I think a critical distinction is that Model is most definitely not state. In your case...your model is storing both business data and state. Thats a blending of concerns, and a fairly critical one at that. Its very important to maintain a separation between business modeling facilities, and user state facilities. User state is transient, it lasts for the duration of the users visit and then dissapears. Model state is, generally, persistant...regardless of where it is stored. The purpose of state data and model data is also generally very different. You have connected two concerns into your model objects that, before anything else, should be separated into isolated facilities that serve just one function. So you need one system to manage state, and another to manage business. Management, or orchestration, of the two...state and business data, would then be done by a third facility...quite possibly the presenters, or maybe another system that the presenters use. But I would say its very, very important to separate state from your model...otherwise I am not sure that a viable implementation of an MVP can really be achieved. A good way to put it is that state is part of context. Context always exists, sometimes its not very obvious. Context also exists at various levels...application, thread, call, etc. Another important aspect about context is that it is a cross-cutting concern...it spans layers and levels of code. This should clarify why state (context) doesn't belong in a model object. If you can separate these concerns properly, you should be able to avoid even having to simulate HttpSessionState for unit testing, as you should be able to create your own custom session object that would in turn delegate to either HttpSessionState (for an actual representation), or possibly just a dictionary or hashtable (for a mock representation). Is there any way you can show an example of one of your model objects? I may be able to help you separate state out of them, but still allow you to achieve the kind of muti-tennancy you need (if you don't know this term, it pretty much referrs to the way you store data in different databases for different customers).
ok I understand the problem. Here's a small representation of the objects: AuthorisationLogic (used for authorising work in the model) - Property UnreleasedSummary (bound by page) - Method: GetUnreleasedSummary (called by page and results stored in property). The actual data returned is an object graph which consists of:
WorkItem
(a container for work to authorise for a user) this in turn contains aList<WorkItemData>
. AWorkItemData
object has details about the actual work that has been done and needs to be authorised and also contains a propertyList<Commands>
with each command holding the name of the specific stored procedure to call to authorise an individualWorkItemData
instance. AWorkItemData
can also hold the actual data that is being authorised for the user to review in anotherList
and this will be bound to in the View. Thats a one of the simple interactions hope I've put in enough details. I can tell you that the original reason that for a lot of data being stored in session was so that additional calls to the database could be avoided. -
ok I understand the problem. Here's a small representation of the objects: AuthorisationLogic (used for authorising work in the model) - Property UnreleasedSummary (bound by page) - Method: GetUnreleasedSummary (called by page and results stored in property). The actual data returned is an object graph which consists of:
WorkItem
(a container for work to authorise for a user) this in turn contains aList<WorkItemData>
. AWorkItemData
object has details about the actual work that has been done and needs to be authorised and also contains a propertyList<Commands>
with each command holding the name of the specific stored procedure to call to authorise an individualWorkItemData
instance. AWorkItemData
can also hold the actual data that is being authorised for the user to review in anotherList
and this will be bound to in the View. Thats a one of the simple interactions hope I've put in enough details. I can tell you that the original reason that for a lot of data being stored in session was so that additional calls to the database could be avoided.Yeah, that helps to clarify things a bit. I would say that your not really storing user state or dealing with context at all in that situation. What you are doing is caching. I still think that storing your state in the session directly is creating an undesired link between your model and the system and frameworks that display data from the model. The simplest solution is to abstract the caching a bit by creating a simple, mockable caching system:
// Contract of a cache
interface ICache
{
void Add(string key, object toCache);
object Get(string key);
void Remove(string key);
}// Session-based cache for live system
class SessionCache: ICache
{
private HttpSessionState Session
{
get
{
if (HttpContext.Current != null)
HttpSessionState.Current.Session;
return null;
}
}private bool IsSessionAvailable { get { return HttpContext.Current != null; } } public void Add(string key, object toCache) { if (!IsSessionAvailable) throw new InvalidOperationException("Session cache is only available within an HttpContext."); Session\[key\] = toCache; } public object Get(string key) { if (!IsSessionAvailable) throw new InvalidOperationException("Session cache is only available within an HttpContext."); object item = Session\[key\]; return item; } public void Remove(string key) { if (!IsSessionAvailable) throw new InvalidOperationException("Session cache is only available within an HttpContext."); Session.Remove(key); }
}
// Dictionary based cache for unit testing
class DictionaryCache: ICache
{
private Dictionary<string,> m_cache;private Dictionary<string,> Cache { get { if (m\_cache == null) { Interlocked.CompareExchange(ref m\_cache, new Dictionary<string,>(), null); } return m\_cache; } } public void Add(string key, object toCache) { Cache.Add(key, toCache); } public object Get(string key) { object item = Cache\[key\]; return item; } public void Remove(string key) { Cache.Remove(key); }
}
// Facade that acts as a single access point to cache
static class CacheManager
{
private static ICache s_cache;public static ICache C
-
Yeah, that helps to clarify things a bit. I would say that your not really storing user state or dealing with context at all in that situation. What you are doing is caching. I still think that storing your state in the session directly is creating an undesired link between your model and the system and frameworks that display data from the model. The simplest solution is to abstract the caching a bit by creating a simple, mockable caching system:
// Contract of a cache
interface ICache
{
void Add(string key, object toCache);
object Get(string key);
void Remove(string key);
}// Session-based cache for live system
class SessionCache: ICache
{
private HttpSessionState Session
{
get
{
if (HttpContext.Current != null)
HttpSessionState.Current.Session;
return null;
}
}private bool IsSessionAvailable { get { return HttpContext.Current != null; } } public void Add(string key, object toCache) { if (!IsSessionAvailable) throw new InvalidOperationException("Session cache is only available within an HttpContext."); Session\[key\] = toCache; } public object Get(string key) { if (!IsSessionAvailable) throw new InvalidOperationException("Session cache is only available within an HttpContext."); object item = Session\[key\]; return item; } public void Remove(string key) { if (!IsSessionAvailable) throw new InvalidOperationException("Session cache is only available within an HttpContext."); Session.Remove(key); }
}
// Dictionary based cache for unit testing
class DictionaryCache: ICache
{
private Dictionary<string,> m_cache;private Dictionary<string,> Cache { get { if (m\_cache == null) { Interlocked.CompareExchange(ref m\_cache, new Dictionary<string,>(), null); } return m\_cache; } } public void Add(string key, object toCache) { Cache.Add(key, toCache); } public object Get(string key) { object item = Cache\[key\]; return item; } public void Remove(string key) { Cache.Remove(key); }
}
// Facade that acts as a single access point to cache
static class CacheManager
{
private static ICache s_cache;public static ICache C
Jon, thanks for all the help, I had one of those moments where I thought I knew what I was doing and in a few simple sentances I realise how wrong I was. I would like to continue the 'conversation' about this but not sure the forum is the best place for this. Thanks again for all the help.
-
Jon, thanks for all the help, I had one of those moments where I thought I knew what I was doing and in a few simple sentances I realise how wrong I was. I would like to continue the 'conversation' about this but not sure the forum is the best place for this. Thanks again for all the help.
-
Hi Nathan, I would love to continue the conversation as well. Perhapse IM would be best...a real-time forum might be best suited to helping you improve your architecture. I'll email you my contact info.
That would be greatly appreciated Jon. 'bout to pack it in this evening but sure can arrange time when both of us are around :)
-
Hi Nathan, I would love to continue the conversation as well. Perhapse IM would be best...a real-time forum might be best suited to helping you improve your architecture. I'll email you my contact info.
Hi Jon, I tried to email you via the link but don't know if its working. Hoping you'll get notified of this as could do with discussing the architecture. You can get me at nathans.FICTICIOUSVALUE.dropbox@NONSENSEVALUE.googlemail.RANDOMVALUE.com I'll leave you to sort out the email address ;)