English 中文(简体)
Sharing asp.net resource files between web applications
原标题:

I have multiple projects that need to share resource files (.resx) Suggestions have been made to move resource files to a separate assembly and have web projects reference it. Is there an example of how to do this?

Do I create a new Class Library project and move App_GlobalResource folder inside of that? I don t think that will work because code classes that are generated for resource files are marked as internal which means that they can not be accessed outside of this assembly.

最佳回答

In the properties window of Visual Studio, you should be able to set the access modifier of the resource file to public. You won t, however, be able to access the resources in aspx files using the normal <%$ Resources:... %> syntax, since it does not support resources in referenced assemblies. I had the same problem and solved it by implementing a custom ExpressionBuilder, but I don t have access to my source code at the moment. If it s still needed then, I can look up the code tonight.


EDIT: OK, here s how I solved that problem:

Step 1: Move the resx files into the class library. They do not need to be in a specific folder. In the visual designer of the resx file, set the "Access Modifier" (upper right-hand corner) to "Public"

You should now be able to

  • reference the resources in C#/VB code (in the library as well as in the web project), e.g., Dim myMessage As String = [Namespace.]Resources.NameOfResx.NameOfResource

  • reference the resource as inline code in aspx pages, e.g., <h1><%= [Namespace.]Resources.NameOfResx.MyTitle %></h1>.

What won t work at this point is to use Resources expression, e.g., <asp:Button runat="server" Text="<%$ Resources:NameOfResx,MyButtonText %>" />. Unfortunately, you cannot simply replace this with inline code, since it s inside the property of a server side control.

Step 2: Let s make a custom ExpressionBuilder in our library, which interprets arbitrary code expressions. Fortunately, we can let the powerful classes of the .net Framework do all the work for us:

Imports System.Web.Compilation
Imports System.Resources
Imports System.CodeDom

<ExpressionPrefix("Code")> _
Public Class CodeExpressionBuilder
    Inherits ExpressionBuilder

    Public Overrides Function GetCodeExpression(ByVal entry As System.Web.UI.BoundPropertyEntry, ByVal parsedData As Object, ByVal context As System.Web.Compilation.ExpressionBuilderContext) As System.CodeDom.CodeExpression
        Return New CodeSnippetExpression(entry.Expression)
    End Function
End Class

Then we need to register this ExpressionBuilder in the web.config:

<system.web>
  ...
  <compilation ...>
    <expressionBuilders>
      <add expressionPrefix="Code" type="NamespaceOfYourLibrary.CodeExpressionBuilder" />
    </expressionBuilders>
  </compilation>
</system.web>

Now you should be able to do the following:

<asp:Button runat="server" Text="<%$ Code:[Namespace.]Resources.NameOfResx.MyButtonText %>" />

Credit: I got the idea for the CodeExpressionBuilder from the Infinites Loop blog. If you re more into C# than VB, you can have a look at the code examples there.

问题回答

We had a already developed application where we had to have 2 copies of all the resource files, one for services and one for the asp.net project, also the project relied on the <%$ Resources:NameOfResx,MyButtonText %> syntax, so changing syntax was no option.

After some time i found the ExpressionBuilder and came up with the following solution:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Web.Compilation;
using System.Resources;
using System.CodeDom;
using System.Reflection;

