{"id":7,"date":"2008-07-22T10:14:00","date_gmt":"2008-07-22T14:14:00","guid":{"rendered":"http:\/\/everysport.net\/GamePlan3\/Default.aspx?tabid=489&amp;EntryID=11"},"modified":"2008-10-17T12:10:57","modified_gmt":"2008-10-17T16:10:57","slug":"configuring-custom-inavigationservice-in-wcsf-contrib-library-updated","status":"publish","type":"post","link":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/2008\/07\/22\/configuring-custom-inavigationservice-in-wcsf-contrib-library-updated\/","title":{"rendered":"Configuring custom INavigationService in WCSF Contrib library (Updated)"},"content":{"rendered":"<p>I <a href=\"http:\/\/blogs.law.harvard.edu\/brandonhaynes\/2008\/02\/17\/configuring-custom-inavigationservice-in-wcsf-library\/\"><span style=\"color: #669966\">recently wrote<\/span><\/a> about implementing a custom PageFlow navigation provider in the WCSF library.\u00a0 Since then, the patterns team has broken out the PageFlow block into a separate package (formally the &#8220;<a href=\"http:\/\/www.codeplex.com\/wcsfcontrib\"><span style=\"color: #669966\">Patterns &amp; Practices: Web Client Software Factory Contrib<\/span><\/a>&#8220;).<\/p>\n<p>Since my existing PageFlow navigation provider-related modifications became obsolete with this change, I thought I&#8217;d spend a few minutes porting my changes to the new block.\u00a0 I actually completed this task a couple of months ago, but have just now found the time to post it publicly.\u00a0 Thanks to those who persevered in prodding me to put it online!<\/p>\n<p><!--more--><\/p>\n<h3>WCSF Changes<\/h3>\n<p>The web.config setting is identical to the original setting, marked up as:<\/p>\n<pre><span class=\"kwrd\">&lt;<\/span><span class=\"html\">pageFlowProvider<\/span> <span class=\"attr\">providerType<\/span><span class=\"kwrd\">=\"WCSFContrib.PageFlow.Xml.XmlPageFlowProvider, WCSFContrib.PageFlow.Xml\"<\/span> <span class=\"attr\">navigationType<\/span><span class=\"kwrd\">=\"<strong>[Fully Qualified Assembly Name]<\/strong>\"<\/span> <span class=\"kwrd\">\/&gt;<\/span><\/pre>\n<pre>This change is picked up through an addition to Configuration\/PageFlowProviderSection.cs, as:<\/pre>\n<pre>        <span class=\"rem\">\/\/\/ &lt;summary&gt;<\/span>\r\n        <span class=\"rem\">\/\/\/ Defines the concrete type of the INavigator.<\/span>\r\n        <span class=\"rem\">\/\/\/ &lt;\/summary&gt;<\/span>\r\n        [ConfigurationProperty(<span class=\"str\">\"navigationType\"<\/span>, DefaultValue = <span class=\"str\">\"WCSFContrib.PageFlow.Services.NavigationService\"<\/span>, IsRequired = <span class=\"kwrd\">false<\/span>)]\r\n        <span class=\"kwrd\">public<\/span> <span class=\"kwrd\">string<\/span> NavigationType\r\n            {\r\n            get { <span class=\"kwrd\">return<\/span> (<span class=\"kwrd\">string<\/span>)<span class=\"kwrd\">base<\/span>[<span class=\"str\">\"navigationType\"<\/span>]; }\r\n            }<\/pre>\n<p>\u00a0<\/p>\n<p>Next, the BuildProvider method of PageFlowDirectory (PageFlowDirectory.cs) must be augmented to pick up the specified provider and load it (changes in bold):<\/p>\n<pre>        <span class=\"kwrd\">private<\/span> <span class=\"kwrd\">static<\/span> IPageFlowProvider BuildProvider()\r\n        {\r\n            PageFlowProviderSection configSection =\r\n                (PageFlowProviderSection) ConfigurationManager.GetSection(<span class=\"str\">\"pageFlow\/pageFlowProvider\"<\/span>);\r\n            PageFlowInstanceStoreProviderSection storeSection =\r\n                (PageFlowInstanceStoreProviderSection) ConfigurationManager.GetSection(<span class=\"str\">\"pageFlow\/pageFlowInstanceStoreProvider\"<\/span>);\r\n            PageFlowInstanceCorrelationTokenProviderSection tokenProviderSection =\r\n                (PageFlowInstanceCorrelationTokenProviderSection)ConfigurationManager.GetSection(<span class=\"str\">\"pageFlow\/pageFlowInstanceCorrelationTokenProvider\"<\/span>);\r\n            Type providerType = Type.GetType(configSection.ProviderType);\r\n<strong>            Type navigationType = Type.GetType(configSection.NavigationType);\r\n<\/strong>\r\n<strong>            <span class=\"kwrd\">if<\/span> (navigationType == <span class=\"kwrd\">null<\/span>)\r\n                <span class=\"kwrd\">throw<\/span> <span class=\"kwrd\">new<\/span> InvalidOperationException(<span class=\"str\">\"Invalid navigationType specified: \"<\/span> + configSection.NavigationType);\r\n\r\n            Services.INavigationService navigationService = (Services.INavigationService)Activator.CreateInstance(navigationType);\r\n<\/strong>            _provider = (IPageFlowProvider)Activator.CreateInstance(providerType,\r\n                                                                    BindingFlags.CreateInstance,\r\n                                                                    <span class=\"kwrd\">null<\/span>,\r\n<strong>                                                                    <span class=\"kwrd\">new<\/span> <span class=\"kwrd\">object<\/span>[] { navigationService, storeSection, tokenProviderSection },\r\n<\/strong>                                                                    CultureInfo.CurrentCulture);\r\n            <span class=\"kwrd\">return<\/span> _provider;\r\n        }<\/pre>\n<p>Finally, each concrete provider must be modified to accept the appropriate navigationService as a constructor parameter. In the case of the XmlPageFlowProvider, this would result in the following changes (highlighted in bold):<\/p>\n<pre>        <span class=\"kwrd\">public<\/span> XmlPageFlowProvider(INavigationService navigationService, ...)\r\n        {\r\n            <span class=\"kwrd\">if<\/span> (pageFlowInstanceStoreProviderSection == <span class=\"kwrd\">null<\/span>)\r\n                <span class=\"kwrd\">throw<\/span> <span class=\"kwrd\">new<\/span> ArgumentNullException(<span class=\"str\">\"pageFlowInstanceStoreProviderSection\"<\/span>);\r\n\r\n            <span class=\"kwrd\">if<\/span> (pageFlowCorrelationTokenProviderSection == <span class=\"kwrd\">null<\/span>)\r\n                <span class=\"kwrd\">throw<\/span> <span class=\"kwrd\">new<\/span> ArgumentNullException(<span class=\"str\">\"pageFlowCorrelationTokenProviderSection\"<\/span>);\r\n\r\n            IDictionary&lt;<span class=\"kwrd\">string<\/span>, NavigationGraph&gt; navigationGraphs = <span class=\"kwrd\">new<\/span> WebConfigStore().GetXmlPageFlowNavigationGraphs();\r\n\r\n<strong>            _pageFlowFactory = <span class=\"kwrd\">new<\/span> XmlPageFlowFactory(navigationGraphs, navigationService);\r\n  <\/strong>          <span class=\"rem\">\/\/_pageFlowFactory = new XmlPageFlowFactory(navigationGraphs, new NavigationService());<\/span>\r\n\r\n            Type tokenProviderType = Type.GetType(pageFlowCorrelationTokenProviderSection.ProviderType, <span class=\"kwrd\">true<\/span>, <span class=\"kwrd\">true<\/span>);\r\n            IPageFlowCorrelationTokenProvider _tokenProvider =\r\n                (IPageFlowCorrelationTokenProvider)Activator.CreateInstance(tokenProviderType);\r\n\r\n            Type storeType = Type.GetType(pageFlowInstanceStoreProviderSection.ProviderType, <span class=\"kwrd\">true<\/span>, <span class=\"kwrd\">true<\/span>);\r\n            _store =\r\n                (IPageFlowInstanceStore)Activator.CreateInstance(storeType, BindingFlags.CreateInstance, <span class=\"kwrd\">null<\/span>,\r\n                                                                  <span class=\"kwrd\">new<\/span> <span class=\"kwrd\">object<\/span>[]\r\n                                                                      {\r\n                                                                          pageFlowInstanceStoreProviderSection.ConnectionStringName,\r\n                                                                        _tokenProvider\r\n                                                                      },\r\n                                                                  CultureInfo.CurrentCulture);\r\n            PopulateDirectory(navigationGraphs);\r\n         }<\/pre>\n<p>As a footnote, I did consider modifying the NavigationService directly to instantiate and decorate an underlying custom NavigationProvider. While this might have resulted in one less code change, I do not feel that it is of optimal design. Concrete PageFlow providers should not be responsible for instantiation of their navigationProviders; these objects should be injected, for maximum flexibility.\u00a0<\/p>\n<h3>Downloads<\/h3>\n<ul>\n<li><a href=\"http:\/\/brandonhaynes.org\/Downloads\/WCSFContrib.PageFlow.zip\">WCSFContrib.PageFlow.DLL and WCSFContrib.PageFlow.Xml.DLL <\/a><\/li>\n<li><a href=\"http:\/\/brandonhaynes.org\/Downloads\/PageFlowSourceModifications.zip\">WCSFContrib.PageFlow and WCSFContrib.PageFlow.Xml Source<\/a>\u00a0(Modified files only!)<\/li>\n<\/ul>\n<p>For the complete (pre-modification) package, visit the project homepage at <a title=\"http:\/\/www.codeplex.com\/wcsfcontrib\" href=\"http:\/\/www.codeplex.com\/wcsfcontrib\"><span style=\"color: #669966\">http:\/\/www.codeplex.com\/wcsfcontrib<\/span><\/a>.\u00a0 For those keeping score, I&#8217;ve created a work item for this change here.<\/p>\n<h3>Coming Soon: Using the PageFlow Application Block within DotNetNuke<\/h3>\n<p>The WCSF PageFlow package continues to be an excellent application block.\u00a0 It is a shame that it continues to be so ASPX-centric.\u00a0 The modifications herein are a first step toward removing this limitation and allowing it to be used in more flexible circumstances, such as an ASCX-based state machine or within the DNN framework.<\/p>\n<p>For anyone who is interested, I am now using this application block successfully (soon to be in production) within the DotNetNuke framework, using:<\/p>\n<ul>\n<li>The block-level modifications outlined above<\/li>\n<li>A custom navigation service (currently SelfRedirectingNavigationService, though, as I will blog about sometime soon, I have some enhancements in store in this area)<\/li>\n<li>A web.config-defined XmlPageFlow provider state machine<\/li>\n<li>A module shell with some custom wire-up code<\/li>\n<li>One ASCX control for each state in the XmlPageFlow state machine<\/li>\n<\/ul>\n<p>I will continue to blog about this topic, most likely addressing a concrete navigation service that may be used with DNN next.\u00a0 Stay tuned!<\/p>\n<p>B<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I recently wrote about implementing a custom PageFlow navigation provider in the WCSF library.\u00a0 Since then, the patterns team has broken out the PageFlow block into a separate package (formally the &#8220;Patterns &amp; Practices: Web Client Software Factory Contrib&#8220;). Since my existing PageFlow navigation provider-related modifications became obsolete with this change, I thought I&#8217;d spend [&hellip;]<\/p>\n","protected":false},"author":1933,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[142,3067],"tags":[3073,3072],"class_list":["post-7","post","type-post","status-publish","format-standard","hentry","category-technology","category-web-client-software-factory-wcsf","tag-inavigationservice","tag-wcsf"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/posts\/7","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/users\/1933"}],"replies":[{"embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/comments?post=7"}],"version-history":[{"count":0,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/posts\/7\/revisions"}],"wp:attachment":[{"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/media?parent=7"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/categories?post=7"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/tags?post=7"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}