2010-03-29 8 views
5

Quiero sobrescribir una cadena de System.ComponentModel.DataAnnotations para un proyecto ASP.NET. ¿Debo hacer un ensamblaje de satélite, jugando con tareas de compilación personalizadas, al.exe, etc.? Incluso si es así, no pude encontrar cómo convertir .resx en .resources para alimentarlo al al.exe. Y si no, ¿dónde poner el .resx. y cómo nombrarlo?Reemplazar un recurso del ensamblado estándar en ASP.NET

UPD: Para dejarlo en claro: quería usar una cadena de recursos personalizada en lugar de una del recurso predeterminado del ensamblaje. No quería hacer cambios en cada lugar que utiliza esa cadena. Después de todo, los recursos existen solo para anularlos.

Respuesta

2

Si bien esto es extraño, sobre todo para las personas familiarizadas con las tecnologías de localización de código abierto, no se puede construir un ensamblado satélite para cualquier montaje del sistema o incluso un tercio de partido firmado uno:

If your main assembly uses strong naming, satellite assemblies must be signed with the same private key as the main assembly. If the public/private key pair does not match between the main and satellite assemblies, your resources will not be loaded.

Si lo mismo es posible de forma automática, pero sin un conjunto de satélites, se desconoce, aunque lo dudo.

1

Suponiendo que desea reemplazar las cadenas de mensajes de error por defecto en los atributos de validación, que puede hacer que al establecer las ErrorMessageResourceName y los ErrorMessageResourceType propiedades como esta:

