簡體   English   中英

解析AspNet Core中的空查詢參數

[英]Parse null query parameters in AspNet Core

如何在AspNet Core中處理空查詢參數?

假設我們有一個查詢?key1=foo1&key1=foo2&key2=&key3=null

在解析它時,我希望在解析此URL時會有某種類型的Dictionary>:

  • key1:[“foo1”,“foo2”]這應該是同一個鍵下的多個值
  • key2:[“”]這應該是一個空字符串
  • key3:[“null”]這應該是一個字符串,據我所知,URL中的null只是一個文字

我的問題是:我應該如何處理空查詢參數?

注意:我可能根本不定義查詢參數並假設不存在的查詢參數為空。 但我認為如果需要,null應該被視為顯式查詢參數中的有效值。

根據這個帖子: 如何在HTTP查詢字符串中發送NULL? 標准是傳遞編碼的空值:請參閱https://www.w3schools.com/tags/ref_urlencode.asp

所以如果我想傳遞一個空值,我應該做類似的事情: ?key1=foo1&key1=foo2&key2=&key3=%00

問題是我不知道如何解碼這個,以便%00被解析為空值。

我嘗試過以下方法:

public Dictionary<string, List<string>> CreateFromQuery(string query)
{
    if (query == null)
    {
        return new Dictionary<string, List<string>>();
    }

    var queryDictionary = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(query);

    var result = queryDictionary.ToDictionary(kv => kv.Key, kv => kv.Value.ToList());
    return result;
}

%00轉換為"\\0"字符串,而不是null

做一個var decodedQuery= HttpUtility.UrlDecode(query); 之前似乎也沒有任何區別。

UPDATE1 :在Kacper和Chris Pratt的評論之后(謝謝你們)我現在考慮了Kacper的第二個建議,因為我覺得有一個場景,請求者想要區分空查詢參數,空查詢參數和不存在的查詢參數。

所以這是我目前的實施:

public class QueryParserFactory
    : IQueryParseable
{
    public Dictionary<string, List<string>> CreateFromQuery(string query)
    {
        if (query == null)
        {
            return new Dictionary<string, List<string>>();
        }

        var queryDecoded = HttpUtility.UrlDecode(query);

        var queryDictionary = QueryHelpers.ParseQuery(queryDecoded);

        var result = queryDictionary
            .ToDictionary(
                kv => kv.Key,
                kv => kv.Value.Select(s => s == "\0" ? null : s).ToList());
        return result;
    }
}

如果有人感興趣,下面有我能想到的所有單元測試

public static class CreateFromQueryTests
{
    public class Given_An_Empty_Query_String_When_Creating_From_A_Query
        : Given_When_Then_Test
    {
        private QueryParserFactory _sut;
        private Dictionary<string, List<string>> _result;

        protected override void Given()
        {
            _sut = new QueryParserFactory();
        }

        protected override void When()
        {
            _result = _sut.CreateFromQuery("");
        }

        [Fact]
        public void Then_It_Should_Return_A_Valid_Result()
        {
            _result.Should().NotBeNull();
        }

        [Fact]
        public void Then_It_Should_Not_Have_Any_Key()
        {
            _result.Keys.Count.Should().Be(0);
        }

        [Fact]
        public void Then_It_Should_Not_Have_Any_Items_In_Dictionary()
        {
            _result.Count.Should().Be(0);
        }
    }

    public class Given_A_Query_String_With_Empty_Values_When_Creating_From_A_Query
        : Given_When_Then_Test
    {
        private QueryParserFactory _sut;
        private Dictionary<string, List<string>> _result;
        private List<string> _expectedValueForKey1;
        private List<string> _expectedValueForKey2;

        protected override void Given()
        {
            _expectedValueForKey1 = new List<string>
            {
                string.Empty
            };

            _expectedValueForKey2 = new List<string>
            {
                string.Empty
            };

            _sut = new QueryParserFactory();
        }

        protected override void When()
        {
            _result = _sut.CreateFromQuery("?key1=&key2=");
        }

        [Fact]
        public void Then_It_Should_Return_A_Valid_Result()
        {
            _result.Should().NotBeNull();
        }

        [Fact]
        public void Then_It_Should_Have_Key_For_All_Fulfilled_Parameters()
        {
            _result.Keys.Count.Should().Be(2);
        }

        [Fact]
        public void Then_It_Should_Have_Empty_Value_For_The_First_Key_Parameter()
        {
            _result["key1"].Should().BeEquivalentTo(_expectedValueForKey1);
        }

        [Fact]
        public void Then_It_Should_Have_Empty_Value_For_The_Second_Key_Parameter()
        {
            _result["key2"].Should().BeEquivalentTo(_expectedValueForKey2);
        }
    }

