Passing Model Information between pages

Topics: Web Client Software Factory, User Forum
Oct 28, 2007 at 11:17 PM
Team,
I am new to WCSF and I have a question on managing some user information in session state. In the application I am developing I not using the pageflow application block. Entire page navigation is controlled by the respective controllers injected into the active presenters. The question I have are:

1) When I move from one page to another, what is the best way to pass the required information from page 1 to page 2. I am collecting these information in a Model and I am wondering how to pass this to the next page. Should I manage this information in current session and load the same information in the page_load event of the second page? Or is there a better way to manage this challenge. I looked through the RI's and none of them seem to use session to pass data between pages. I read some challenges this will add in to testability.

In my case, the scenario is like this, I capture the personal Info in page 1, add that in to a model and then I move to page 2 where I capture the spouse information, then all the kids in household. Once all tabs/pages are filled in the data needs to be persisted in DB. Other than using session and page flow store is there a better way to pass the model information. If I need to use session, is there any best practice that can be followed under the umbrella of WCSF.

Please share any thoughts or ideas that can help me.
Thanks
SKR
Oct 29, 2007 at 6:38 AM
Edited Oct 29, 2007 at 6:38 AM
Hi SKR

WIth PageFlow you can actually store your model data in the flow. It will automatically serialize along iwth the PageFlow itself and thus be available throughout the pages within the flow. To do this store your model by accessing the UserData Collection on the PageFlow itself. Below is a snippet from our PageFlowWIthShoppingCart Quick start.

    public class StoreController
    {
        private IPageFlowProvider _pageFlowProvider;
        private IPageFlow _storePageFlow;
 
        public StoreController(IPageFlowProvider provider)
        {
            _pageFlowProvider = provider;
        }
 
        public IPageFlow StorePageFlow
        {
            get
            {
                if (_storePageFlow == null)
                {
                    _storePageFlow = _pageFlowProvider.GetPageFlow(typeof(StorePageFlow));
                }
                return _storePageFlow;
            }
        }
 
        public ShoppingCart Cart
        {
            get
            {
                if (!StorePageFlow.UserData.Contains("Cart"))
                {
                    StorePageFlow.UserData["Cart"] = new ShoppingCart(Thread.CurrentPrincipal.Identity);
                }
                return (ShoppingCart)StorePageFlow.UserData["Cart"];
            }
            set { StorePageFlow.UserData["Cart"] = value; }
        }
        ...

You can see in the above snippet that the ShoppingCart instance is stored in the PageFlow. Whenever a transition occurs in the flow, the ShoppingCart can be retrieved. Note, the type needs to be marketd serializable in order to have it persisted.

If you are using PageFlow this is the recommended method. Now serialization can be costly, so depending on the server load and amount of traffic you expect you may or may not want to store the model here. A variation on this is to only store IDs in the PageFlow for the model references and then grab the model either from the cache, or instantiate a new instance. Another option is to replace the PageFlow persistance mechanism so that it only uses the one in memory. Paulo Morgado has a great post on this that you can find here. http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx.

Hope this helps
Glenn
Oct 29, 2007 at 4:06 PM
Hi Glenn,

Thanks for the quick reply and I really appreciate your help. I guess I was not clear in my first post. My application is not using pageflow application block to handle the navigation. The reasons are varied and I am not going into that aspect. So the whole navigation part --> from page1.aspx to page2.aspx is managed at the controller. Also we are using user control's heavily in each pages. (Thanks to the latest code drop which support some level of DI for user controls and master pages.)

Having said that, Let me explain my challenge.

I have the page1.aspx which has userControl1.ascx embedded in the page. This user control accepts the personal information of the user. The page1.aspx has a button and on click of the same the user shall be navigated to page2.aspx. The page2.aspx has two user controls --> first one same as in page1.aspx - userControl1.ascx and userControl2.ascx. When page2.aspx is displayed the userControl1.aspx shall be prepopulated with the data which user entered in page1.aspx. In page2.aspx, the user can edit the same data or add more info to the page through the userControl2.aspx.

The challenge I am facing here is, how to pass the information from page1.aspx to user controls in page2.aspx. Since I am NOT using pageflow block, I guess I need to manage this data in the session. Is this a correct way to do in terms of WCSF? If so, how to tie the session lookup process to the presenter of the user control? Or is there a better solution of this challenge which you can think of.

Any help is highly appreciated.

Best
SKR

Oct 30, 2007 at 9:36 AM
Hi

I'm using HttpSessionState for everything I need to pass between pages (if not using pageflow). If you want to have data available across modules I think you have to, but thats maybe your case here? I would also like to hear if there is some best practices on this.

Anyway, this is how I have done it;

I have created a Session-object that I saves in the session. The object is created in Global.asax when a session starts like this:

void Session_Start(object sender, EventArgs e)
{
SessionCache sessionCache = new SessionCache(Session);
Session.Add("SessionCache", sessionCache);
}

All my pages inherites from BasePage and that makes the "SessionManager" available for all pages like this:

private SessionCache sessionManager;
public SessionCache SessionManager
{
get { return this.sessionManager; }
}

protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
sessionManager = (SessionCache)Session"SessionCache";
}

