选择逃避HTML在反序列化期间串 [英] Selectively escape HTML in strings during deserialization

查看:106
本文介绍了选择逃避HTML在反序列化期间串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在找写 JsonConverter 这转义HTML字符串中,除非 [AllowHtml] 属性有被应用;

I'm looking to write a JsonConverter which escapes HTML in strings, unless the [AllowHtml] attribute has been applied;

    private class ObjectWithStrings
    {
        // will be HTML-escaped
        public string Name { get; set; }

        // won't be escaped
        [AllowHtml]
        public string Unsafe { get; set; }
    }



所以我想写一个JsonConverter与自定义ReadJson财产;

So I'm trying to write a JsonConverter with a custom ReadJson property;

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(string);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var s = (string)reader.Value;
        if (s == null)
        {
            return null;
        }

        // here I need to get a PropertyInfo so I can call GetCustomAttribute<AllowHtmlAttribute>();

        var encoded = System.Web.Security.AntiXss.AntiXssEncoder.HtmlEncode(s, useNamedEntities: true);
        return encoded;
    }



我已经得到了差距,我不能看看JSON。网将让我知道我在读入属性。因此,我无法弄清楚如何获得属性的自定义属性。

The gap I've got is that I can't see if Json.Net will let me know the property I'm reading into. Consequently, I can't figure out how to get the property's custom attributes.

有没有办法找出我连载什么财产成,或者不同的图案

Is there a way to find out what property I'm serialising into, or a different pattern recommended for this kind of thing?

修改:我没有写一个清晰的问题;我试图写一个 JsonConverter 这deserialises的字符串的 - 见上面的实施CanConvert()。我怀疑这样的选择是我的问题的开始;我可能需要deserialise用绳子属性的对象,并且做一个标准的反序列化deserialising特殊属性时除外。

EDIT: I failed to write a clear question; I've attempted to write a JsonConverter which deserialises strings, -- see the implementation above of CanConvert(). I suspect that choice is the start of my problem; I may need to deserialise objects with string properties, and do a standard deserialize except when deserialising particular properties.

推荐答案

从自定义内 JsonConverter ,你可以找到JSON属性的名称由挑选出来的路径属性被反序列化 JsonReader

From within a custom JsonConverter, you can find the name of the JSON property being deserialized by picking it out of the Path property from the JsonReader.

string propertyName = reader.Path.Split('.').Last();



不过,这不会解决你的整体问题。假设JSON属性的名称目标类的属性相匹配,你仍旧需要一种方式来获得父对象类型,以便你可以从它的自定义属性。不幸的是,这个信息是不提供给你一个转换器内。 A变换器旨在是仅用于它说,它可以转换(你的情况字符串)对象类型负责,并且该对象的子属性(均未在此情况下,由于字符串是一个原始)。因此,要使其工作时,转换器将需要写入的的的类上进行操作,然后将需要处理该类的所有字符串属性。因为你的目标似乎是运用HTML编码的行为在所有类别中的所有字符串,那么你将你想要什么需要一个通用的转换器,处理所有非原始类型,它可以得到相当混乱,这取决于广度反序列化。

However, this will not solve your overall problem. Assuming the name of the JSON property matches your target class property, you'd still need a way to get the parent object type so you can get the custom attributes from it. Unfortunately, this information is not available to you inside a converter. A converter is intended to be responsible only for the object type it says it can convert (string in your case), and that object's child properties (none in this case, since string is a primitive). So, to make it work, the converter would need to be written to operate on the parent class, and would then need to handle all the string properties of that class. Since your goal seems to be to apply the HTML encoding behavior to all strings in all classes, then you would need a generic converter that handles all non-primitive types, which could get pretty messy, depending on the breadth of what you're trying to deserialize.

幸运的是,有一个更好的办法。而是采用了 JsonConverter ,您可以结合使用自定义的 IContractResolver IValueProvider <的/ code>来解决这个问题。要广泛适用某种行为A ContractResolver 是更适合来这样的问题。

Fortunately, there is a better way. Instead of using a JsonConverter, you can use a custom IContractResolver in combination with a IValueProvider to solve this. A ContractResolver is much better suited to problems like this where you want to apply a certain behavior broadly.

下面是你需要的代码的一个例子。在 CustomResolver 类扩展了Json.Net提供的 DefaultContractResolver 。在 CreateProperties()方法检查的基础解析器创建的 JsonProperty 对象,重视内部<$ C的一个实例$ C> HtmlEncodingValueProvider 类不具有应用 [AllowHtml] 属性的任何字符串属性。每个值提供商后处理通过的SetValue()方法,它的目标字符串属性的实际编码。

Below is an example of the code you would need. The CustomResolver class extends the DefaultContractResolver provided by Json.Net. The CreateProperties() method inspects the JsonProperty objects created by the base resolver and attaches an instance of the inner HtmlEncodingValueProvider class to any string properties which do not have the [AllowHtml] attribute applied. Each value provider later handles the actual encoding of its target string property via the SetValue() method.

public class CustomResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);

        // Find all string properties that do not have an [AllowHtml] attribute applied
        // and attach an HtmlEncodingValueProvider instance to them
        foreach (JsonProperty prop in props.Where(p => p.PropertyType == typeof(string)))
        {
            PropertyInfo pi = type.GetProperty(prop.UnderlyingName);
            if (pi != null && pi.GetCustomAttribute(typeof(AllowHtmlAttribute), true) == null)
            {
                prop.ValueProvider = new HtmlEncodingValueProvider(pi);
            }
        }

        return props;
    }

    protected class HtmlEncodingValueProvider : IValueProvider
    {
        PropertyInfo targetProperty;

        public HtmlEncodingValueProvider(PropertyInfo targetProperty)
        {
            this.targetProperty = targetProperty;
        }

        // SetValue gets called by Json.Net during deserialization.
        // The value parameter has the original value read from the JSON;
        // target is the object on which to set the value.
        public void SetValue(object target, object value)
        {
            var encoded = System.Web.Security.AntiXss.AntiXssEncoder.HtmlEncode((string)value, useNamedEntities: true);
            targetProperty.SetValue(target, encoded);
        }

        // GetValue is called by Json.Net during serialization.
        // The target parameter has the object from which to read the string;
        // the return value is the string that gets written to the JSON
        public object GetValue(object target)
        {
            // if you need special handling for serialization, add it here
            return targetProperty.GetValue(target);
        }
    }
}

要使用的解析器,创建一个新的 JsonSerializerSettings 实例,那么它的 ContractResolver 属性设置为自定义冲突解决的新实例,并传递给设置 JsonConvert.DeserializeObject()

To use the resolver, create a new JsonSerializerSettings instance, then set its ContractResolver property to a new instance of the custom resolver and pass the settings to the JsonConvert.DeserializeObject() method.

下面是一个简短的演示:

Here is a short demo:

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        { 
            ""Name"" : ""<b>Foo Bar</b>"", 
            ""Description"" : ""<p>Bada Boom Bada Bing</p>"", 
        }";

        JsonSerializerSettings settings = new JsonSerializerSettings
        {
            ContractResolver = new CustomResolver()
        };

        Foo foo = JsonConvert.DeserializeObject<Foo>(json, settings);
        Console.WriteLine("Name: " + foo.Name);
        Console.WriteLine("Desc: " + foo.Description);
    }
}

class Foo
{
    public string Name { get; set; }
    [AllowHtml]
    public string Description { get; set; }
}

class AllowHtmlAttribute : Attribute { }

下面是输出。注意:名称属性,都会HTML编码,而说明属性不。

Here is the output. Notice that the Name property gets HTML encoded while the Description property does not.

Name: &lt;b&gt;Foo Bar&lt;/b&gt;
Desc: <p>Bada Boom Bada Bing</p>



小提琴:的 https://dotnetfiddle.net/cAg4NC

这篇关于选择逃避HTML在反序列化期间串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