    public class Given_A_Query_String_With_Single_Values_When_Creating_From_A_Query
        : Given_When_Then_Test
    {
        private QueryParserFactory _sut;
        private Dictionary<string, List<string>> _result;
        private List<string> _expectedValueForKey1;
        private List<string> _expectedValueForKey2;

        protected override void Given()
        {
            _expectedValueForKey1 = new List<string>()
            {
                "value1"
            };

            _expectedValueForKey2 = new List<string>()
            {
                "value2"
            };

            _sut = new QueryParserFactory();
        }

        protected override void When()
        {
            _result = _sut.CreateFromQuery("?key1=value1&key2=value2");
        }

        [Fact]
        public void Then_It_Should_Return_A_Valid_Result()
        {
            _result.Should().NotBeNull();
        }

        [Fact]
        public void Then_It_Should_Have_Key_For_All_Fulfilled_Parameters()
        {
            _result.Keys.Count.Should().Be(2);
        }

        [Fact]
        public void Then_It_Should_Have_The_Correct_Multiple_Values_For_Keys_With_Multiple_Parameters()
        {
            _result["key1"].Should().BeEquivalentTo(_expectedValueForKey1);
        }

        [Fact]
        public void Then_It_Should_Have_The_Correct_Single_Value_For_Keys_With_One_Parameter()
        {
            _result["key2"].Should().BeEquivalentTo(_expectedValueForKey2);
        }

        [Fact]
        public void Then_It_Should_Not_Have_Entries_For_Inexistent_Parameters()
        {
            _result.TryGetValue("key3", out List<string> _).Should().BeFalse();
        }
    }

    public class Given_A_Query_String_With_Multiple_Values_For_The_Same_Key_When_Creating_From_A_Query
        : Given_When_Then_Test
    {
        private QueryParserFactory _sut;
        private Dictionary<string, List<string>> _result;
        private List<string> _expectedValueForKey1;

        protected override void Given()
        {
            _expectedValueForKey1 = new List<string>()
            {
                "value1",
                "value2",
                "value3"
            };

            _sut = new QueryParserFactory();
        }

        protected override void When()
        {
            _result = _sut.CreateFromQuery("?key1=value1&key1=value2&key1=value3");
        }

        [Fact]
        public void Then_It_Should_Return_A_Valid_Result()
        {
            _result.Should().NotBeNull();
        }

        [Fact]
        public void Then_It_Should_Have_Only_One_Key()
        {
            _result.Keys.Count.Should().Be(1);
        }

        [Fact]
        public void Then_It_Should_Have_The_Correct_Multiple_Values_For_Keys_With_Multiple_Parameters()
        {
            _result["key1"].Should().BeEquivalentTo(_expectedValueForKey1);
        }

        [Fact]
        public void Then_It_Should_Not_Have_Entries_For_Inexistent_Parameters()
        {
            _result.TryGetValue("key2", out List<string> _).Should().BeFalse();
        }
    }

