[英]Web API - Detecting null assignment
我正在嘗試提出一種模式,可以檢測屬性何時設置為null。 類似於Nullable<T>
類的東西,但更高級一些。 我們稱之為MoreThanNullable<T>
。 基本上我需要根據以下3種情況做一些不同的事情:
我使用“實例化”屬性創建了自己的類來完成此操作,並且它都在測試場景中工作。 一些示例代碼:
public struct MoreThanNullable<T>
{
private bool hasValue;
internal T value;
public bool Instantiated { get; set; }
public MoreThanNullable(T value)
{
this.value = value;
this.hasValue = true;
Instantiated = true;
}
// ... etc etc...
並且測試按照我的預期通過:
[TestFixture]
public class MoreThanNullableTests
{
public class AccountViewModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public MoreThanNullable<string> Test1 { get; set; }
public MoreThanNullable<string> Test2 { get; set; }
public MoreThanNullable<string> Test3 { get; set; }
}
[Test]
public void Tests()
{
var myClass = new AccountViewModel();
Assert.AreEqual(false, myClass.Test1.Instantiated);
myClass.Test1 = null;
Assert.AreEqual(true, myClass.Test1.Instantiated);
}
}
接下來,使用相同的視圖模型,我將其連接到我的REST服務上的POST,然后傳入以下JSON:
{
Name:"test",
Test1:null,
Test2:"test"
}
......一切都崩潰了。 Test1和Test3都沒有實例化! 顯然,我不希望Test3被實例化,但Test1仍未實例化是出乎意料的。 實際上,我無法區分我通過REST獲得和未獲得的屬性。 (注意:在我們的應用程序中,未設置和設置為null之間存在明顯差異)
我做錯了嗎? 或者這是Web API的正確行為?
** 更新 **
我可能沒有說清楚的是,我已經有效地復制了Nullable<T>
類來實現這一點,包括重載隱式運算符,如下所示:
public static implicit operator MoreThanNullable<T>(T value)
{
return new MoreThanNullable<T>(value);
}
在我的問題中,我似乎總是遺漏重要的東西......
為什么不起作用? 在您的JSON
{
Name:"test",
Test1:null,
Test2:"test"
}
Test1結束Test2是原始類型,但是你創建了自己的類型,它們應該映射到它們的屬性,因此它不再是原始的,而是一個復雜的對象。 所以你的JSON實際上也應該包含對象。 如果你改成它,它會工作
{
Name:"test",
Test1:{Instantiated:false, value: null},
Test2:{Instantiated:false, value: "test"},
}
因為現在它們是對象並且反序列化。 你的struct也有一個默認的空構造函數,如果它是一個帶有私有默認構造函數的類,它將無法再次運行。
現在,如何獲得像字符串這樣的原始類型來反序列化到自定義類型? 您可以使用自定義Web api操作過濾器執行此操作,並解析傳入的json並將其映射到OnActionExecuting中的對象。
編輯2
假設您正在使用newtonsoft的JSON.NET,您可以插入自定義JSON轉換器。 這將是Web api應用程序的全局變更,無需自定義過濾器。
public sealed class MoreThanNullableConverter : Newtonsoft.Json.JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof (MoreThanNullable<>);
}
public override bool CanWrite { get { return false; } }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// return a new MoreThanNullable instance with value
return Activator.CreateInstance(objectType, reader.Value);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
更改為webapiconfig.cs
var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
jsonFormatter.SerializerSettings.Converters.Add(new MoreThanNullableConverter());
我認為你已經陷入了對.net服務反序列化的共同問題
我總是看到WCF的這個問題,但我認為它也存在於json反序列化中
反序列化期間的.NET不執行構造函數,因此如果需要在反序列化后執行某些代碼,則必須添加一些代碼作為這些代碼
[OnDeserialized()]
internal void OnDeserializedMethod(StreamingContext context)
{
// ... logic here after deserialization
}
在該邏輯中,您應該完成缺少信息的私有字段。 必須根據值是否為null來設置hasValue字段。 實例化應該有一個私有字段與setter私有。 它應該建立在真正的公共價值觀上。 如果hasValue為true,則實例化顯然是正確的,否則怎么辦? 所以問題是,我們怎樣才能將hasvalue假錯,但實例化為真呢?
這是唯一一種無法用其他值確定值的情況,因此我們需要其他的東西。 使實例化公共的setter是最簡單的方法,但為了確保對象一致性,你應該在反序列化后檢查它以確保以前的對象規則...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.