[Required(ErrorMessageResourceName = "Required_Username", ErrorMessageResourceType = typeof(MyResourceFile)] 
public string Username { get; set; } 

Se puede crear un archivo de recursos llamada MyResourceFile .resx que contiene Required_Username con el mensaje de error que desea.

Espero que esto ayude.

+0

Lo sé, pero no quiero cambiar todos los atributos. – wRAR

4

Phil Haack tiene un excelente artículo Localizing ASP.Net MVC Validation que le guía específicamente a través anulando sus cadenas. Este artículo se aplica más a DataAnnotations que a ASP.net MVC. Por lo tanto, esto ayudará sin embargo si está utilizando DataAnnotattions.

A continuación, he enumerado los pasos más simples para agregar recursos localizados en Visual Studio.

  1. Abra el diálogo Project Properties.
  2. Seleccione la pestaña Resources.
  3. Haga clic para crear una nueva archivo de recursos predeterminado.
  4. Esto creará dos archivos en su carpeta Properties.
    • Resources.resx
    • Resources.Designer.cs
  5. Cuando Resources.resx ha abierto , cambiar su Access Modifier a Public.
  6. Agregue sus cadenas.

Para añadir archivos de recursos adicionales para culturas específicas que se necesitan para.

  1. Haga clic derecho en su Project en el Solution Explorer.
  2. Seleccionar Añadir -> Nuevo elemento -> Recursos Archivo.
  3. nómbrelo Resources.en-us.resx. (reemplace 'es-es' con el código apropiado )
  4. Haga clic en Agregar
  5. arrastrarlo a la carpeta Properties.
  6. abierto Resources.en-us.resx y cambiar su Access Modifier a Public.
  7. Agregue sus cadenas.
  8. Repita para cada cultura que necesita para soporte.

Durante la acumulación VS convertirá el Resx archivos a .resource archivos y crear clases contenedoras para usted. A continuación, puede acceder a través del espacio de nombres YourAssembly.Properties.Resources.

Con esta declaración de uso.

using YourAssembly.Properties; 

Se puede decorar con atributos como esto:

[Required(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = "MyStringName")] 

Nota: He utilizado el Propiedades de carpetas para mantener la coherencia. Para usar App_GlobalResources mueve tus archivos .resx allí y cambia tu declaración de uso para que coincida con el nombre del directorio. De esta manera:

using YourAssembly.App_GlobalResources; 

Editar: Lo más cerca que se puede llegar al establecimiento inflexible nombres de recursos habría que hacer algo como esto:

public class ResourceNames 
{ 
    public const string EmailRequired = "EmailRequired"; 
} 

entonces Se puede decorar con atributos como este.

[Required(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = ResourceNames.EmailRequired)] 

para permitir la detección automática de clientes cultura añadir el globalizationsection al archivo web.config .

<configuration> 
    <system.web> 
     <globalization enableClientBasedCulture="true" culture="auto:en-us" uiCulture="auto:en-us"/> 
    </system.web> 
<configuration> 

Aquí me han permitido una cultura basada en el cliente y establecer la cultura y la uiculture a " automático" con un valor predeterminado de "es-".


Crear ensamblados satélite separados:

El MSDN Creating Satellite Assemblies artículo le ayudará también. Si es nuevo en los ensambles satelitales, asegúrese de leer Packaging and Deploying Resources.

Al crear ensambles satelitales en el pasado, he encontrado que es útil usar eventos de compilación VS. Estos son los pasos que tomaría.

  1. Crear un proyecto separado Class Library en mi solución.
  2. Crear o agregar mis archivos .resx a este proyecto.
  3. Añadir un Post-Build Event al diálogo Project Properties. (Como la de abajo)

Muestra VS Post Script-Build:

set RESGEN="C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\resgen.exe" 
set LINKER="C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\al.exe" 
set ASSEMBLY=$(TargetName) 
set SOURCEDIR=$(ProjectDir) 
Set OUTDIR=$(TargetDir) 

REM Build Default Culture Resources (en) 
%RESGEN% %SOURCEDIR%en\%ASSEMBLY%.en.resx %SOURCEDIR%en\%ASSEMBLY%.resources 

REM Embed Default Culture 
%LINKER% /t:lib /embed:%SOURCEDIR%en\%ASSEMBLY%.resources /culture:en /out:%OUTDIR%%ASSEMBLY%.resources.dll 
REM Embed English Culture 
IF NOT EXIST %OUTDIR%en\ MKDIR $%OUTDIR%en\ 
%LINKER% /t:lib /embed:%SOURCEDIR%en\%ASSEMBLY%.resources /culture:en /out:%OUTDIR%en\%ASSEMBLY%.resources.dll 


REM These are just a byproduct of using the project build event to run the resource build script 
IF EXIST %OUTDIR%%ASSEMBLY%.dll DEL %OUTDIR%%ASSEMBLY%.dll 
IF EXIST %OUTDIR%%ASSEMBLY%.pdb DEL %OUTDIR%%ASSEMBLY%.pdb 

Si prefiere no utilizar ResGen.exe para convertir sus .resx archivos, usted podría hacer algo como esto .

using System; 
using System.Collections; 
using System.IO; 
using System.Resources; 

namespace ResXConverter 
{ 
    public class ResxToResource 
    { 
     public void Convert(string resxPath, string resourcePath) 
     { 
      using (ResXResourceReader resxReader = new ResXResourceReader(resxPath)) 
      using (IResourceWriter resWriter = new ResourceWriter(
        new FileStream(resourcePath, FileMode.Create, FileAccess.Write))) 
      { 
       foreach (DictionaryEntry entry in resxReader) 
       { 
        resWriter.AddResource(entry.Key.ToString(), entry.Value); 
       } 
       resWriter.Generate(); 
       resWriter.Close(); 
      } 
     } 
    } 
} 

Una de las posibles pegas a hacer la conversión de esta manera es la necesidad de hacer referencia a la System.Windows.Forms.dll. Aún necesitará usar Assembly Linker.

Editar: Como wRAR nos ha recordado si está firmando sus conjuntos, sus claves must match.

+0

Ya leí todos estos enlaces. El primer enlace sugiere colocar los nombres de los recursos en los atributos explícitamente, esto no es lo que quiero. En cuanto a los ensamblados de satélites, todavía no puedo entender (e incluso encontrar el lugar relevante en MSDN) cómo el ensamblado, el espacio de nombres y el recurso deben ser cargados por el tiempo de ejecución y si existen requisitos adicionales. System.ComponentModel.DataAnnotations.resources.dll que contiene System.ComponentModel.DataAnnotations.resources o System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources.resources aparentemente no está cargado. – wRAR

+0

@wRAR: Antes de llegar a las convenciones de nombres, ¿desea especificar en tiempo de ejecución qué tipo de mensaje se muestra o si no desea cadenas en sus atributos? – VoidDweller

+0

Solo quiero localizar cadenas estándar. – wRAR

0

Si el servidor no tiene paquetes de idioma .NET instalados, sin importar en qué CurrentUICulture esté configurado, siempre obtendrá inglés en los mensajes de validación de DataAnnotaciones. Este hack épico funciona para nosotros.

  • Ir a "Microsoft .NET Framework 4.6.1 paquete de idioma en" descargar la página https://www.microsoft.com/en-us/download/details.aspx?id=49977
  • Seleccionar idioma y descargar
  • Extracto NDP461-KB3102436-x86-x64-AllOS- {lang} .exe con 7 -Zip
  • Extracto archivo CAB x64-Windows10.0-KB3102502-x64.cab con 7-Zip
  • Localizar "msil_system.componentmod..notations.resources _...."
  • ... en el que se Encontrará "system.componentmodel.dataannotations.resources.dll"
  • .resources.dll abierta con ILSpy, localizar recursos y haga clic en el botón Guardar anterior tabla de cadenas para guardar como System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources. {IDIOMA} .resources
  • Añadir a su proyecto bajo dicen un "Recursos "
  • garantizar que los archivos Construir acción de propiedad de los archivos de recursos se establece en 'Recurso incrustado'

Luego, en un método de prearranque de su proyecto se sobrescribe el campo estático privada System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources.resourceMan (se dijo que era un truco) con los que tienes en tu proyecto

using System; 
using System.Linq; 
using System.Reflection; 
using System.Resources; 

[assembly: WebActivator.PreApplicationStartMethod(typeof(ResourceManagerUtil), nameof(ResourceManagerUtil.PreStart))] 

class ResourceManagerUtil 
{ 
    public static void PreStart() 
    { 
     initDataAnnotationsResourceManager(); 
    } 

    /// <summary> 
    /// If the server doesn't have .NET language packs installed then no matter what CurrentUICulture is set to, you'll always get English in 
    /// DataAnnotations validation messages. Here we override DataAnnotationsResources to use a ResourceManager that uses language .resources 
    /// files embedded in this assembly. 
    /// </summary> 
    static void initDataAnnotationsResourceManager() 
    { 
     var embeddedResourceNamespace = "<YourProjectDefaultNamespace>.<FolderYouSavedResourcesFilesIn>"; 
     var dataAnnotationsResourcesName = "System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources"; 
     var thisAssembly = typeof(ResourceManagerUtil).Assembly; 
     var dataAnnotationsAssembly = typeof(System.ComponentModel.DataAnnotations.ValidationAttribute).Assembly; 

     var resourceManager = new ResourceManager(embeddedResourceNamespace + "." + dataAnnotationsResourcesName, thisAssembly); 

     // Set internal field `DataAnnotationsResources.resourceMan` 
     var dataAnnotationsResourcesType = dataAnnotationsAssembly.GetType(dataAnnotationsResourcesName); 
     var resmanProp = dataAnnotationsResourcesType.GetField("resourceMan", BindingFlags.NonPublic | BindingFlags.Static); 
     resmanProp.SetValue(null, resourceManager); 
    } 
} 
Cuestiones relacionadas