重写ASP.NET中标准程序集中的资源

重写ASP.NET中标准程序集中的资源,asp.net,localization,satellite-assembly,Asp.net,Localization,Satellite Assembly,我想覆盖ASP.NET项目的System.ComponentModel.DataAnnotations中的字符串。我是否需要制作附属程序集,处理自定义构建任务,al.exe等。?即使是,我也找不到如何将.resx转换为.resources以将其提供给al.exe。如果没有,将.resx.放置在何处以及如何命名 UPD:为了说明这一点:我想使用一个自定义资源字符串,而不是程序集默认资源中的字符串。我不想在每个使用该字符串的地方进行更改。毕竟,资源的存在只是为了覆盖它们。假设要覆盖验证属性中的默认错

我想覆盖ASP.NET项目的
System.ComponentModel.DataAnnotations
中的字符串。我是否需要制作附属程序集,处理自定义构建任务,
al.exe
等。?即使是,我也找不到如何将
.resx
转换为
.resources
以将其提供给
al.exe
。如果没有,将
.resx.
放置在何处以及如何命名


UPD:为了说明这一点:我想使用一个自定义资源字符串,而不是程序集默认资源中的字符串。我不想在每个使用该字符串的地方进行更改。毕竟,资源的存在只是为了覆盖它们。

假设要覆盖验证属性中的默认错误消息字符串,可以通过如下设置
ErrorMessageResourceName
ErrorMessageResourceType
属性来实现:

[Required(ErrorMessageResourceName = "Required_Username", ErrorMessageResourceType = typeof(MyResourceFile)]
public string Username { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = "MyStringName")]
public class ResourceNames
{
    public const string EmailRequired = "EmailRequired";
}
您可以创建一个名为MyResourceFile.resx的资源文件,其中包含
必需的\u用户名
,并显示所需的错误消息


希望这有帮助。

Phil Haack有一篇优秀的文章专门指导您重写字符串。本文更多地应用于
DataAnnotations
,而不是
ASP.netmvc
。因此,这将有助于您使用数据注释

下面我列出了在VisualStudio中添加本地化资源的最简单步骤

  • 打开
    项目属性
    对话框
  • 选择
    资源
    选项卡
  • 单击以创建新的默认值 资源文件
  • 这将在
    Properties
    文件夹中创建两个文件。
    • Resources.resx
    • Resources.Designer.cs
  • 当Resources.resx 打开,更改其
    访问修饰符
    公共
  • 添加字符串
  • 要为特定区域性添加其他资源文件,您需要

  • 右键单击中的
    项目
    解决方案资源管理器
  • 选择添加->新项目->资源 文件
  • 将其命名为Resources.en us.resx。 (将“en us”替换为适当的 代码)
  • 单击添加
  • 将其拖动到
    Properties
    文件夹中
  • 打开Resources.en-us.resx并更改其
    Access修饰符
    公共
  • 添加字符串
  • 为您需要的每种文化重复上述步骤 支持
  • 在构建过程中,VS会将.resx文件转换为.resource文件,并为您构建包装器类。然后,您可以通过命名空间
    yoursassembly.Properties.Resources
    进行访问

    使用这个using语句

    using YourAssembly.Properties;
    
    您可以使用如下属性进行装饰:

    [Required(ErrorMessageResourceName = "Required_Username", ErrorMessageResourceType = typeof(MyResourceFile)]
    public string Username { get; set; }
    
    [Required(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = "MyStringName")]
    
    public class ResourceNames
    {
        public const string EmailRequired = "EmailRequired";
    }
    
    注意:为了保持一致性,我使用了Properties文件夹。要使用App_GlobalResources,请将.resx文件移到那里,并更改using语句以匹配目录名。像这样:

    using YourAssembly.App_GlobalResources;
    

    编辑:最接近强类型资源名称的方法是执行以下操作:

    [Required(ErrorMessageResourceName = "Required_Username", ErrorMessageResourceType = typeof(MyResourceFile)]
    public string Username { get; set; }
    
    [Required(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = "MyStringName")]
    
    public class ResourceNames
    {
        public const string EmailRequired = "EmailRequired";
    }
    
    然后,您可以使用这样的属性进行装饰

    [Required(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = ResourceNames.EmailRequired)]
    
    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();
                }
            }
        }
    }
    
    要启用自动客户端区域性检测,请将添加到web.config文件

    如果您不希望使用转换
    .resx
    文件,可以执行以下操作

    [Required(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = ResourceNames.EmailRequired)]
    
    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();
                }
            }
        }
    }
    
    以这种方式进行转换的一个潜在缺点是需要引用
    System.Windows.Forms.dll
    。您仍然需要使用


    编辑:正如wRAR提醒我们的那样,如果你正在为你的程序集签名你的密钥。

    虽然这很奇怪,特别是对于熟悉开源本地化技术的人来说,但是你不能为任何系统程序集甚至第三方签名的程序集构建卫星程序集:


    虽然我对此表示怀疑,但不知道是否可以自动执行相同的操作,但没有附属程序集。

    如果服务器没有安装.NET语言包,那么无论CurrentUICulture设置为什么,您都会在DataAnnotations验证消息中获得英语。这部史诗般的黑客作品适合我们

    • 转到“Microsoft.NET Framework 4.6.1语言包”下载页
    • 选择语言并下载
    • 使用7-Zip解压缩NDP461-KB3102436-x86-x64-AllOS-{LANG}.exe
    • 使用7-Zip解压缩CAB文件x64-Windows10.0-KB3102502-x64.CAB
    • 找到“msil_系统.componentmod..notations.resources_u….”
    • 。。。您可以在其中找到“system.componentmodel.dataannotations.resources.dll”
    • 使用ILSpy打开.resources.dll,找到资源并单击字符串表上方的“保存”按钮,以另存为System.ComponentModel.DataAnnotations.resources.DataAnnotationsResources.{LANGUAGE}.resources
    • 在“资源”下添加到项目中
    • 确保资源文件的文件生成操作属性设置为“嵌入式资源”
    然后,在项目的预启动方法中,用项目中的字段覆盖
    System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources.resourceMan
    私有静态字段(告诉您这是一个黑客行为)

    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);
        }
    }
    
    使用系统;
    使用System.Linq;
    运用系统反思;
    利用系统资源;
    [程序集:WebActivator.PreApplicationStartMethod(typeof(ResourceManagerUtil)、nameof(ResourceManagerUtil.PreStart))]
    Rutil类
    {
    公共静态无效预启动()
    {
    initDataAnnotationsResourceManager();
    }
    /// 
    ///如果服务器上没有安装.NET语言包,那么无论CurrentUICulture设置为什么,您都可以使用英语
    ///DataAnnotations验证消息。这里我们重写DataAnnotationsResources以使用使用language.resources的ResourceManager
    ///嵌入此程序集中的文件。
    /// 
    静态void initDataAnnotationsResourceManager()
    {
    var embeddedResourceNamespace=“.”;
    var dataAnnotationsResourcesName=“System.ComponentMo