Then you have access to the session-object from all your pages that inherits from BasePage. Note here that the reason for creating the SessionCache-object is that you can use access variables in Session without the casting from object.

Hope this was what you where looking for....

-RightCoder

Oct 30, 2007 at 2:18 PM
Hi RightCoder,

Thanks for the help. Yes this solution will definitely solve the issue I am having right now. I will try this out and post the results.

Best
Shibu
Nov 17, 2007 at 11:18 PM
Edited Nov 17, 2007 at 11:22 PM
Hi Shibu

You can also look at using the StateDependency attribute to declaratively inject values from Session State. Below is an example from the docs of doing this via Constructor injection. You can also use this attribute on a public property or method.

class SampleClass
{
  private StateValue<string> _myStringValue;
 
  public SampleClass([StateDependency("stringKey")] StateValue<string> myStringValue)
  {
    _myStringValue = myStringValue;
  }
  public string MyStringValue
  {
    get { return _myStringValue.Value; }
  }
}

Note: The StateDependency attribute is available in the Composite Web Client Library and not in WCSF 1.1.

Regards
Glenn
Dec 1, 2007 at 10:26 AM
Hi,

I am developing an application where-in there is only one webpage called default.aspx. In the page there is different placeholders which potentially will be filled with user-controls depending upon the kind of module user is requesting to contribute to the page. Is there any way to implement page flow kind of thing with user controls so that rights and priviledges of specific kind of user can be maintained in the application.

Thanks & Regards
Abhijit
Dec 4, 2007 at 7:26 AM

gblock wrote:
Hi Shibu

You can also look at using the StateDependency attribute to declaratively inject values from Session State. Below is an example from the docs of doing this via Constructor injection. You can also use this attribute on a public property or method.


Hi Glenn,

Would this be faster than using Userdata?
I am asking this because I noticed that the SqlWorkflowPersistenceService will persist on every change of the userdata.
This means that if you need store 5 different statevariables, the state will be persisted (and retrieved!) 5 times. Depending on the size of the businessmodel you put in the statemachine this can give you a performancepenalty. We have a webfarm, so sessionstate is not an option.

A reasonable solution for this could be 1 property of type List<string, object>.

Regards,

Mike
Dec 7, 2007 at 3:18 AM
Greetings Glen,
Thanks for the help. I tried to implement the solution and I just want to make sure that I am right with in the context of WebSF.

Take a case like this for the sake of discussion.

IIndexView - View Interface
Index.aspx = the ASPX page
IndexPresenter - the presenter class and
SomeController - Controller for the module.

Customer, Address and ContactDetails are the domain entities or Business Enttities which acts as the model in this case.

So we define in IIndexView properties like this.

Customer MyCustomer {get; set;}
Address MyAddress {get; set;}
In IndexPresenter.cs we can refer the same as View.Customer and View.Address. If needed the same can be passed to Controller as well as arguments.

Suppose that we need to get share the Customer information across pages. So the simplest way is to store it in session. For testability reasons we need to use StateValue<T> template class.

So my question here is, Should I attribute the property inside the Index.aspx code behind class with StateDependency attribute to something like this.

public class Index: Page, IIndexView
{
    
   private StateValue<Customer> _myCustomer;       
    
