<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Improving The Page Flow Application Block: Removing Database Dependencies</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx</link><description>Introduction Especially in development and demonstration scenarios, the dependency on a database can be a big hassle. In this article I&amp;#39;ll show how to remove this dependency. Instance Correlation Provider A Page Flow Application Block &amp;#39;s instance</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>Resources for geekSpeak - Web Client Software Factory with Paulo Morgado</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1495982</link><pubDate>Mon, 04 Feb 2008 21:56:27 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1495982</guid><dc:creator>Noticias externas</dc:creator><description>&lt;p&gt;Here is a great set of resources from our guest Paulo Morgado. Catch the recording here . Contextual&lt;/p&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1495982" width="1" height="1"&gt;</description></item><item><title>Resources for geekSpeak - Web Client Software Factory with Paulo Morgado</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1495885</link><pubDate>Mon, 04 Feb 2008 21:20:23 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1495885</guid><dc:creator>geekSpeak</dc:creator><description>&lt;p&gt;Here is a great set of resources from our guest Paulo Morgado. Catch the recording here . Contextual&lt;/p&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1495885" width="1" height="1"&gt;</description></item><item><title>re: Improving The Page Flow Application Block: Removing Database Dependencies</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1476429</link><pubDate>Wed, 23 Jan 2008 13:43:57 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1476429</guid><dc:creator>Paulo Morgado</dc:creator><description>&lt;p&gt;Are you sure it&amp;#39;s the compression that is taking the 100 milliseconds? I&amp;#39;m asking because I haven&amp;#39;t measured it yet.&lt;/p&gt;
&lt;p&gt;The &lt;a title="WorkflowPersistenceService.GetDefaultSerializedForm Method" href="http://msdn2.microsoft.com/library/System.Workflow.Runtime.Hosting.WorkflowPersistenceService.GetDefaultSerializedForm.aspx" target="_blank"&gt;WorkflowPersistenceService.GetDefaultSerializedForm&lt;/a&gt; does a lot more than just compression the workflow.&lt;/p&gt;
&lt;p&gt;You can activate the workflow traces (runtime, tracking and host) but setting (in your configuration file) the value of the following &lt;a title="SourceSwitch Class" href="http://msdn2.microsoft.com/library/System.Diagnostics.SourceSwitch.aspx" target="_blank"&gt;SourceSwitch&lt;/a&gt;es:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;System.Workflow.Runtime&lt;/strong&gt; 
&lt;li&gt;&lt;strong&gt;System.Workflow.Runtime.Tracking&lt;/strong&gt; 
&lt;li&gt;&lt;strong&gt;System.Workflow.Runtime.Hosting&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;for the &lt;a title="TraceSource Class" href="http://msdn2.microsoft.com/library/System.Diagnostics.TraceSource.aspx" target="_blank"&gt;TraceSource&lt;/a&gt;s with the same name.&lt;/p&gt;
&lt;p&gt;Additionally, you can enable the following &lt;a title="BooleanSwitch Class" href="http://msdn2.microsoft.com/library/System.Diagnostics.BooleanSwitch.aspx" target="_blank"&gt;BooleanSwitch&lt;/a&gt;es:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;System.Workflow LogToFile&lt;/strong&gt; - To output traces to the &lt;strong&gt;WorkflowTrace.log&lt;/strong&gt; file. 
&lt;li&gt;&lt;strong&gt;System.Workflow LogToTraceListeners&lt;/strong&gt; - To output traces to the &lt;a title="system.diagnostics Element" href="http://msdn2.microsoft.com/library/3f348f42-fa72-4ff2-aa1c-bb9eecad4bb2.aspx" target="_blank"&gt;registered&lt;/a&gt; &lt;a title="trace Element" href="http://msdn2.microsoft.com/library/7931c942-63c1-47c3-a045-9d9de3cacdbf.aspx" target="_blank"&gt;trace&lt;/a&gt; &lt;a title="listeners Element for trace" href="http://msdn2.microsoft.com/library/1394c2c3-6304-46db-87c1-8e8b16f5ad5b.aspx" target="_blank"&gt;listeners&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1476429" width="1" height="1"&gt;</description></item><item><title>re: Improving The Page Flow Application Block: Removing Database Dependencies</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1476337</link><pubDate>Wed, 23 Jan 2008 12:24:35 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1476337</guid><dc:creator>TJ</dc:creator><description>&lt;p&gt;But even if I read and write my data to UserData only once per request I can still take away almost 100 milliseconds by commenting out the compression.&lt;/p&gt;
&lt;p&gt;I&amp;#39;m looking forward to the pageflow bundle that doesn&amp;#39;t require a workflow (&lt;a rel="nofollow" target="_new" href="http://www.codeplex.com/websf/Thread/View.aspx?ThreadId=16781"&gt;www.codeplex.com/.../View.aspx&lt;/a&gt;). You don&amp;#39;t happen to know anything about its schedule?&lt;/p&gt;
&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1476337" width="1" height="1"&gt;</description></item><item><title>re: Improving The Page Flow Application Block: Removing Database Dependencies</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1470849</link><pubDate>Sat, 19 Jan 2008 20:00:03 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1470849</guid><dc:creator>Paulo Morgado</dc:creator><description>&lt;p&gt;When Joern says that &amp;quot;GetDefaultSerializedForm() does the compression&amp;quot;, it&amp;#39;s not because he choosed to. It&amp;#39;s becaus that&amp;#39;s how wrokflow serialization works (look it up with Reflector).&lt;/p&gt;
&lt;p&gt;I think your real problem is too much access to &lt;strong&gt;UserData&lt;/strong&gt; in the same request.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1470849" width="1" height="1"&gt;</description></item><item><title>re: Improving The Page Flow Application Block: Removing Database Dependencies</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1470380</link><pubDate>Sat, 19 Jan 2008 11:51:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1470380</guid><dc:creator>TJ</dc:creator><description>&lt;p&gt;But is there a way to disable compression totally with the current implementation?&lt;/p&gt;
&lt;p&gt;I tried by commenting out these lines in the PageFlowStorageSessionStateProvider (also a few other changes were needed)&lt;/p&gt;
&lt;p&gt;byte[] data = WorkflowPersistenceService.GetDefaultSerializedForm(rootActivity);&lt;/p&gt;
&lt;p&gt;return WorkflowPersistenceService.RestoreFromDefaultSerializedForm(data, outerActivity);&lt;/p&gt;
&lt;p&gt;By doing that I got error messages complaining about PageFlow not beeing serializable and had to switch to InProc mode. Can I also somehow disable compression of the underlying workflow?&lt;/p&gt;
&lt;p&gt;I implemented retrieving all UserData in OnInit and storing in PreRender of a common page base class. Seems to work ok, but I guess there could be a more elegant solution..&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1470380" width="1" height="1"&gt;</description></item><item><title>re: Improving The Page Flow Application Block: Removing Database Dependencies</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1469372</link><pubDate>Fri, 18 Jan 2008 22:40:36 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1469372</guid><dc:creator>Paulo Morgado</dc:creator><description>&lt;p&gt;Every time you access the UserData, the underlying workflow of the page flow is loaded, ran and unloaded. Decompression is part of the loading process and compression is part of the unloading process.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;PageFlow&lt;/strong&gt; object is not serializable because it doesn&amp;#39;t need to. On each request, the underlying workflow is loaded and wrapped by a new &lt;strong&gt;PageFlow&lt;/strong&gt; instance.&lt;/p&gt;
&lt;p&gt;As you figured out, with the present implementation of the WorkflowFoundationPageFlow, you should touch the &lt;strong&gt;UserData&lt;/strong&gt; property as less as possible.&lt;/p&gt;
&lt;p&gt;I totally agree with you that the underlying workflow should only be loaded and unloaded once per HTTP request. I hope to continue this series of articles about the Page Flow Application Block soon and I&amp;#39;ll try to implement that.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1469372" width="1" height="1"&gt;</description></item><item><title>re: Improving The Page Flow Application Block: Removing Database Dependencies</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1468574</link><pubDate>Fri, 18 Jan 2008 10:20:20 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1468574</guid><dc:creator>TJ</dc:creator><description>&lt;p&gt;Thanks for sharing!&lt;/p&gt;
&lt;p&gt;I noticed that the data compression as Joern suggests turned out to be a bit problematic in my case.&lt;/p&gt;
&lt;p&gt;Seems like the compression/decompression occurs each time I access the data. When reading/writing same data multiple times within a single request (like with session you can do), the total time consumed in retrieving/saving the data builds up very high.&lt;/p&gt;
&lt;p&gt;I tried to tackle this problem by commenting out the parts where the compression/decompression occurs and storing an Activity objects instead&amp;nbsp; (this forced me to change session to InProc mode as PageFlow object is not Serializable).&lt;/p&gt;
&lt;p&gt;But still it seems to take an awful long time to get the property Data a few times:&lt;/p&gt;&lt;pre&gt;public MyObject[] Data
{
  get
  {
    if (!CurrentPageFlow.UserData.Contains(&amp;quot;MyObject&amp;quot;))
      return null;
    return CurrentPageFlow.UserData[&amp;quot;MyObject&amp;quot;] as MyObject[];
  }
  set { CurrentPageFlow.UserData[&amp;quot;MyObject&amp;quot;] = value; }
}&lt;/pre&gt;
&lt;p&gt;Should I instead store all my objects inside a container and retrieve/store that object&amp;nbsp; only once per request?&lt;/p&gt;
&lt;p&gt;Also, session enables to do things like this:&lt;/p&gt;&lt;pre&gt;MyObject data = Session[&amp;quot;somekey&amp;quot;];
data.Property = otherdata; // new Property contents will be saved eventually
// With pageflow the data doesn&amp;#39;t get stored I set it explicitly
MyObject data = MyPageFlow.UserData[&amp;quot;somekey&amp;quot;];
data.Property = otherdata;
MyPageFlow.UserData[&amp;quot;somekey&amp;quot;] = data; // This is required&lt;/pre&gt;
&lt;p&gt;What would be the best approach to make the data be stored at the end of the request execution like session does it?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1468574" width="1" height="1"&gt;</description></item><item><title>http://dotnetkicks.com/aspnet/improving_the_page_flow_application_block_removing_database_dependenc</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1464659</link><pubDate>Tue, 15 Jan 2008 22:22:04 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1464659</guid><dc:creator>TrackBack</dc:creator><description>&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1464659" width="1" height="1"&gt;</description></item><item><title>re: Improving The Page Flow Application Block: Removing Database Dependencies</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1363472</link><pubDate>Wed, 28 Nov 2007 00:30:42 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1363472</guid><dc:creator>Paulo Morgado</dc:creator><description>&lt;p&gt;Hi Mike,&lt;/p&gt;
&lt;p&gt;Joem did a great job.&lt;/p&gt;
&lt;p&gt;To make it work in the sample I just replaced:&lt;/p&gt;
&lt;p&gt;&lt;font face="courier new,courier"&gt;&amp;lt;add type=&amp;quot;System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35&amp;quot; connectionString=&amp;quot;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=WCSF_Quickstart;Data Source=.\SQLEXPRESS;&amp;quot; LoadIntervalSeconds=&amp;quot;5&amp;quot; UnloadOnIdle=&amp;quot;true&amp;quot;/&amp;gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;with:&lt;/p&gt;
&lt;p&gt;&lt;font face="courier new,courier"&gt;&amp;lt;add type=&amp;quot;PauloMorgado.Practices.PageFlow.Storage.AspNetSessionState.WorkflowAspNetSessionStatePersistenceService, PauloMorgado.Practices.PageFlow.Storage.AspNetSessionState&amp;quot;/&amp;gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;I&amp;#39;ll post the modified sample as soon as I can.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1363472" width="1" height="1"&gt;</description></item><item><title>re: Improving The Page Flow Application Block: Removing Database Dependencies</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1361393</link><pubDate>Tue, 27 Nov 2007 12:02:51 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1361393</guid><dc:creator>Mike</dc:creator><description>&lt;p&gt;Hi Paulo, Joem,&lt;/p&gt;
&lt;p&gt;Good work! Why didn&amp;#39;t they include it out of the box?!&lt;/p&gt;
&lt;p&gt;I tried Joem&amp;#39;s example. &lt;/p&gt;
&lt;p&gt;However changing the sql provider by itself (1 line in the web.config) is not enough.&lt;/p&gt;
&lt;p&gt;Could you send me a working example by E-mail?&lt;/p&gt;
&lt;p&gt;mi.van.engelenDELETEME@DELETEMEinterpolis.nl&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Mike&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1361393" width="1" height="1"&gt;</description></item><item><title>re: Improving The Page Flow Application Block: Removing Database Dependencies</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1279673</link><pubDate>Sat, 03 Nov 2007 12:12:09 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1279673</guid><dc:creator>Paulo Morgado</dc:creator><description>&lt;p&gt;Thanks a lot Joem.&lt;/p&gt;
&lt;p&gt;This was my first choice of how to do it, but, due to the lack of time and, mostly, Workflow Foundation knowledge, I took the quick way out.&lt;/p&gt;
&lt;p&gt;I'll add it to the article and code download as soon as possilbe (I'm heading for TechEd Developers Europe).&lt;/p&gt;
&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1279673" width="1" height="1"&gt;</description></item><item><title>re: Improving The Page Flow Application Block: Removing Database Dependencies</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1278853</link><pubDate>Fri, 02 Nov 2007 20:53:48 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1278853</guid><dc:creator>Joern</dc:creator><description>&lt;p&gt;Because I did not want to patch the Microsoft.Practices.PageFlow.WorkflowFoundation.WorkflowFoundationPageFlow.Suspend and PageFlow.WorkflowFoundation.WorkflowFoundationPageFlowFactory.GetPageFlow methods and I felt it would be a good idea to have both providers,&lt;/p&gt;
&lt;p&gt;I implemented a memory persistence service. (Based on your correlation provider.)&lt;/p&gt;
&lt;p&gt;It replaces the SQL persistence service and serializes the workflow state to the ASP.NET session. (In a form that should allow it to be persisted to any database.)&lt;/p&gt;
&lt;p&gt;Just replace the SQL provider in the web.config file with this provider.&lt;/p&gt;
&lt;p&gt;Also, if used in a production environment, it saves memory by persisting the workflow to a compressed format if the workflow is idle - which basically means after each page request. (In my tests the persisted workflow required about 7k in compressed format and 60k in uncompressed format.)&lt;/p&gt;
&lt;p&gt;BTW, GetDefaultSerializedForm() does the compression.&lt;/p&gt;
&lt;p&gt;Here is the code:&lt;/p&gt;&lt;pre class="code"&gt;using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Web;
using System.Workflow.ComponentModel;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
namespace Joern.PageFlow.SimpleStorage.SessionState
{
   /// &amp;lt;summary&amp;gt;
   /// Implements the custom WorkflowPersistenceService, which persists workflow instances in the ASP.NET session.
   /// &amp;lt;/summary&amp;gt;
   public class PageFlowStorageSessionStateProvider : WorkflowPersistenceService
   {
       private const string SessionStateStorageName = &amp;quot;PageFlowWorkflowStore&amp;quot;;
       public PageFlowStorageSessionStateProvider()
       {
       }
       #region Serialization
       /// &amp;lt;summary&amp;gt;
       /// Performs the serialization of one activity. Invoked during dehydration.
       /// &amp;lt;/summary&amp;gt;
       /// &amp;lt;param name=&amp;quot;id&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
       /// &amp;lt;param name=&amp;quot;rootActivity&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
       private void SerializeActivity(Guid id, Activity rootActivity)
       {
           byte[] data = WorkflowPersistenceService.GetDefaultSerializedForm(rootActivity);
           SessionStorage.WriteInstanceData(id, data);
       }
       /// &amp;lt;summary&amp;gt;
       /// Performs deserialization of persisted activity. Invoked during rehydration.
       /// &amp;lt;/summary&amp;gt;
       /// &amp;lt;param name=&amp;quot;id&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
       /// &amp;lt;param name=&amp;quot;outerActivity&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
       /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
       private Activity DeserializeActivity(Guid id, Activity outerActivity)
       {
           byte[] data = SessionStorage.LoadInstanceData(id);
           return WorkflowPersistenceService.RestoreFromDefaultSerializedForm(data, outerActivity);
       }
       /// &amp;lt;summary&amp;gt;
       /// Removes the serialization of an activity. Invoked when the workflow is completed or terminated.
       /// &amp;lt;/summary&amp;gt;
       /// &amp;lt;param name=&amp;quot;id&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
       private void DeleteActivity(Guid id)
       {
           SessionStorage.DeleteInstance(id);
       }
       #endregion
       #region Provider Members
       #region WorkflowProvider Interface Implementation
       protected override Activity LoadCompletedContextActivity(Guid scopeId, Activity outerActivity)
       {
           //Trace.WriteLine(&amp;quot;Rehydration&amp;quot;);
           object obj = DeserializeActivity(scopeId, outerActivity);
           return (Activity)obj;
       }
       protected override Activity LoadWorkflowInstanceState(Guid instanceId)
       {
           //Trace.WriteLine(&amp;quot;Rehydration&amp;quot;);
           object obj = DeserializeActivity(instanceId, null);
           return (Activity)obj;
       }
       protected override void SaveCompletedContextActivity(Activity activity)
       {
           Guid contextGuid = (Guid)activity.GetValue(Activity.ActivityContextGuidProperty);
           SerializeActivity(contextGuid, activity);
       }
       protected override void SaveWorkflowInstanceState(Activity rootActivity, bool unlock)
       {
           Guid contextGuid = (Guid)rootActivity.GetValue(Activity.ActivityContextGuidProperty);
           WorkflowStatus workflowStatus = WorkflowPersistenceService.GetWorkflowStatus(rootActivity);
           if ((workflowStatus != WorkflowStatus.Completed) &amp;amp;&amp;amp; (workflowStatus != WorkflowStatus.Terminated))
           {
               SerializeActivity(contextGuid, rootActivity);
           }
           else
           {
               DeleteActivity(contextGuid);
           }
       }
       protected override bool UnloadOnIdle(Activity activity)
       {
           return true;
       }
       protected override void UnlockWorkflowInstanceState(Activity rootActivity)
       {
       }
       #endregion
       #endregion
       private Storage SessionStorage
       {
           get
           {
               Storage pageFlowStorage = HttpContext.Current.Session[SessionStateStorageName] as Storage;
               if (pageFlowStorage == null)
               {
                   HttpContext.Current.Session[SessionStateStorageName] = pageFlowStorage = new Storage();
               }
               return pageFlowStorage;
           }
       }
       [Serializable]
       private class Storage : ISerializable
       {
           private SortedList&amp;lt;Guid, StorageItem&amp;gt; items = new SortedList&amp;lt;Guid, StorageItem&amp;gt;();
           /// &amp;lt;summary&amp;gt;
           /// Initializes a new instance of the Storage class.
           /// &amp;lt;/summary&amp;gt;
           public Storage()
           {
           }
           #region ISerializable Members
           /// &amp;lt;summary&amp;gt;
           /// Initializes a new instance of the &amp;lt;see cref=&amp;quot;Storage&amp;quot;/&amp;gt; class.
           /// &amp;lt;/summary&amp;gt;
           /// &amp;lt;param name=&amp;quot;info&amp;quot;&amp;gt;The info.&amp;lt;/param&amp;gt;
           /// &amp;lt;param name=&amp;quot;context&amp;quot;&amp;gt;The context.&amp;lt;/param&amp;gt;
           protected Storage(SerializationInfo info, StreamingContext context)
           {
               this.items = (SortedList&amp;lt;Guid, StorageItem&amp;gt;)info.GetValue(&amp;quot;items&amp;quot;, typeof(SortedList&amp;lt;Guid, StorageItem&amp;gt;));
           }
           /// &amp;lt;summary&amp;gt;
           /// Populates a &amp;lt;see cref=&amp;quot;T:System.Runtime.Serialization.SerializationInfo&amp;quot;&amp;gt;&amp;lt;/see&amp;gt; with the data needed to serialize the target object.
           /// &amp;lt;/summary&amp;gt;
           /// &amp;lt;param name=&amp;quot;info&amp;quot;&amp;gt;The &amp;lt;see cref=&amp;quot;T:System.Runtime.Serialization.SerializationInfo&amp;quot;&amp;gt;&amp;lt;/see&amp;gt; to populate with data.&amp;lt;/param&amp;gt;
           /// &amp;lt;param name=&amp;quot;context&amp;quot;&amp;gt;The destination (see &amp;lt;see cref=&amp;quot;T:System.Runtime.Serialization.StreamingContext&amp;quot;&amp;gt;&amp;lt;/see&amp;gt;) for this serialization.&amp;lt;/param&amp;gt;
           /// &amp;lt;exception cref=&amp;quot;T:System.Security.SecurityException&amp;quot;&amp;gt;The caller does not have the required permission. &amp;lt;/exception&amp;gt;
           void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
           {
               info.AddValue(&amp;quot;items&amp;quot;, this.items);
           }
           #endregion
           internal void WriteInstanceData(Guid instanceId, byte[] data)
           {
               StorageItem item;
               if (!this.items.TryGetValue(instanceId, out item))
               {
                   item = new StorageItem();
                   this.items.Add(instanceId, item);
                   item.InstanceId = instanceId;
               }
               item.Data = data;
           }
           internal byte [] LoadInstanceData(Guid instanceId)
           {
               StorageItem item;
               if (this.items.TryGetValue(instanceId, out item))
                   return item.Data;
               return null;
           }
           internal void DeleteInstance(Guid instanceId)
           {
               if (this.items.ContainsKey(instanceId))
                   this.items.Remove(instanceId);
           }
           [Serializable]
           private class StorageItem
           {
               public Guid InstanceId;
               public byte [] Data;
           }
       }
   }&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;Feel free to share it with the community.&lt;/p&gt;
&lt;p&gt;Joern&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1278853" width="1" height="1"&gt;</description></item><item><title>Bug Found On The Page Flow Without Database Improvement - Paulo Morgado</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1276943</link><pubDate>Thu, 01 Nov 2007 19:16:35 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1276943</guid><dc:creator>Bug Found On The Page Flow Without Database Improvement - Paulo Morgado</dc:creator><description>&lt;p&gt;Pingback from &amp;nbsp;Bug Found On The Page Flow Without Database Improvement - Paulo Morgado&lt;/p&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1276943" width="1" height="1"&gt;</description></item><item><title>re: Improving The Page Flow Application Block: Removing Database Dependencies</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1274874</link><pubDate>Wed, 31 Oct 2007 01:03:27 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1274874</guid><dc:creator>Paulo Morgado</dc:creator><description>&lt;p&gt;Thanks Joern,&lt;/p&gt;
&lt;p&gt;You're absolutely right about the code. I don't know what I was thinking of when I wrote that.&lt;/p&gt;
&lt;p&gt;(By the way, I think it now works with any session state storage, but I haven't tested it.)&lt;/p&gt;
&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1274874" width="1" height="1"&gt;</description></item><item><title>re: Improving The Page Flow Application Block: Removing Database Dependencies</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1274683</link><pubDate>Tue, 30 Oct 2007 20:03:54 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1274683</guid><dc:creator>Joern</dc:creator><description>&lt;p&gt;Thanks for the code!!!&lt;/p&gt;
&lt;p&gt;I believe I found a bug:&lt;/p&gt;&lt;pre style="OVERFLOW:auto;"&gt;private Storage PageFlowStorage
   {
       get
       {
           if (this.pageFlowStorage == null)
           {
               this.pageFlowStorage = HttpContext.Current.Session[this.pageFlowStorageName] as Storage;
               if (this.pageFlowStorage == null)
               {
                   HttpContext.Current.Session[this.pageFlowStorageName] = this.pageFlowStorage = new Storage();
               }
           }
           return this.pageFlowStorage;
       }
   }&lt;/pre&gt;
&lt;p&gt;With this implementation the pageFlowStorage is cached by the PageFlowInstanceCorrelationAspNetSessionStateProvider class. I have not tested it but I believe that there is only one instance of the class per ASP.NET application. Therefore, with this implementation the storage really is tied to the class instance and not the Session object.&lt;/p&gt;
&lt;p&gt;I would implement:&lt;/p&gt;&lt;pre style="OVERFLOW:auto;"&gt;private Storage PageFlowStorage
   {
       get
       {
           Storage s = HttpContext.Current.Session[this.pageFlowStorageName] as Storage;
           if (s == null)
           {
                   HttpContext.Current.Session[this.pageFlowStorageName] = s = new Storage();
           }
           return s;
       }
   }&lt;/pre&gt;
&lt;p&gt;Your implementation works because the provider probably goes out of scope, when the Application unloads. But I guess that is not what you intended. (By the way, caching it on the provider level probably won&amp;#39;t work neither if the Session is stored in a database.)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1274683" width="1" height="1"&gt;</description></item><item><title>Improving The Page Flow Application Block: Removing Database Dependencies</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1264345</link><pubDate>Thu, 25 Oct 2007 23:00:38 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1264345</guid><dc:creator>Paulo Morgado</dc:creator><description>&lt;p&gt;In this first article of the series I&amp;#39;ll show how you can use the Page Flow Application Block of&lt;/p&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1264345" width="1" height="1"&gt;</description></item><item><title>Improving The Page Flow Application Block - Paulo Morgado</title><link>http://msmvps.com/blogs/paulomorgado/pages/improving-the-page-flow-application-block-removing-database-dependencies.aspx#1255721</link><pubDate>Sun, 21 Oct 2007 18:39:55 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1255721</guid><dc:creator>Improving The Page Flow Application Block - Paulo Morgado</dc:creator><description>&lt;p&gt;Pingback from &amp;nbsp;Improving The Page Flow Application Block - Paulo Morgado&lt;/p&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1255721" width="1" height="1"&gt;</description></item></channel></rss>