• 依赖注入的威力,.NET Core的魅力:解决MVC视图中的中文被html编码的问题


    有园友在博问中提了这样一个问题 —— .NET Core 中文等非英文文字html编码输出问题,到我们的 ASP.NET Core 项目中一看,也是同样的问题。

    比如下面的Razor视图代码:

    @{
        ViewBag.Title = "代码改变世界";
    }
    <title>@ViewBag.Title</title>

    输出的html代码变成了:

    <title>&#x4EE3;&#x7801;&#x6539;&#x53D8;&#x4E16;&#x754C;</title>

    上面的 @ViewBag.Title 实际上等同于下面的代码:

    @Html.Raw(Html.Encode(ViewBag.Title))

    所以解决这个问题需要从ASP.NET Core MVC中的HtmlHelper下手(上面代码中Html的类型就是HtmlHelper)。

    从GitHub上签出MVC的源代码看看HtmlHelper.Encode()的实现:

    private readonly IHtmlGenerator _htmlGenerator;
    public string Encode(string value)
    {
        return _htmlGenerator.Encode(value);
    }

    实际调用的是IHtmlGenerator接口的Encode()方法,MVC中实现这个接口的是DefaultHtmlGenerator,其对应的Encode()实现代码如下:

    private readonly HtmlEncoder _htmlEncoder;
    public string Encode(string value)
    {
        return !string.IsNullOrEmpty(value) ? _htmlEncoder.Encode(value) : string.Empty;
    }

    原来真正干活的主角是HtmlEncoder,但它不是在MVC中实现的,而是在.NET Core Framework中实现的,命名空间是 System.Text.Encodings.Web 。

    写个.NET Core控制台程序直接调用HtmlEncoder看看是不是就是它惹的祸。

    public class Program
    {
        public static void Main(string[] args)
        {            
            Console.WriteLine(HtmlEncoder.Default.Encode("代码改变世界"));
        }
    }

    输出结果与MVC中是同样的问题。

    试试不用默认的HtmlEncoder实例(HtmlEncoder.Default),而是自己调用HtmlEncoder.Create()方法创建实例,这时发现了UnicodeRange参数类型。

    public static HtmlEncoder Create(params UnicodeRange[] allowedRanges);

    当使用UnicodeRanges.All作为参数创建HtmlEncoder实例时,问题就解决了。

    Console.WriteLine(HtmlEncoder.Create(UnicodeRanges.All).Encode("代码改变世界"));

    紧接着从GitHub上签出System.Text.Encodings.Web的源代码,看看HtmlEncoder.Default对应的HtmlEncode实例是如何被创建的:

    internal readonly static DefaultHtmlEncoder Singleton = new DefaultHtmlEncoder(new TextEncoderSettings(UnicodeRanges.BasicLatin));

    原来用的是UnicodeRanges.BasicLatin,难怪中文会被编码,搞不懂为什么默认不用UnicodeRanges.All?

    知道了问题的原因,解决起来就不难了,只要我们以HtmlEncoder.Create(UnicodeRanges.All)创建HtmlEncoder实例,并替换掉MVC中所用的默认HtmlEncoder实例。那如何替换呢?

    回到MVC的源代码中,看看DefaultHtmlGenerator的实现,发现它的构造函数参数中有HtmlEncoder:

    public DefaultHtmlGenerator(
        IAntiforgery antiforgery,
        IOptions<MvcViewOptions> optionsAccessor,
        IModelMetadataProvider metadataProvider,
        IUrlHelperFactory urlHelperFactory,
        HtmlEncoder htmlEncoder,
        ClientValidatorCache clientValidatorCache)
    {
    }

    根据.NET从上到下、由内而外全面依赖注入的秉性,这个地方应该也是依赖注入的,我们只需注入一个新的HtmlEncoder实例即可,是不是这样呢?

    码上一行,你就知道。

    在 Startup.cs 的 ConfigureServices() 方法中添加下面的一行代码:

    services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All));

    运行ASP.NET Core站点,输出结果如下:

    <title>代码改变世界</title>

    一行注入,立马解决。依赖注入的威力,.NET Core的魅力。

    更新1:根据 零度的火 的评论,更好的解决方法是

    services.Configure<WebEncoderOptions>(options =>
    {
          options.TextEncoderSettings = new TextEncoderSettings(UnicodeRanges.All);
    });

    更新2:后来发现更好的解决方法

    services.Configure<WebEncoderOptions>(options =>
        options.TextEncoderSettings = new TextEncoderSettings(UnicodeRanges.BasicLatin,
            UnicodeRanges.CjkUnifiedIdeographs));
  • 相关阅读:
    tomcat监控与优化
    rpm打包
    Rewrite和location 区别
    LNMP服务
    yum仓库脚本
    用户管理的脚本2
    pxe装机脚本
    用户管理的脚本1
    磁盘管理综合测试题
    MySQL 增量备份介绍及案例演示
  • 原文地址:https://www.cnblogs.com/dudu/p/5879913.html
Copyright © 2020-2023  润新知