2010-03-29 12 views
5

Desidero sovrascrivere una stringa da System.ComponentModel.DataAnnotations per un progetto ASP.NET. Devo creare un satellite assembly, fare scherzi con le attività di compilazione personalizzate, al.exe ecc.? Anche se sì, non sono riuscito a trovare come convertire .resx in .resources per inviarlo a al.exe. E se no, dove mettere il .resx. e come chiamarlo?Sovrascrivere una risorsa dall'assieme standard in ASP.NET

UPD: Per chiarire: volevo utilizzare una stringa di risorse personalizzata anziché una dalla risorsa predefinita dell'assieme. Non volevo apportare modifiche in ogni posto che utilizza quella stringa. Dopo tutto, le risorse esistono solo per sovrascriverle.

risposta

2

Mentre questo è strano, soprattutto per le persone che hanno familiarità con le tecnologie di localizzazione open source, non si può costruire un assembly satellite per qualsiasi sistema di montaggio o anche un 3rd-party firmato 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.

Se lo stesso è possibile automaticamente, ma senza un satellite, è sconosciuto, anche se ne dubito.

1

Supponendo che si desidera ignorare le stringhe di messaggio di errore di default negli attributi di convalida, è possibile farlo impostando le e le ErrorMessageResourceType proprietà ErrorMessageResourceName come questo:

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

È possibile creare un file di risorse chiamato MyResourceFile .resx che contiene Required_Username con il messaggio di errore desiderato.

Spero che questo aiuti.

+0

Lo so, ma non voglio cambiare tutti gli attributi. – wRAR

4

Phil Haack ha un eccellente articolo Localizing ASP.Net MVC Validation che ti guida specificatamente attraverso l'override delle stringhe. Questo articolo si applica più a DataAnnotations rispetto a ASP.net MVC. Quindi, questo ti aiuterà comunque a utilizzare DataAnnotattions.

Di seguito sono elencati i passaggi più semplici per aggiungere risorse localizzate in Visual Studio.

  1. Aprire la finestra di Project Properties.
  2. Selezionare la scheda Resources.
  3. Fare clic per creare un nuovo file risorse predefinito .
  4. Ciò creerà due file nella cartella Properties.
    • Resources.resx
    • Resources.Designer.cs
  5. Quando Resources.resx ha aperto , cambiare è Access Modifier a Public.
  6. Aggiungi le tue stringhe.

Per aggiungere ulteriori file di risorse per culture specifiche sarà necessario.

  1. Fare clic destro tua Project nel Solution Explorer.
  2. Selezionare Aggiungi ->Nuovo elemento ->risorse file.
  3. Denominarlo Resources.en-us.resx. (sostituire 'it-it' con codice appropriato )
  4. Fare clic su Aggiungi
  5. trascinare nella cartella Properties.
  6. aperto Resources.en-us.resx e cambiare è Access Modifier a Public.
  7. Aggiungi le tue stringhe.
  8. Ripetere per ogni coltura che è necessario il supporto .

durante la costruzione VS convertirà i file .resx-.resource file e costruire classi wrapper per voi. È quindi possibile accedere tramite il namespace YourAssembly.Properties.Resources.

Con questa istruzione using.

using YourAssembly.Properties; 

Potete decorare con attributi come questo:

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

Nota: ho usato la cartella Proprietà per coerenza. Per utilizzare App_GlobalResources spostare i file .resx e modificare l'istruzione using in modo che corrisponda al nome della directory. Come questo:

using YourAssembly.App_GlobalResources; 

Edit: Il più vicino che si può arrivare a tipizzato fortemente i nomi di risorsa potrebbe essere quella di fare qualcosa di simile:

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

È quindi possibile decorare con attributi come questo.

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

per attivare il rilevamento automatico di cultura cliente aggiunge il globalizationsection al file di web.config.

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

Qui mi hanno consentito una cultura basata client e impostare il cultura e la uiculture a "auto" con un valore predefinito di "it-it".


Creazione di assembly satellite separati:

MSDN Creating Satellite Assemblies articolo vi aiuterà pure. Se si è nuovi all'assemblaggio satellitare, assicurarsi di leggere Packaging and Deploying Resources.

Durante la creazione di assemblee satellitari in passato, ho trovato utile utilizzare gli eventi di generazione VS. Questi sono i passi che vorrei prendere.

  1. Creare un distinto progetto di Class Library nella mia soluzione.
  2. Creare o aggiungere i miei .resx file a questo progetto.
  3. Aggiungi un Post-Build Event alla finestra di Project Properties. (Come quella qui sotto)

Esempio VS Script di post-generazione:

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 

Se si preferisce non utilizzare ResGen.exe per convertire i .resx file, si potrebbe fare qualcosa di simile .

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

Uno dei potenziali spalle di disegnare a fare la conversione in questo modo è la necessità di fare riferimento al System.Windows.Forms.dll. Sarà comunque necessario utilizzare Assembly Linker.

Modifica: come wRAR ci ha ricordato se si sta firmando il tuo assemblee le chiavi must match.

+0

Ho già letto tutti questi link. Il primo link suggerisce di posizionare esplicitamente i nomi delle risorse negli attributi, questo non è ciò che voglio. Per quanto riguarda gli assembly satellitari, non riesco ancora a capire (e persino a trovare il posto pertinente in MSDN) come dovrebbe essere chiamato il assembly, lo spazio dei nomi e la risorsa per essere caricato dal runtime e se esistono requisiti aggiuntivi. System.ComponentModel.DataAnnotations.resources.dll contenente System.ComponentModel.DataAnnotations.resources o System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources.resources apparentemente non viene caricato. – wRAR

+0

@wRAR: Prima di arrivare alle convenzioni di denominazione, vuoi specificare in fase di esecuzione quale tipo di messaggio viene visualizzato o è che non desideri stringhe nei tuoi attributi? – VoidDweller

+0

Voglio solo localizzare le stringhe standard. – wRAR

0

Se il server non ha pacchetti di lingua .NET installati, indipendentemente da cosa sia impostato CurrentUICulture, si otterrà sempre l'inglese nei messaggi di convalida DataAnnotations. Questo epico hack funziona per noi.

  • Vai a "Microsoft .NET Framework Language Pack 4.6.1" pagina di download https://www.microsoft.com/en-us/download/details.aspx?id=49977
  • Seleziona la lingua e scarica
  • estratto NDP461-KB3102436-x86-x64-AllOS- {LANG} .exe con 7 -Zip
  • estratto x64-Windows10.0-KB3102502-x64.cab file CAB con 7-Zip
  • Individuare "msil_system.componentmod..notations.resources _...."
  • ... in cui si troverà "system.componentmodel.dataannotations.resources.dll"
  • aperta .resources.dll con ILSpy, individuare le risorse e fare clic sul pulsante Salva sopra tabella di stringhe da salvare come System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources. {LANGUAGE} resources
  • aggiungere al progetto sotto dire una "Risorse "
  • assicurare che i file Anno di costruzione d'azione dei file di risorse è impostato su 'risorsa incorporata'

Poi in un metodo pre-partenza del progetto si sovrascrive il campo statico privato System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources.resourceMan (detto che era un hack) con quelli che hai nel tuo progetto.

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