2010-01-26 14 views
9

Tengo varios proyectos que necesitan compartir archivos de recursos (.resx) Se han hecho sugerencias para mover los archivos de recursos a un ensamblaje separado y hacer que los proyectos web lo hagan referencia. ¿Hay algún ejemplo de cómo hacer esto?Compartiendo archivos de recursos asp.net entre aplicaciones web

¿Creo un nuevo proyecto de biblioteca de clases y muevo la carpeta App_GlobalResource dentro de eso? No creo que eso funcione porque las clases de código que se generan para los archivos de recursos están marcadas como 'internas', lo que significa que no se puede acceder a ellas fuera de este ensamblaje.

Respuesta

17

En la ventana de propiedades de Visual Studio, debe poder establecer el modificador de acceso del archivo de recursos en público. Sin embargo, no podrá acceder a los recursos en archivos aspx utilizando la sintaxis normal <%$ Resources:... %>, ya que no admite recursos en los ensamblados a los que se hace referencia. Tuve el mismo problema y lo resolví implementando un ExpressionBuilder personalizado, pero no tengo acceso a mi código fuente en este momento. Si todavía es necesario, puedo buscar el código esta noche.


EDIT: OK, aquí está cómo resolví ese problema:

Paso 1: Mover los archivos resx en la biblioteca de clases. No necesitan estar en una carpeta específica. En el diseñador visual de la resx, establecer el "modificador de acceso" (esquina superior derecha) en "Público"

Ahora debería ser capaz de

  • referencia a los recursos en C#/código de VB (en la biblioteca, así como en el proyecto web), por ejemplo, Dim myMessage As String = [Namespace.]Resources.NameOfResx.NameOfResource

  • referencia el recurso como código en línea en las páginas aspx, por ejemplo, <h1><%= [Namespace.]Resources.NameOfResx.MyTitle %></h1>.

Lo que se no trabajo en este momento es el uso de la expresión de los recursos, por ejemplo, <asp:Button runat="server" Text="<%$ Resources:NameOfResx,MyButtonText %>" />. Desafortunadamente, no puede simplemente reemplazar esto con el código en línea, ya que está dentro de la propiedad de un control del lado del servidor.

Paso 2: Hagamos un ExpressionBuilder personalizado en nuestra biblioteca, que interpreta expresiones de código arbitrarias. Afortunadamente, podemos dejar que las clases poderosas del marco .NET hacen todo el trabajo por nosotros:

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 

entonces tenemos que registrar este ExpressionBuilder en el web.config:

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

Ahora usted debe ser capaz de hacer lo siguiente:

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

crédito: me dio la idea para el CodeExpressionBuilder del Infinites Loop blog. Si estás más interesado en C# que en VB, puedes echar un vistazo a los ejemplos de código allí.

+0

Es bueno saber que no voy a ser capaz de acceder a los recursos archivos aspx (su definitivamente ser utilizado como esa) Sería bueno ver este ExpressionBuilder personalizado si puedes compartirlo. –

+0

@ dev.e.loper: He actualizado mi respuesta. – Heinzi

+1

@Heinzi: Esa solución no hace el ensamblaje por separado para resolver los recursos por cultura. Obtendrá todas las cadenas para la cultura predeterminada, incluso si hay una resx adicional definida para la cultura actual. – Sergio

7

Teníamos una aplicación ya desarrollada donde teníamos que tener 2 copias de todos los archivos de recursos, uno para servicios y uno para el proyecto asp.net, también el proyecto dependía de la sintaxis <%$ Resources:NameOfResx,MyButtonText %>, por lo que cambiar la sintaxis no era una opción .

Después de algún tiempo encontré la ExpressionBuilder y se acercó con la siguiente solución:

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

Reemplazar OneTypeInResourceAssembly con un tipo en el montaje que contiene los recursos.

Después de que usted puede simplemente añadir lo siguiente a web.config y que sólo debería funcionar ..

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

Agradable. ¡Esto funciona! – Fanda

Cuestiones relacionadas