zoukankan      html  css  js  c++  java
  • 依赖注入的威力,.NET Core的魅力:解决MVC视图中的中文被html编码的问题【转载】

    转载:http://www.cnblogs.com/dudu/p/5879913.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的魅力。

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

    services.Configure<WebEncoderOptions>(options =>
    {
          options.TextEncoderSettings = new TextEncoderSettings(UnicodeRanges.All);
    });
  • 相关阅读:
    poj 3068 Bridge Across Islands
    XidianOJ 1086 Flappy v8
    XidianOJ 1036 分配宝藏
    XidianOJ 1090 爬树的V8
    XidianOJ 1088 AK后的V8
    XidianOJ 1062 Black King Bar
    XidianOJ 1091 看Dota视频的V8
    XidianOJ 1098 突击数论前的xry111
    XidianOJ 1019 自然数的秘密
    XidianOJ 1109 Too Naive
  • 原文地址:https://www.cnblogs.com/wangpd/p/7232410.html
Copyright © 2011-2022 走看看