// Brandon Haynes - http://brandonhaynes.org
// Copyright (c) 2008
// by Brandon Haynes
// Please refer to the project license, located at http://www.codeplex.com/DNNLocalization/license
// The above copyright notice and this permission notice shall be included in all copies or substantial portions
// of the Software.
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
//INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
//SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
//WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
//USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Resources;
using System.Resources.Tools;
using System.Security.Permissions;
using System.Web.Compilation;
using System.Xml;
using System.Xml.Schema;
namespace BrandonHaynes.DotNetNukeResXBuildProvider
{
public abstract class BaseResourcesBuildProvider : BuildProvider
{
#region Protected Properties
protected bool GenerateStronglyTypedClasses { get; set; }
protected ResourcePathMetadata Resource { get; set; }
#endregion
#region Constructors
protected BaseResourcesBuildProvider()
{ GenerateStronglyTypedClasses = true; }
#endregion
#region Abstract Members
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected abstract IResourceReader GetResourceReader(Stream inputStream);
#endregion
#region Public Methods
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public override void GenerateCode(AssemblyBuilder assemblyBuilder)
{
#region Modification for Gallery Server Pro
// BEGIN: Code Addition by Roger Martin, 2010-08-31
// The following can be used to process all .resx files in App_GlobalResources, but this causes issues when language packs are installed.
//if (!VirtualPath.Contains("App_GlobalResources"))
// return;
if (!VirtualPath.EndsWith("GalleryServerPro.resx"))
return;
// END: Code Addition by Roger Martin, 2010-08-31
// Problem: This original build provider by Brandon Haynes processes all .resx files in an application. However, some modules
// (such as Ultra Media Gallery 6.5.2) produce an error when this code processes its local resource files (e.g. for a
// particular user control).
// Solution: Modify this function to process only the GalleryServerPro.resx file. This may be problematic if other
// module developers are using this build provider to process their own .resx files. However, when I change the code to process all
// .resx files in App_GlobalResource, the following error occurs when a language pack is installed:
// "The namespace 'Resources' already contains a definition for 'GlobalResources'"
// Error that occurs when the above code is not included:
// DotNetNuke.Services.Exceptions.ModuleLoadException: An item with the same key has already been added. --->
// System.Web.HttpParseException: An item with the same key has already been added. --->
// System.ArgumentException: An item with the same key has already been added. at
// BrandonHaynes.DotNetNukeResXBuildProvider.BaseResourcesBuildProvider.GenerateCode(AssemblyBuilder assemblyBuilder) in
// C:\Documents and Settings\Brandon.DELL\My Documents\My Projects\BrandonHaynes\DotNetNuke ASP.NET Localization BuildProvider\BuildProvider\BaseResourcesBuildProvider.cs:line 70
// at System.Web.Compilation.AssemblyBuilder.AddBuildProvider(BuildProvider buildProvider)
// --- End of inner exception stack trace --- at System.Web.Compilation.AssemblyBuilder.AddBuildProvider(BuildProvider buildProvider) at
// System.Web.Compilation.BuildProvidersCompiler.ProcessBuildProviders() at System.Web.Compilation.BuildProvidersCompiler.PerformBuild() at
// System.Web.Compilation.CodeDirectoryCompiler.GetCodeDirectoryAssembly(VirtualPath virtualDir, CodeDirectoryType dirType, String assemblyName,
// StringSet excludedSubdirectories, Boolean isDirectoryAllowed) at System.Web.Compilation.BuildManager.CompileCodeDirectory(VirtualPath virtualDir,
// CodeDirectoryType dirType, String assemblyName, StringSet excludedSubdirectories) at System.Web.Compilation.BuildManager.EnsureFirstTimeDirectoryInit(VirtualPath
// virtualDir) at System.Web.Compilation.BuildManager.GetBuildResultFromCacheInternal(String cacheKey, Boolean keyFromVPP, VirtualPath virtualPath,
// Int64 hashCode, Boolean ensureIsUpToDate) at System.Web.Compilation.BuildManager.GetVPathBuildResultFromCacheInternal(VirtualPath virtualPath,
// Boolean ensureIsUpToDate) at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean
// allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate) at
// System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean
// allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate) at
// System.Web.Compilation.BuildManager.GetVPathBuildResult(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp,
// Boolean allowBuildInPrecompile, Boolean ensureIsUpToDate) at System.Web.UI.TemplateControl.LoadControl(VirtualPath virtualPath) at
// DotNetNuke.UI.ControlUtilities.LoadControl[T](TemplateControl containerControl, String ControlSrc) in
// D:\Development\DNN\Library\UI\ControlUtilities.vb:line 61 at DotNetNuke.UI.Modules.ModuleHost.LoadModuleControl() in
// D:\Development\DNN\Library\UI\Modules\ModuleHost.vb:line 229 --- End of inner exception stack trace ---
#endregion
Resource = new ResourcePathMetadata(VirtualPath);
using (Stream stream = base.OpenStream())
{
var resourceReader = this.GetResourceReader(stream);
try
{
GenerateResourceFile(assemblyBuilder, resourceReader);
}
catch (ArgumentException exception)
{
throw DereferenceException(exception);
}
if (Resource.Culture.Equals(CultureInfo.InvariantCulture) && !Resource.IsLocal && GenerateStronglyTypedClasses)
GenerateStronglyTypedClass(assemblyBuilder, resourceReader);
}
}
#endregion
#region Private Methods
private void GenerateResourceFile(AssemblyBuilder assemblyBuilder, IResourceReader reader)
{
using (var stream = assemblyBuilder.CreateEmbeddedResource(this, Resource.EmbeddedName))
using (var writer = new ResourceWriter(stream))
foreach (DictionaryEntry entry in reader)
writer.AddResource(entry.Key.ToString(), entry.Value);
}
private void GenerateStronglyTypedClass(AssemblyBuilder assemblyBuilder, IResourceReader reader)
{
IDictionary resourceList;
string[] unmatchableElements;
using (reader)
resourceList = GetResourceList(reader);
var code = StronglyTypedResourceBuilder.Create(resourceList, Resource.TypeName, Resource.Namespace, assemblyBuilder.CodeDomProvider, false, out unmatchableElements);
assemblyBuilder.AddCodeCompileUnit(this, code.Adapt(Resource));
}
private static IDictionary GetResourceList(IResourceReader reader)
{
return reader
.Cast<DictionaryEntry>()
.ToDictionary(entry => entry.Key, entry => entry.Value);
}
private static Exception DereferenceException(Exception exception)
{
if (exception.InnerException == null || (!(exception.InnerException is XmlException) && !(exception.InnerException is XmlSchemaException)))
return exception;
return exception.InnerException;
}
#endregion
}
}