11

リソースファイル(.resx)を共有する必要のあるプロジェクトが複数あります。リソースファイルを別のアセンブリに移動し、Webプロジェクトに参照させるように提案されています。これを行う方法の例はありますか?

新しいクラスライブラリプロジェクトを作成し、その中にApp_GlobalResourceフォルダーを移動しますか?リソースファイル用に生成されたコードクラスは「内部」としてマークされているため、これは機能しないと思います。これは、このアセンブリの外部からアクセスできないことを意味します。

4

2 に答える 2

21

Visual Studioのプロパティウィンドウで、リソースファイルのアクセス修飾子をパブリックに設定できるはずです。<%$ Resources:... %>ただし、参照されるアセンブリのリソースをサポートしていないため、通常の構文を使用してaspxファイルのリソースにアクセスすることはできません。同じ問題が発生し、カスタムのExpressionBuilderを実装することで解決しましたが、現時点ではソースコードにアクセスできません。それでも必要な場合は、今夜コードを検索できます。


編集:OK、これが私がその問題を解決した方法です:

ステップ1:resxファイルをクラスライブラリに移動します。特定のフォルダにある必要はありません。resxファイルのビジュアルデザイナで、「AccessModifier」(右上隅)を「Public」に設定します

これで、次のことができるようになります。

  • C#/ VBコード(ライブラリおよびWebプロジェクト)のリソースを参照します。例:Dim myMessage As String = [Namespace.]Resources.NameOfResx.NameOfResource

  • aspxページのインラインコードとしてリソースを参照します。例:<h1><%= [Namespace.]Resources.NameOfResx.MyTitle %></h1>

この時点で機能しないのは、Resources式を使用すること<asp:Button runat="server" Text="<%$ Resources:NameOfResx,MyButtonText %>" />です。残念ながら、これはサーバー側のコントロールのプロパティ内にあるため、単純にインラインコードに置き換えることはできません。

ステップ2:任意のコード式を解釈するカスタムExpressionBuilderをライブラリに作成しましょう。幸い、.netFrameworkの強力なクラスにすべての作業を任せることができます。

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のアイデアは、InfinitesLoopブログから入手しました。VBよりもC#に興味がある場合は、そこでコード例を見ることができます。

于 2010-01-26T16:13:24.057 に答える
9

すでに開発されたアプリケーションがあり、すべてのリソースファイルのコピーが2つ必要でした。1つはサービス用、もう1つは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>
于 2014-10-13T10:56:49.303 に答える