Совместное использование файлов ресурсов asp.net между веб-приложениями - PullRequest
10 голосов
/ 26 января 2010

У меня есть несколько проектов, которым необходимо предоставить общий доступ к файлам ресурсов (.resx). Были сделаны предложения о перемещении файлов ресурсов в отдельную сборку и ссылки на них в веб-проектах. Есть ли пример того, как это сделать?

Создать ли новый проект библиотеки классов и переместить в него папку App_GlobalResource? Я не думаю, что это будет работать, потому что классы кода, сгенерированные для файлов ресурсов, помечены как «внутренние», что означает, что к ним нельзя получить доступ вне этой сборки.

Ответы [ 2 ]

20 голосов
/ 26 января 2010

В окне свойств Visual Studio вы должны установить публичный модификатор доступа к файлу ресурса. Однако вы не сможете получить доступ к ресурсам в файлах aspx, используя обычный синтаксис <%$ Resources:... %>, поскольку он не поддерживает ресурсы в ссылочных сборках. У меня была та же проблема, и я решил ее, реализовав пользовательский ExpressionBuilder, но в данный момент у меня нет доступа к исходному коду. Если это все еще нужно, я могу посмотреть код сегодня вечером.


РЕДАКТИРОВАТЬ: ОК, вот как я решил эту проблему:

Шаг 1 : переместить файлы resx в библиотеку классов. Они не должны быть в определенной папке. В визуальном конструкторе файла resx установите «Модификатор доступа» (в верхнем правом углу) на «Public»

Теперь вы должны быть в состоянии

  • ссылки на ресурсы в C # / VB код (в библиотеке и в веб-проекте), например, 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 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

Затем нам нужно зарегистрировать этот ExpressionBuilder в web.config:

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

Теперь вы должны быть в состоянии сделать следующее:

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

Кредит: я получил идею CodeExpressionBuilder из блога Infinites Loop . Если вы больше разбираетесь в C #, чем в VB, вы можете взглянуть на примеры кода там.

7 голосов
/ 13 октября 2014

У нас уже было разработанное приложение, в котором мы должны были иметь 2 копии всех файлов ресурсов, одну для служб и одну для проекта asp.net, также проект опирался на синтаксис <%$ Resources:NameOfResx,MyButtonText %>, поэтому изменение синтаксиса опция.

Через некоторое время я нашел 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>
...