【问题标题】:Sharing asp.net resource files between web applications在 Web 应用程序之间共享 asp.net 资源文件
【发布时间】:2010-01-26 16:07:49
【问题描述】:

我有多个项目需要共享资源文件 (.resx) 已建议将资源文件移动到单独的程序集并让 Web 项目引用它。有如何做到这一点的例子吗?

我是否创建一个新的类库项目并将 App_GlobalResource 文件夹移到其中?我认为这不会起作用,因为为资源文件生成的代码类被标记为“内部”,这意味着它们无法在此程序集之外访问。

【问题讨论】:

    标签: asp.net resources resx


    【解决方案1】:

    在 Visual Studio 的属性窗口中,您应该可以将资源文件的访问修饰符设置为 public。但是,您将无法使用普通的 <%$ Resources:... %> 语法访问 aspx 文件中的资源,因为它不支持引用程序集中的资源。我遇到了同样的问题,并通过实现自定义 ExpressionBuilder 解决了它,但我目前无法访问我的源代码。如果还需要的话,我今晚可以查一下代码。


    编辑:好的,这就是我解决这个问题的方法:

    第 1 步:将 resx 文件移动到类库中。它们不需要位于特定文件夹中。在 resx 文件的可视化设计器中,将“Access Modifier”(右上角)设置为“Public”

    你现在应该可以

    • 引用C#/VB 代码中的资源(在库中以及在 Web 项目中),例如,Dim myMessage As String = [Namespace.]Resources.NameOfResx.NameOfResource

    • 在 aspx 页面中将资源引用为内联代码,例如,<h1><%= [Namespace.]Resources.NameOfResx.MyTitle %></h1>

    此时不会起作用的是使用资源表达式,例如<asp:Button runat="server" Text="<%$ Resources:NameOfResx,MyButtonText %>" />。不幸的是,您不能简单地将其替换为内联代码,因为它位于服务器端控件的属性中。

    第 2 步:让我们在我们的库中创建一个自定义的 ExpressionBuilder,它可以解释任意代码表达式。幸运的是,我们可以让 .net 框架的强大类为我们完成所有工作:

    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
    

    那么我们需要在web.config中注册这个ExpressionBuilder:

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

    现在您应该可以执行以下操作了:

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

    致谢:我从Infinites Loop blog 得到了 CodeExpressionBuilder 的想法。如果您更喜欢 C# 而不是 VB,可以查看那里的代码示例。

    【讨论】:

    • 很高兴知道我将无法访问 aspx 文件中的资源(它肯定是这样使用的)。如果您可以分享这个自定义的 ExpressionBuilder,那就太好了。
    • @Heinzi:该解决方案不会通过单独的程序集来按文化解析资源。即使为当前文化定义了额外的 resx,您也将获得默认文化的所有字符串。
    • @Sergio:我们成功地将这种方法用于两种不同的文化。如果它在您的情况下不起作用,则问题可能出在其他地方。
    • @Heinzi:我的错,我忘了部署/复制替代文化目录。另外,有没有办法替换 HttpContext.GetGlobalResourceObject("NameOfResx", MyButtonText) 调用?
    【解决方案2】:

    我们有一个已经开发的应用程序,我们必须拥有所有资源文件的 2 个副本,一个用于服务,一个用于 asp.net 项目,而且该项目依赖于 &lt;%$ Resources:NameOfResx,MyButtonText %&gt; 语法,因此更改语法是没有的选项。

    一段时间后,我找到了 ExpressionBuilder 并提出了以下解决方案:

    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);
        }
    }
    

    OneTypeInResourceAssembly 替换为包含资源的程序集中的类型。

    之后,您可以将以下内容添加到 web.config 中,它应该可以正常工作..

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-15
      • 2013-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-17
      • 1970-01-01
      相关资源
      最近更新 更多