    [StateDependency("currentCustomer")]   
    public Customer MyCustomer
    {
          get 
              {
                  return _myCustomer.value;
               }
           set
              {
                // set the object properties
               Customer _aCustomer = new Customer();
               _myCustomer.value = _aCustomer;
              }
     }
}

And now, CompositeWeb library will set Customer Object to the session and in another page or presenter of another page I retrieve the same using StateDependency attributre.
Is this process correct. Or shall I set the value to session in the presenter of the first page.

If you happen to have a sample code of a Aspx page, A view and a presenter which uses the StateDependency can you share the same. For me WebSF is very new and out of that StateDependency seems to be vague to me. So any help will be highly appreciated.

Thanks once again for the wonderful work you are doing for the community.

Best
Shibu Raj





gblock wrote:
Hi Shibu

You can also look at using the StateDependency attribute to declaratively inject values from Session State. Below is an example from the docs of doing this via Constructor injection. You can also use this attribute on a public property or method.

class SampleClass
{
  private StateValue<string> _myStringValue;
 
  public SampleClass([StateDependency("stringKey")] StateValue<string> myStringValue)
  {
    _myStringValue = myStringValue;
  }
  public string MyStringValue
  {
    get { return _myStringValue.Value; }
  }
}

Note: The StateDependency attribute is available in the Composite Web Client Library and not in WCSF 1.1.

Regards
Glenn

Dec 7, 2007 at 4:56 AM
Hi Shibu

The sample you are showing looks correct. You should be able to use the StateDependency attribute to store and retrieve the value from the Session across pages. I don't have a good sample, but I can write you one if you want :)

The StateValue<T> type encapsulates pushing and retrieving the value to the Session if it is available. If you have 2 properties on different pages that are both decorated with StateDependency attributes pointing to the same key, then they will both retireve and set the same value in the Session.

Let me know if you need me to draw up a sample, and I will :)
Dec 7, 2007 at 8:16 PM
Greetings Glen,

Thanks for the email. If you can, I would really appreciate a sample with a View, Model, Presenter and controller. This will help me as well as others in the community to use as a reference. My confusion with my example is it seems to me like I am doing the same process in two places - code behind file as well as presenter. So if we get a sample from an expert like you will be definitelt useful. Really appreciate your time and the help you are extending to me.

Thanks
Shibu Raj


gblock wrote:
Hi Shibu

The sample you are showing looks correct. You should be able to use the StateDependency attribute to store and retrieve the value from the Session across pages. I don't have a good sample, but I can write you one if you want :)

The StateValue<T> type encapsulates pushing and retrieving the value to the Session if it is available. If you have 2 properties on different pages that are both decorated with StateDependency attributes pointing to the same key, then they will both retireve and set the same value in the Session.

Let me know if you need me to draw up a sample, and I will :)

Jan 8, 2008 at 11:00 AM
Hi,

I am developing an application where-in there is only one webpage called default.aspx. In the page there is different placeholders which potentially will be filled with user-controls depending upon the kind of module user is requesting to contribute to the page. Is there any way to implement page flow kind of thing with user controls so that rights and priviledges of specific kind of user can be maintained in the application.

Thanks & Regards
Abhijit
Developer
Jan 14, 2008 at 4:19 PM
Hi

The Page Flow Application Block provides you with an infrastructure that helps you control the sequence of the Web pages that users see as they interact with your application. The application block is usable out of the box, but it is designed to be easy to extend and modify. So you can build your own custom page flow and make it useful by user controls.

You can review this topic in the WCSF documentation to understand its design:
  • Web Client Software Factory - June 2007 -> Inspecting the Software Factory Assets -> Application Blocks -> Page Flow Application Block -> Design of the Page Flow Application Block
Please let me know if this helps.

Mariano Converti
http://staff.southworks.net/blogs/mconverti/
Jul 24, 2009 at 3:40 AM

Hi shibukraj,

Did you get sample from Glen?

I need help to understand StateValue<T> for my load-balance environment.
Can I use StateValue<T> so sessions are managed and available on multiple servers (where same application is deployed)?
OR do I need to consider any special considerations here to achieve my objective?

Any help greatly appreciated.

Thanks and regards,
- Satish