当前位置: 首页 > 编程语言 > C#

ASP.NETWebAPI2和部分更新分享

时间:2023-04-10 16:16:42 C#

ASP.NETWebAPI2和部分更新我们正在使用ASP.NETWebAPI2并希望通过以下方式公开部分编辑某些对象的能力:HTTPPATCH/customers/1{"firstName":"John","lastName":null}...将firstName设置为“John”,将lastName设置为null。HTTPPATCH/customers/1{"firstName":"John"}...只是为了将firstName更新为"John"而根本不触摸lastName。假设我们有许多属性要用这种语义更新。这是OData练习的一种非常方便的行为。问题是默认的JSON序列化器在这两种情况下都返回null,所以没有办法区分它们。我正在寻找某种方法来使用某种包装器(设置/取消设置值和标志)来注释模型,以便可以看到这种差异。任何现有的解决方案?起初我误解了这个问题。当我使用Xml时,我发现这很容易。只需在属性中添加一个属性并将属性留空即可。但正如我发现的那样,Json并不是那样工作的。由于我一直在寻找xml和json的解决方案,因此您会在此答案中找到xml引用。另外,我在C#客户端中编写了这个。第一步是创建两个序列化类。publicclassChangeType{[JsonProperty("#text")][XmlText]publicstringText{get;放;}}publicclassGenericChangeType:ChangeType{}我选择了泛型和非泛型类,因为它很难转换为泛型,但这并不重要。此外,对于xml实现,XmlText必须是一个字符串。XmlText是属性的实际值。好处是你可以给这个对象添加属性,而且这是一个对象,而不仅仅是一个字符串。在Xml中它看起来像:JohnForJson这不起作用。Json不知道属性。所以对于Json来说它只是一个有属性的类。为了实现xml值的想法(我将在后面讨论),我将属性重命名为#text。这只是一个约定。由于XmlText是一个字符串(我们希望将其序列化),因此可以忽略类型来存储值。但是在序列化的情况下,我想知道实际类型。缺点是viewmodel需要引用这些类型,优点是属性是强类型序列化:publicclassCustomerViewModel{publicGenericChangeTypeId{get;放;}publicChangeType名字{get;放;}publicChangeType姓氏{get;放;}publicChangeType参考{get;放;}}假设我设置了值:varcustomerViewModel=newCustomerViewModel{//其中int需要保存为字符串。Id=newGenericChangeType{Text="12"},Firstname=newChangeType{Text="John"},Lastname=newChangeType{},Reference=null//也可以省略。在xml中,这看起来像:12John这足以让服务器检测到更改。但是使用json会产生以下内容:{"id":{"#text":"12"},"firstname":{"#text":"John"},"lastname":{"#text":null}之所以有效,是因为在我的实现中,接收视图模型具有相同的定义。但是因为你只是在谈论序列化,如果你使用其他实现,你需要:{"id":12,"firstname":"John","lastname":null}这就是我们需要添加自定义json转换器为这个结果产生位置。相关代码在WriteJson中,假设您只将此转换器添加到序列化程序设置中。但为了完整起见,我还添加了readJson代码。publicclassChangeTypeConverter:JsonConverter{publicoverrideboolCanConvert(TypeobjectType){//这很重要,我们只能将此转换器用于ChangeTypereturntypeof(ChangeType).IsAssignableFrom(objectType);}publicoverrideobjectReadJson(JsonReaderreader,TypeobjectType,objectexistingValue,JsonSerializerserializer){varvalue=JToken.Load(reader);//类型匹配,可以毫无问题地反序列化。如果(value.Type==JTokenType.Object)返回JsonConvert.DeserializeObject(value.ToString(),objectType);//转换为ChangeType并设置值,如果不为空:vart=(ChangeType)Activator.CreateInstance(objectType);if(value.Type!=JTokenType.Null)t.Text=value.ToString();返回吨;}publicoverridevoidWriteJson(JsonWriterwriter,objectvalue,JsonSerializerserializer){vard=value.GetType();如果(typeof(ChangeType).IsAssignableFrom(d)){varchangeObject=(ChangeType)value;//例如GenericChangeTypeif(value.GetType().IsGenericType){try{//类型-intvartype=value.GetType().GetGenericArguments()[0];varc=Convert.ChangeType(changeObject.Text,类型);//写入int值writer.WriteValue(c);}catch{//忽略异常,只写null.writer.WriteNull();}}else{//ChangeType对象。编写内部字符串(如xmlText值)编写器。WriteValue(changeObject.Text);}//写完了。返回;}//另一个派生自ChangeType的对象。//不要在这里添加电流转换器,因为这会导致循环。vars=newJsonSerializer{NullValueHandling=serializer.NullValueHandling,DefaultValueHandling=serializer.DefaultValueHandling,ContractResolver=serializer.ContractResolver};JToken.FromObject(值,s).WriteTo(作者);起初我尝试将转换器添加到类中:[JsonConverter(ChangeTypeConverter)]但问题是转换器将一直被使用,这会创建一个引用循环(如上面代码中的注释中所述)。此外,您可能只想使用此转换器进行序列化。这就是我将它添加到序列化程序的原因:varserializerSettings=newJsonSerializerSettings{NullValueHandling=NullValueHandling.Ignore,DefaultValueHandling=DefaultValueHandling.IgnoreAndPopulate,Converters=newList{newChangeTypeConverter()},ContractResolver=newNewtonsoft.Json。Serialization.CamelCasePropertyNamesContractResolver()};vars=JsonConvert.SerializeObject(customerViewModel,serializerSettings);这将生成我正在寻找的json,并且应该足以让服务器检测到更改。--更新--由于此答案侧重于序列化,因此请务必注意姓氏是序列化字符串的一部分。然后它取决于接收方如何将字符串再次反序列化为对象。序列化和反序列化使用不同的设置。要再次反序列化,您可以使用:vardeserializerSettings=newJsonSerializerSettings{//NullValueHandling=NullValueHandling.Ignore,DefaultValueHandling=DefaultValueHandling.IgnoreAndPopulate,Converters=newList{newConverters.NoChangeTypeConverter()},ContractResolver=newJson.Newtonsoft。Serialization.CamelCasePropertyNamesContractResolver()};varobj=JsonConvert.DeserializeObject(s,deserializerSettings);如果使用相同的类进行反序列化,Request.Lastname应该是ChangeType,Text=null。我不确定为什么从反序列化设置中删除NullValueHandling会导致问题。但是你可以通过将空对象写成值而不是null来克服这个问题。在转换器中,当前的ReadJson已经处理了这个。但是在WriteJson中要修改。而不是writer.WriteValue(changeObject.Text);你需要这样的东西:if(changeObject.Text==null)JToken.FromObject(newChangeType(),s).WriteTo(writer);否则writer.WriteValue(changeObject.Text);这样就会导致:以上就是C#学习教程的全部内容:ASP.NETWebAPI2及部分更新。如果对大家有用,需要进一步了解C#学习教程,希望大家多多关注——{"id":12,"firstname":"John","lastname":{}}这篇文章是收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: