{"id":33,"date":"2008-10-29T10:01:58","date_gmt":"2008-10-29T14:01:58","guid":{"rendered":"http:\/\/blogs.law.harvard.edu\/brandonhaynes\/?p=33"},"modified":"2008-10-29T10:01:58","modified_gmt":"2008-10-29T14:01:58","slug":"a-second-look-enabling-aspnet-20-localization-in-a-dotnetnuke-application-2","status":"publish","type":"post","link":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/2008\/10\/29\/a-second-look-enabling-aspnet-20-localization-in-a-dotnetnuke-application-2\/","title":{"rendered":"A Second Look: Enabling ASP.NET 2.0 Localization in a DotNetNuke Application"},"content":{"rendered":"<p>Some time ago, I\u00a0<a href=\"http:\/\/blogs.law.harvard.edu\/brandonhaynes\/2008\/04\/08\/enabling-aspnet-20-localization-in-a-dotnetnuke-application\/\">wrote<\/a>\u00a0about an approach for enabling ASP.NET 2.0 localization within a DotNetNuke application.\u00a0 This approach not only required a core modification, but the change introduced a potential breaking change with third party modules.\u00a0 This was clearly unsatisfactory, and the fact that I was unable to fully solve the problem has been vexing me for some time.<\/p>\n<p>As my research on the recently-released <a href=\"http:\/\/blogs.law.harvard.edu\/brandonhaynes\/2008\/10\/14\/adapting-the-linq-to-sql-attributed-meta-model-for-use-in-dotnetnuke\/\">Linq to Sql Adapter<\/a>\u00a0(currently hosted on <a href=\"http:\/\/www.codeplex.com\/DNNLinqToSqlAdapter\">CodePlex<\/a>) wound down, I decided to investigate a new approach to solving the problem.\u00a0 In my opinion, an optimal solution would fulfill the following requirements:<\/p>\n<ol>\n<li>Require no core changes<\/li>\n<li>Be side-by-side compatible with the existing DotNetNuke localization services<\/li>\n<li>Require little configuration by a hosting user<\/li>\n<li>Allow strongly-typed per-portal and per-culture access to existing global DotNetNuke resources<\/li>\n<li>Minimal additional in-memory footprint and reasonable performance<\/li>\n<li>Enable use of the meta:resourcekey attribute in DotNetNuke modules<\/li>\n<li>Be fully compatibility with third-party modules<\/li>\n<\/ol>\n<p>I am pleased to announce a preview release of a custom BuildProvider that, to my knowledge, accomplishes all of these goals.<\/p>\n<p><!--more--><\/p>\n<p>For those not familiar with the issue at hand, I strongly recommend reading my <a href=\"http:\/\/blogs.law.harvard.edu\/brandonhaynes\/2008\/04\/08\/enabling-aspnet-20-localization-in-a-dotnetnuke-application\/\">previous entry<\/a>\u00a0for the relevant background information.\u00a0 The remainder of this discourse will assume such familiarity.<\/p>\n<p>The previous approach failed in satisfying two of the more important requirements above (specifically (1) and (7) above).\u00a0 A core change was necessary to\u00a0keep portal-specific localization files out of the App_GlobalResources directory where ASP.NET would choke\u00a0during\u00a0automatic compilation.\u00a0 This core change caused trouble with pre-compiled third-party modules\u00a0because of the compile-time linking of publicly exposed constant values.\u00a0 Clearly unsatisfactory, and clearly a dead-end.<\/p>\n<p>This time around, I elected to utilize a different approach.\u00a0 This revision includes a\u00a0 custom BuildProvider which handles the full compilation life cycle for ResX files; in this manner such files may continue to exist in the App_GlobalResources directory and be fully side-by-side compatible with the DotNetNuke localization system.\u00a0 Further, custom extensions allow portal-specific resource customizations to extend to the ResourceManager (including both strongly- and weakly-typed access).<\/p>\n<p>For example, the strongly-typed variable (enabled via this BuildProvider) Resources.GlobalResources.Error_Text will consistently yield the same value obtained through a DotNetNuke.Services.Localization.Localization.GetString(&#8220;Error&#8221;, Localization.GlobalResourceFile).\u00a0<\/p>\n<p>Similarly, a meta:resourcekey attribute on an appropriately named control will yield the same value obtained through a call to UserModuleBase.GetLocalResourceObject(&#8230;).<\/p>\n<h3>Configuration<\/h3>\n<p>Configuration is straightforward, requiring only a single additional node in the web.config file (highlighted below):<\/p>\n<pre>&lt;buildProviders&gt;<\/pre>\n<pre>&lt;remove extension=\".resx\" \/&gt;<\/pre>\n<pre>  &lt;remove extension=\".resources\" \/&gt;<\/pre>\n<pre>  <strong><span style=\"color: #ff0000\">&lt;add extension=\".resx\" \u00a0\u00a0\u00a0<\/span><\/strong><\/pre>\n<pre><strong><span style=\"color: #ff0000\">type=\"BrandonHaynes.DotNetNukeResXBuildProvider.ResXBuildProvider, <\/span><\/strong><\/pre>\n<pre><strong><span style=\"color: #ff0000\">BrandonHaynes.DotNetNukeResXBuildProvider\" \/&gt; <\/span><\/strong><\/pre>\n<pre>&lt;\/buildProviders&gt;<\/pre>\n<p>Here, we keep the existing DotNetNuke &lt;remove&gt; elements and add the new BuildProvider to the list.\u00a0 During startup, ASP.NET will utilize this BuildProvider to compile all files with the .ResX extension.\u00a0 This BuildProvider will handle strongly-typed class generation, ResourceManager decoration, and enable full ASP.NET localization within the application.\u00a0 That&#8217;s it!<\/p>\n<h3>CodePlex Project<\/h3>\n<p>As I gather feedback on the approach, I am initially releasing the BuildProvider project as a beta release.\u00a0 Please understand that it is preview software, has undergone limited testing, and may break existing installations.\u00a0 Though I am not currently aware of any outstanding issues, please use caution in a production environment.\u00a0 Note that any custom BuildProvider, including this one, requires deployment in a Full Trust environment.<\/p>\n<p>The project is available on CodePlex.\u00a0 <a href=\"http:\/\/www.codeplex.com\/DNNLocalization\">Click here<\/a> to access.\u00a0 Full source is available.<\/p>\n<p>As I work to confirm that this BuildProvider works properly across a wider variety of installations, I would appreciate any and all feedback about the experiences of those using it.\u00a0 It is greatly appreciated.<\/p>\n<p>B<\/p>\n<p><span style=\"font-size: smaller\">* Installation of this module will still require the manual web.config modifications outlined above; at some point I will likely release a 5.0-compatible package that performs this task automatically.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Some time ago, I\u00a0wrote\u00a0about an approach for enabling ASP.NET 2.0 localization within a DotNetNuke application.\u00a0 This approach not only required a core modification, but the change introduced a potential breaking change with third party modules.\u00a0 This was clearly unsatisfactory, and the fact that I was unable to fully solve the problem has been vexing me [&hellip;]<\/p>\n","protected":false},"author":1933,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3062,142],"tags":[3367,3070,3366],"class_list":["post-33","post","type-post","status-publish","format-standard","hentry","category-dotnetnuke-dnn-content-management-system","category-technology","tag-aspnet","tag-dotnetnuke","tag-localization"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/posts\/33","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=33"}],"version-history":[{"count":1,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/posts\/33\/revisions"}],"predecessor-version":[{"id":198,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/posts\/33\/revisions\/198"}],"wp:attachment":[{"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/media?parent=33"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/categories?post=33"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/brandonhaynes\/wp-json\/wp\/v2\/tags?post=33"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}