/// <summary>
/// This class allows asp.net Resource lookups to different assembly
/// </summary>
[ExpressionPrefix("Resources")]
public class ResourceExpressionBuilder : ExpressionBuilder
{
    static readonly Dictionary<string, ResourceManager> mResourceManagers = new Dictionary<string, ResourceManager>(StringComparer.OrdinalIgnoreCase);
    static ResourceExpressionBuilder()
    {
        Assembly resourceAssembly = Assembly.GetAssembly(typeof(OneTypeInResourceAssembly));
        const string suffix = ".resources";
        string assemblyName = resourceAssembly.GetName().Name;
        foreach (string resource in resourceAssembly.GetManifestResourceNames()) {
            if ((resource.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))) {
                string resourceName = resource.Substring(0, resource.Length - suffix.Length);
                string resourceFriendlyName = resourceName.Substring(assemblyName.Length + 1, resourceName.Length - (assemblyName.Length + 1));
                mResourceManagers.Add(resourceFriendlyName, new ResourceManager(resourceName, resourceAssembly));
            }
        }
    }

    /// <summary>
    /// When overridden in a derived class, returns a value indicating whether the current <see cref="T:System.Web.Compilation.ExpressionBuilder" /> object supports no-compile pages.
    /// </summary>
    /// <returns>true if the <see cref="T:System.Web.Compilation.ExpressionBuilder" /> supports expression evaluation; otherwise, false.</returns>
    public override bool SupportsEvaluate {
        get { return true; }
    }

    /// <summary>
    /// When overridden in a derived class, returns an object that represents an evaluated expression.
    /// </summary>
    /// <param name="target">The object containing the expression.</param>
    /// <param name="entry">The object that represents information about the property bound to by the expression.</param>
    /// <param name="parsedData">The object containing parsed data as returned by <see cref="M:System.Web.Compilation.ExpressionBuilder.ParseExpression(System.String,System.Type,System.Web.Compilation.ExpressionBuilderContext)" />.</param>
    /// <param name="context">Contextual information for the evaluation of the expression.</param>
    /// <returns>
    /// An object that represents the evaluated expression; otherwise, null if the inheritor does not implement <see cref="M:System.Web.Compilation.ExpressionBuilder.EvaluateExpression(System.Object,System.Web.UI.BoundPropertyEntry,System.Object,System.Web.Compilation.ExpressionBuilderContext)" />.
    /// </returns>
    public override object EvaluateExpression(object target, System.Web.UI.BoundPropertyEntry entry, object parsedData, System.Web.Compilation.ExpressionBuilderContext context)
    {
        if ((parsedData != null && object.ReferenceEquals(parsedData.GetType(), typeof(string)))) {
            return GetRequestedValue(Convert.ToString(parsedData));
        }
        return base.EvaluateExpression(target, entry, parsedData, context);
    }

    /// <summary>
    /// When overridden in a derived class, returns code that is used during page execution to obtain the evaluated expression.
    /// </summary>
    /// <param name="entry">The object that represents information about the property bound to by the expression.</param>
    /// <param name="parsedData">The object containing parsed data as returned by <see cref="M:System.Web.Compilation.ExpressionBuilder.ParseExpression(System.String,System.Type,System.Web.Compilation.ExpressionBuilderContext)" />.</param>
    /// <param name="context">Contextual information for the evaluation of the expression.</param>
    /// <returns>
    /// A <see cref="T:System.CodeDom.CodeExpression" /> that is used for property assignment.
    /// </returns>
    public override System.CodeDom.CodeExpression GetCodeExpression(System.Web.UI.BoundPropertyEntry entry, object parsedData, System.Web.Compilation.ExpressionBuilderContext context)
    {
        CodeExpression[] inputParams = new CodeExpression[] { new CodePrimitiveExpression(entry.Expression.Trim()) };
        return new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(this.GetType()), "GetRequestedValue", inputParams);
    }


    /// <summary>
    /// Gets the requested value.
    /// </summary>
    /// <param name="expression">The expression.</param>
    /// <returns></returns>
    public static object GetRequestedValue(string expression)
    {
        string[] parts = expression.Split(new char[] {  ,  }, 2, StringSplitOptions.None);
        if ((parts.Length != 2)) {
            throw new ArgumentException("Expression must contain ,");
        }
        string resourceFile = parts[0].Trim();
        string resourceName = parts[1].Trim();
        return mResourceManagers[resourceFile].GetString(resourceName);
    }
}

Replace OneTypeInResourceAssembly with a type in the assembly containing the resources.

After that you can just add the following to web.config and it should just work..

<system.web>
  <compilation>
    <expressionBuilders>
      <remove expressionPrefix="Resources" />
      <add expressionPrefix="Resources" type="Assembly.ResourceExpressionBuilder" />
    </expressionBuilders>
  </compilation>
</system.web>




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

How to Add script codes before the </body> tag ASP.NET

Heres the problem, In Masterpage, the google analytics code were pasted before the end of body tag. In ASPX page, I need to generate a script (google addItem tracker) using codebehind ClientScript ...

Transaction handling with TransactionScope

I am implementing Transaction using TransactionScope with the help this MSDN article http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx I just want to confirm that is ...

System.Web.Mvc.Controller Initialize

i have the following base controller... public class BaseController : Controller { protected override void Initialize(System.Web.Routing.RequestContext requestContext) { if (...

Microsoft.Contracts namespace

For what it is necessary Microsoft.Contracts namespace in asp.net? I mean, in what cases I could write using Microsoft.Contracts;?

Separator line in ASP.NET

I d like to add a simple separator line in an aspx web form. Does anyone know how? It sounds easy enough, but still I can t manage to find how to do it.. 10x!

热门标签