2010-01-26 10 views
9

Mam wiele projektów, które muszą udostępniać pliki zasobów (.resx) Podano sugestie dotyczące przenoszenia plików zasobów do osobnego zespołu i odniesienia do projektów internetowych. Czy istnieje przykład tego, jak to zrobić?Udostępnianie plików zasobów asp.net między aplikacjami WWW

Czy mogę utworzyć nowy projekt biblioteki klas i przenieść w tym folderze App_GlobalResource? Nie sądzę, że to zadziała, ponieważ klasy kodu generowane dla plików zasobów są oznaczone jako "wewnętrzne", co oznacza, że ​​nie można uzyskać do nich dostępu poza tym złożeniem.

Odpowiedz

17

W oknie właściwości programu Visual Studio powinieneś mieć możliwość ustawienia modyfikatora dostępu pliku zasobów na publiczny. Nie będzie jednak można uzyskać dostępu do zasobów w plikach aspx przy użyciu normalnej składni <%$ Resources:... %>, ponieważ nie obsługuje zasobów w zestawach referencyjnych. Miałem ten sam problem i rozwiązałem go, wprowadzając niestandardowy ExpressionBuilder, ale w tej chwili nie mam dostępu do mojego kodu źródłowego. Jeśli nadal będzie to potrzebne, mogę dziś wyszukać kod.


EDIT: OK, oto jak ja rozwiązał ten problem:

Krok 1: Przenieś RESX pliki do biblioteki klas. Nie muszą znajdować się w określonym folderze. W wizualnym projektanta pliku RESX, ustaw „Access modyfikator” (górny prawy narożnik), aby „publiczne”

Teraz powinno być w stanie

  • odniesienia zasobów w C#/kod VB (w bibliotece, a także w projekcie internetowym), np Dim myMessage As String = [Namespace.]Resources.NameOfResx.NameOfResource

  • odniesienia zasób jako kod inline na stronach aspx, np <h1><%= [Namespace.]Resources.NameOfResx.MyTitle %></h1>.

Co nie praca w tym momencie jest użycie wyrażenia Resources, na przykład <asp:Button runat="server" Text="<%$ Resources:NameOfResx,MyButtonText %>" />. Niestety, nie można po prostu zastąpić tego kodem inline, ponieważ jest on własnością kontrolki po stronie serwera.

Krok 2: Zróbmy niestandardową ExpressionBuilder w naszej bibliotece, który interpretuje dowolnych wyrażeń kodu. Na szczęście możemy pozwolić potężne klas .NET Framework wykonać całą pracę za nas:

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 

Następnie musimy zarejestrować ten ExpressionBuilder w web.config:

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

Teraz powinno być w stanie wykonać następujące czynności:

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

kredytowe: mam pomysł na CodeExpressionBuilder z Infinites Loop blog. Jeśli bardziej interesuje Cię C# niż VB, możesz rzucić okiem na przykłady kodu.

+0

Jest dobrze wiedzieć, że przyzwyczajenie będę mógł zasobów dostępu do plików aspx (jej zdecydowanie wykorzystywane tak). Byłoby miło zobaczyć ten niestandardowy ExpressionBuilder, jeśli możesz go udostępnić. –

+0

@ dev.e.loper: Zaktualizowałem swoją odpowiedź. – Heinzi

+1

@Heinzi: To rozwiązanie nie tworzy oddzielnego zespołu do rozwiązywania zasobów przez kulturę. Otrzymasz wszystkie ciągi dla domyślnej kultury, nawet jeśli tam zdefiniujesz dodatkowy resx dla aktualnej kultury. – Sergio

7

Mamy już opracowaną aplikację, w której musieliśmy mieć 2 kopie wszystkich plików zasobów, jeden dla usług i jeden dla projektu asp.net, a także projekt opierał się na składni <%$ Resources:NameOfResx,MyButtonText %>, więc zmiana składni nie była opcją .

Po pewnym czasie znalazłem ExpressionBuilder i wymyślił następujące rozwiązanie:

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

Wymień OneTypeInResourceAssembly z typem w zespole zawierającym zasobów.

Po tym można tylko dodać następujące web.config i powinien po prostu pracować ..

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

Nice. To działa! – Fanda

Powiązane problemy