简体   繁体   English

在Web应用程序之间共享asp.net资源文件

[英]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. 我有多个需要共享资源文件的项目(.resx)已经建议将资源文件移动到单独的程序集并让Web项目引用它。 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? 我是否创建了一个新的类库项目并在其中移动App_GlobalResource文件夹? 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. 在Visual Studio的属性窗口中,您应该能够将资源文件的访问修饰符设置为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. 但是,您不能使用常规<%$ Resources:... %>语法访问aspx文件中的<%$ Resources:... %> ,因为它不支持引用程序集中的资源。 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. 我有同样的问题并通过实现自定义ExpressionBuilder解决了它,但我目前无法访问我的源代码。 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. 第1步 :将resx文件移动到类库中。 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" 在resx文件的可视化设计器中,将“Access Modifier”(右上角)设置为“Public”

You should now be able to 你现在应该能够

  • reference the resources in C#/VB code (in the library as well as in the web project), eg, Dim myMessage As String = [Namespace.]Resources.NameOfResx.NameOfResource 引用C#/ VB代码中的资源(在库中以及在Web项目中),例如, Dim myMessage As String = [Namespace.]Resources.NameOfResx.NameOfResource

  • reference the resource as inline code in aspx pages, eg, <h1><%= [Namespace.]Resources.NameOfResx.MyTitle %></h1> . 将资源引用为aspx页面中的内联代码,例如<h1><%= [Namespace.]Resources.NameOfResx.MyTitle %></h1>

What won't work at this point is to use Resources expression, eg, <asp:Button runat="server" Text="<%$ Resources:NameOfResx,MyButtonText %>" /> . 什么在这一点上行不通的是使用资源的表达,例如, <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. 第2步 :让我们在我们的库中创建一个自定义的ExpressionBuilder,它解释任意代码表达式。 Fortunately, we can let the powerful classes of the .net Framework do all the work for us: 幸运的是,我们可以让强大的.net Framework类为我们完成所有工作:

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: 然后我们需要在web.config中注册这个ExpressionBuilder:

<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 . Credit:我从Infinites Loop博客获得了CodeExpressionBuilder的想法。 If you're more into C# than VB, you can have a look at the code examples there. 如果你比VB更喜欢C#,你可以看看那里的代码示例。

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. 我们有一个已经开发的应用程序,我们必须拥有所有资源文件的2个副本,一个用于服务,一个用于asp.net项目,该项目依赖于<%$ Resources:NameOfResx,MyButtonText %>语法,所以改变语法是没有选择的。

After some time i found the ExpressionBuilder and came up with the following solution: 一段时间后,我找到了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);
    }
}

Replace OneTypeInResourceAssembly with a type in the assembly containing the resources. OneTypeInResourceAssembly替换为包含资源的程序OneTypeInResourceAssembly的类型。

After that you can just add the following to web.config and it should just work.. 之后你可以将以下内容添加到web.config中,它应该正常工作..

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM