Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 实现ASP.NET Web API可选参数_C#_.net_Json_Asp.net Web Api_Json.net - Fatal编程技术网

C# 实现ASP.NET Web API可选参数

C# 实现ASP.NET Web API可选参数,c#,.net,json,asp.net-web-api,json.net,C#,.net,Json,Asp.net Web Api,Json.net,我需要能够区分未提供的密钥和null JSON的一个例子是: # key not specified {} # key specified but null {'optionalKey' : null} # key specified and is valid {'optionalKey' : 123} 为了区分键的缺失和null,我创建了一个通用的可选类来包装每个字段,但这需要编写一个定制的JsonConverter和DefaultContractResolver来展平JSON/解压O

我需要能够区分未提供的密钥和null

JSON的一个例子是:

# key not specified
{} 

# key specified but null
{'optionalKey' : null}

# key specified and is valid
{'optionalKey' : 123}
为了区分键的缺失和null,我创建了一个通用的可选类来包装每个字段,但这需要编写一个定制的JsonConverter和DefaultContractResolver来展平JSON/解压OptionalType(为每个字段发送嵌套JSON不是一个选项)

我已经设法创建了一个LINQPad脚本来实现这一点,但我忍不住想,一定有一种更简单的方法,不涉及反射

void Main()
{
    //null
    Settings settings = null;
    JsonConvert.SerializeObject(settings, new JsonSerializerSettings() { ContractResolver = new ShouldSerializeContractResolver() }).Dump();

    settings = new Settings();

    // no key {}
    settings.OptionalIntegerSetting = null;
    JsonConvert.SerializeObject(settings, new JsonSerializerSettings() { ContractResolver = new ShouldSerializeContractResolver() }).Dump();

    // null key {\"OptionalIntegerSetting\" : null}
    settings.OptionalIntegerSetting = new Optional<uint?>(); // assigning this to null assigns the optional type class, it does not use the implict operators.
    JsonConvert.SerializeObject(settings, new JsonSerializerSettings() { ContractResolver = new ShouldSerializeContractResolver() }).Dump();

    // has value {\"OptionalIntegerSetting\" : 123}
    settings.OptionalIntegerSetting = 123;
    JsonConvert.SerializeObject(settings, new JsonSerializerSettings() { ContractResolver = new ShouldSerializeContractResolver() }).Dump();

    JsonConvert.DeserializeObject<Settings>("{}").Dump();
    JsonConvert.DeserializeObject<Settings>("{'OptionalIntegerSetting' : null}").Dump();
    JsonConvert.DeserializeObject<Settings>("{'OptionalIntegerSetting' : '123'}").Dump(); // supplying 'a string' instead of '123' currently breaks OptionalConverter.ReadJson 
}

public class Settings
{
    public Optional<uint?> OptionalIntegerSetting { get; set; }
}

[JsonConverter(typeof(OptionalConverter))]
public class Optional<T>
{
    public T Value { get; set; }

    public Optional() { }

    public Optional(T value)
    {
        Value = value;
    }

    public static implicit operator Optional<T>(T t)
    {
        return new Optional<T>(t);
    }

    public static implicit operator T(Optional<T> t)
    {
        return t.Value;
    }
}

// Provides a way of populating the POCO Resource model with CanSerialise proerties at the point just before serialisation.
// This prevents having to define a CanSerialiseMyProperty method for each property.
public class ShouldSerializeContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Optional<>))
        {
            // add an additional ShouldSerialize property to omit no json
            property.ShouldSerialize = instance =>
                instance.GetType().GetProperty(property.PropertyName).GetValue(instance) != null;
        }
        return property;
    }
}

// Performs the conversion to and from a JSON value to compound type
public class OptionalConverter : JsonConverter
{
    public override bool CanWrite => true;
    public override bool CanRead => true;

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(Optional<>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jtoken = JToken.Load(reader);
        var genericTypeArgument = objectType.GetGenericArguments()[0];
        var constructor = objectType.GetConstructor(new[] { genericTypeArgument });
        var result = JTokenType.Null != jtoken.Type ? jtoken.ToObject(genericTypeArgument) : null;

        return constructor.Invoke(new object[] { JTokenType.Null != jtoken.Type ? jtoken.ToObject(genericTypeArgument) : null });
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var val = value.GetType().GetProperty("Value").GetValue(value);
        (val != null ? JValue.FromObject(val) : JValue.CreateNull()).WriteTo(writer);
    }
}
void Main()
{
//空的
设置=空;
SerializeObject(设置,新JsonSerializerSettings(){ContractResolver=new ShouldSerializeContractResolver()}).Dump();
设置=新设置();
//没有键{}
settings.optionIntegerSetting=null;
SerializeObject(设置,新JsonSerializerSettings(){ContractResolver=new ShouldSerializeContractResolver()}).Dump();
//空键{\“OptionalIntegerSetting\”:空}
settings.OptionalIntegerSetting=new Optional();//将此赋值为null将指定可选类型类,但它不使用隐式运算符。
SerializeObject(设置,新JsonSerializerSettings(){ContractResolver=new ShouldSerializeContractResolver()}).Dump();
//具有值{\“OptionalIntegerSetting\”:123}
settings.optionIntegerSetting=123;
SerializeObject(设置,新JsonSerializerSettings(){ContractResolver=new ShouldSerializeContractResolver()}).Dump();
JsonConvert.DeserializeObject(“{}”).Dump();
JsonConvert.DeserializeObject(“{OptionalIntegerSetting':null}”).Dump();
JsonConvert.DeserializeObject(“{'OptionalIntegerSetting':'123'}”).Dump();//提供'string'而不是'123'当前会中断OptionalConverter.ReadJson
}
公共类设置
{
公共可选选项IntegerSetting{get;set;}
}
[JsonConverter(类型(可选转换器))]
公共课任选
{
公共T值{get;set;}
公共可选(){}
公共可选(T值)
{
价值=价值;
}
公共静态隐式运算符可选(T)
{
返回新的可选(t);
}
公共静态隐式运算符T(可选T)
{
返回t.值;
}
}
//提供了一种在序列化之前使用CanSerialise proerties填充POCO资源模型的方法。
//这样可以避免为每个属性定义CanSerialiseMyProperty方法。
公共类应序列化ContractResolver:DefaultContractResolver
{
受保护的重写JsonProperty CreateProperty(MemberInfo成员、MemberSerialization MemberSerialization)
{
JsonProperty属性=base.CreateProperty(成员,成员序列化);
if(property.PropertyType.IsGenericType&&property.PropertyType.GetGenericTypeDefinition()==typeof(可选))
{
//添加一个额外的ShouldSerialize属性以省略任何json
property.ShouldSerialize=实例=>
instance.GetType().GetProperty(property.PropertyName).GetValue(instance)!=null;
}
归还财产;
}
}
//执行从JSON值到复合类型的转换
公共类OptionalConverter:JsonConverter
{
public override bool CanWrite=>true;
public override bool CanRead=>true;
公共覆盖布尔CanConvert(类型objectType)
{
返回objectType.IsGenericType&&objectType.GetGenericTypeDefinition()==typeof(可选);
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
var jtoken=jtoken.Load(读卡器);
var genericTypeArgument=objectType.GetGenericArguments()[0];
var constructor=objectType.GetConstructor(新[]{generictyperagument});
var result=JTokenType.Null!=jtoken.Type?jtoken.ToObject(genericTypeArgument):Null;
返回构造函数.Invoke(新对象[]{JTokenType.Null!=jtoken.Type?jtoken.ToObject(genericTypeArgument):Null});
}
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
var val=value.GetType().GetProperty(“值”).GetValue(值);
(val!=null?JValue.FromObject(val):JValue.CreateNull()).WriteTo(writer);
}
}

全部学分归@dbc所有

void Main()
{
    var settings = new Settings();

    // no key {}
    settings.OptionalIntegerSetting = null;
    JsonConvert.SerializeObject(settings).Dump();

    // null key {\"OptionalIntegerSetting\" : null}
    settings.OptionalIntegerSetting = null;
    settings.OptionalIntegerSettingSpecified = true;
    JsonConvert.SerializeObject(settings).Dump();

    // has value {\"OptionalIntegerSetting\" : 123}
    settings.OptionalIntegerSetting = 123;
    JsonConvert.SerializeObject(settings).Dump();

    JsonConvert.DeserializeObject<Settings>("{}").Dump();
    JsonConvert.DeserializeObject<Settings>("{'OptionalIntegerSetting' : null}").Dump();
    JsonConvert.DeserializeObject<Settings>("{'OptionalIntegerSetting' : '123'}").Dump();
}

public class Settings
{
    public uint? OptionalIntegerSetting { get; set; }

    [JsonIgnore]
    public bool OptionalIntegerSettingSpecified { get; set;}
}
void Main()
{
变量设置=新设置();
//没有键{}
settings.optionIntegerSetting=null;
序列化对象(设置).Dump();
//空键{\“OptionalIntegerSetting\”:空}
settings.optionIntegerSetting=null;
settings.optionIntegerSettingSpecified=true;
序列化对象(设置).Dump();
//具有值{\“OptionalIntegerSetting\”:123}
settings.optionIntegerSetting=123;
序列化对象(设置).Dump();
JsonConvert.DeserializeObject(“{}”).Dump();
JsonConvert.DeserializeObject(“{OptionalIntegerSetting':null}”).Dump();
JsonConvert.DeserializeObject(“{'OptionalIntegerSetting':'123'}”).Dump();
}
公共类设置
{
公共uint?OptionalIntegerSetting{get;set;}
[JsonIgnore]
公共bool optionIntegerSettingSpecified{get;set;}
}

全部学分归@dbc所有

void Main()
{
    var settings = new Settings();

    // no key {}
    settings.OptionalIntegerSetting = null;
    JsonConvert.SerializeObject(settings).Dump();

    // null key {\"OptionalIntegerSetting\" : null}
    settings.OptionalIntegerSetting = null;
    settings.OptionalIntegerSettingSpecified = true;
    JsonConvert.SerializeObject(settings).Dump();

    // has value {\"OptionalIntegerSetting\" : 123}
    settings.OptionalIntegerSetting = 123;
    JsonConvert.SerializeObject(settings).Dump();

    JsonConvert.DeserializeObject<Settings>("{}").Dump();
    JsonConvert.DeserializeObject<Settings>("{'OptionalIntegerSetting' : null}").Dump();
    JsonConvert.DeserializeObject<Settings>("{'OptionalIntegerSetting' : '123'}").Dump();
}

public class Settings
{
    public uint? OptionalIntegerSetting { get; set; }

    [JsonIgnore]
    public bool OptionalIntegerSettingSpecified { get; set;}
}
void Main()
{
变量设置=新设置();
//没有键{}
settings.optionIntegerSetting=null;
序列化对象(设置).Dump();
//空键{\“OptionalIntegerSetting\”:空}
settings.optionIntegerSetting=null;
settings.optionIntegerSettingSpecified=true;
序列化对象(设置).Dump();
//具有值{\“OptionalIntegerSetting\”:123}
settings.optionIntegerSetting=123;
序列化对象(设置).Dump();
JsonConvert.DeserializeObject(“{}”).Dump();
JsonConvert.Deseri