簡體   English   中英

Web API - 檢測空賦值

[英]Web API - Detecting null assignment

我正在嘗試提出一種模式,可以檢測屬性何時設置為null。 類似於Nullable<T>類的東西,但更高級一些。 我們稱之為MoreThanNullable<T> 基本上我需要根據以下3種情況做一些不同的事情:

  1. 該物業從未設定過
  2. 該屬性設置為null
  3. 該屬性設置為T的實例。

我使用“實例化”屬性創建了自己的類來完成此操作,並且它都在測試場景中工作。 一些示例代碼:

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反序列化中

https://msdn.microsoft.com/en-us/library/system.runtime.serialization.ondeserializedattribute(v=vs.110).aspx

反序列化期間的.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM