Override a resource from a standard assembly in ASP.NET

I want to override a string from System.ComponentModel.DataAnnotations for an ASP.NET project. Do I need to assemble a satellite assembly, tinker with custom assembly tasks, al.exe , etc.? Even if so, I could not find how to convert .resx to .resources to pass it to al.exe . And if not, where to put .resx. and what to call him?

UPD: To make it clear: I wanted to use a custom resource string instead of one of the default resources from the assembly. I did not want to make changes to every place using this line. In the end, resources exist only to redefine them.

+5
source share
4 answers

While this is strange, especially for people familiar with open source localization technologies, it is not possible to assemble a satellite assembly for any system assembly or even a third-party signed:

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

The same is possible automatically, but without assembling the satellite, it is unknown, although I doubt it.

+2
source

Phil Haack has an excellent ASP.Net MVC Validation Localization article that specifically helps you redefine your strings. This article relates more to DataAnnotations than to ASP.net MVC . This way, it will help you use DataAnnotattions.

The following are the simplest steps to add localized resources in Visual Studio.

  • Open the Project Properties dialog box.
  • Select the Resources tab.
  • Click to create a new default resource file.
  • This will create two files in your Properties folder.
    • Resources.resx
    • Resources.Designer.cs
  • When Resource.resx has an open, change its Access Modifier to Public .
  • Add your lines.

To add additional resource files for specific cultures, you will need to.

  • Right-click your Project in Solution Explorer .
  • Choose Add β†’ New Item β†’ Resource File.
  • Name it Resources.en-us.resx . (replace "en-us" with the appropriate code)
  • Click Add
  • Drag it to the Properties folder.
  • Open Resources.en-us.resx and change its Access Modifier to Public .
  • Add your lines.
  • Repeat for each Culture, support.

During build, VS will convert the .resx files to .resource files and create wrapper classes for you. You can then access through the YourAssembly.Properties.Resources namespace.

With the help of this instruction.

 using YourAssembly.Properties; 

You can decorate with the following attributes:

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

Note. I used the Properties folder to ensure consistency. To use App_GlobalResources, move the .resx files there and modify the using statement to match the directory name. Like this:

 using YourAssembly.App_GlobalResources; 

Edit: closest to what you can get for strongly typed resource names would be to do something like this:

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

Then you can decorate with such attributes.

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

To enable automatic client culture detection, add globalizationsection to the web.config file.

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

Here I turned on a client-based culture and set the culture and ugliness to β€œauto” with a default value of β€œen-us”.


Creating separate satellite assemblies:

At MSDN, building satellite assemblies will also help. If you are new to satellite builds, make sure you read Packaging and Deploying Resources .

When creating satellite assemblies in the past, I found it useful to use VS build events. These are the steps that I would take.

  • Create a separate Class Library project in my solution.
  • Create or add my .resx files to this project.
  • Add a Post-Build Event to the Project Properties . (As below)

VS Post-Build Script example:

 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 

If you do not want to use ResGen.exe to convert your .resx files, you can do something like this.

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

One possible way back to perform the conversion in this way is to need a reference to System.Windows.Forms.dll . You still have to use Assembly Linker .

Edit: since wRAR reminded us that you are signing your assemblies, your keys must match .

+4
source

Assuming you want to override the default error message lines in the validation attributes, you can do this by setting the ErrorMessageResourceName and ErrorMessageResourceType as follows:

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

You can create a MyResourceFile.resx resource file containing Required_Username with the desired error message.

Hope this helps.

+1
source

If the .NET language packs are not installed on the server, regardless of what CurrentUICulture is installed for, you will always receive messages in English in the DataAnnotations check messages. This epic hack works for us.

  • Go to the download page of the "Microsoft.NET Framework 4.6.1 Language Pack" https://www.microsoft.com/en-us/download/details.aspx?id=49977
  • Choose your language and download
  • Extract NDP461-KB3102436-x86-x64-AllOS- {LANG} .exe with 7-Zip
  • Extract CAB file x64-Windows10.0-KB3102502-x64.cab with 7-Zip
  • Search for "msil_system.componentmod..notations.resources _...."
  • ... in which you will find "system.componentmodel.dataannotations.resources.dll"
  • Open .resources.dll with ILSpy, find the resources and click the "Save" button above the row table to save it as System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources. {LANGUAGE} .resources
  • Add to your project in the "Resources" section
  • Verify that the Build Action property of the resource files is set to Embedded Resource

Then, in the PreStart method of your project, you overwrite the private static field System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources.resourceMan (they said it was a hack) with the ones you have in your project.

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

Source: https://habr.com/ru/post/892679/


All Articles