    public class Given_A_Query_String_With_Non_Url_Encoded_Null_Values_When_Creating_From_A_Query
        : Given_When_Then_Test
    {
        private QueryParserFactory _sut;
        private Dictionary<string, List<string>> _result;
        private List<string> _expectedValueForKey1;
        private List<string> _expectedValueForKey2;

        protected override void Given()
        {
            _expectedValueForKey1 = new List<string>()
            {
                "null"
            };

            _expectedValueForKey2 = new List<string>()
            {
                "null"
            };

            _sut = new QueryParserFactory();
        }

        protected override void When()
        {
            _result = _sut.CreateFromQuery("?key1=null&key2=null");
        }

        [Fact]
        public void Then_It_Should_Return_A_Valid_Result()
        {
            _result.Should().NotBeNull();
        }

        [Fact]
        public void Then_It_Should_Have_Key_For_All_Fulfilled_Parameters()
        {
            _result.Keys.Count.Should().Be(2);
        }

        [Fact]
        public void Then_It_Should_Have_A_Null_Literal_For_The_First_Parameter()
        {
            _result["key1"].Should().BeEquivalentTo(_expectedValueForKey1);
        }

        [Fact]
        public void Then_It_Should_Have_A_Null_Literal_For_The_Second_Parameter()
        {
            _result["key2"].Should().BeEquivalentTo(_expectedValueForKey2);
        }

        [Fact]
        public void Then_It_Should_Not_Have_Entries_For_Inexistent_Parameters()
        {
            _result.TryGetValue("key3", out List<string> _).Should().BeFalse();
        }
    }

    public class Given_A_Query_String_With_Url_Encoded_Null_Values_When_Creating_From_A_Query
        : Given_When_Then_Test
    {
        private QueryParserFactory _sut;
        private Dictionary<string, List<string>> _result;
        private List<string> _expectedValueForKey1;
        private List<string> _expectedValueForKey2;

        protected override void Given()
        {
            _expectedValueForKey1 = new List<string>()
            {
                null
            };

            _expectedValueForKey2 = new List<string>()
            {
                null
            };

            _sut = new QueryParserFactory();
        }

        protected override void When()
        {
            _result = _sut.CreateFromQuery("?key1=%00&key2=%00");
        }

        [Fact]
        public void Then_It_Should_Return_A_Valid_Result()
        {
            _result.Should().NotBeNull();
        }

        [Fact]
        public void Then_It_Should_Have_Key_For_All_Fulfilled_Parameters()
        {
            _result.Keys.Count.Should().Be(2);
        }

        [Fact]
        public void Then_It_Should_Have_A_Null_Literal_For_The_First_Parameter()
        {
            _result["key1"].Should().BeEquivalentTo(_expectedValueForKey1);
        }

        [Fact]
        public void Then_It_Should_Have_A_Null_Literal_For_The_Second_Parameter()
        {
            _result["key2"].Should().BeEquivalentTo(_expectedValueForKey2);
        }

        [Fact]
        public void Then_It_Should_Not_Have_Entries_For_Inexistent_Parameters()
        {
            _result.TryGetValue("key3", out List<string> _).Should().BeFalse();
        }
    }
}

我找不到任何內置的東西來制作它。 所以我有兩種選擇,取決於適合你的選擇。

1。

public Dictionary<string, List<string>> CreateFromQuery(string query)
{
    if (query == null)
    {
        return new Dictionary<string, List<string>>();
    }

    var queryDictionary = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(query);

    var result = queryDictionary
       .ToDictionary(
           kv => kv.Key, 
           kv => kv.Value.Select(s => s.Trim("\0")).ToList()); //There you will have String.Empty
    return result;
}

2。

public Dictionary<string, List<string>> CreateFromQuery(string query)
{
    if (query == null)
    {
        return new Dictionary<string, List<string>>();
    }

    var queryDictionary = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(query);

    var result = queryDictionary
       .ToDictionary(
           kv => kv.Key, 
           kv => kv.Value.Select(s => s == "\0" ? null : s).ToList()); //There you will have nulls
    return result;
}

傳遞null的方法是根本不傳遞值,或者完全排除鍵,即:

?key1=foo1&key1=foo2&key2=&key3=

或者干脆:

?key1=foo1&key1=foo2&key2=

對於你的key2參數,你應該知道沒有辦法傳遞一個空字符串。 ASP.NET Core會將其解釋為null值。 如果你有一個實際上不應該為null的字符串屬性(即在這種情況下你希望它總是一個空字符串),那么你可以通過自定義getter處理它。

private string key2;
public string Key2
{
    get => key2 ?? string.Empty;
    set => key2 = value;
}

然后,在將其設置為空值的情況下,它將實現為空字符串。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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