C# 在AspNet内核中解析空查询参数

C# 在AspNet内核中解析空查询参数,c#,http,url,asp.net-core,query-parameters,C#,Http,Url,Asp.net Core,Query Parameters,如何在AspNet核心中处理空查询参数 假设我们有一个问题 ?key1=foo1&key1=foo2&key2=&key3=null 在解析该URL时,我希望在解析该URL时得到某种字典>,如: 键1:[“foo1”,“foo2”]这应该是同一键下的多个值 键2:[“”]这应该是一个空字符串 key3:[“null”]这应该是一个字符串,据我所知,URL中的null只是一个文本 我的问题是:我应该如何处理空查询参数 注意:我不能简单地定义查询参数并假设不存在的查询参数为空。但我认为,如果需要

如何在AspNet核心中处理空查询参数

假设我们有一个问题
?key1=foo1&key1=foo2&key2=&key3=null

在解析该URL时,我希望在解析该URL时得到某种字典>,如:

  • 键1:[“foo1”,“foo2”]这应该是同一键下的多个值
  • 键2:[“”]这应该是一个空字符串
  • key3:[“null”]这应该是一个字符串,据我所知,URL中的null只是一个文本
我的问题是:我应该如何处理空查询参数

注意:我不能简单地定义查询参数并假设不存在的查询参数为空。但我认为,如果需要,null应该被视为显式查询参数中的有效值

根据这条线索: 标准是传递编码的空值:请参阅

因此,如果我想传递一个空值,我应该执行如下操作:
?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;
}
如果有人感兴趣,下面是我能想到的所有单元测试:

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();
        }
    }
}
公共静态类CreateFromQueryTests
{
当从查询创建时,公共类给出了一个空查询字符串
:给定\u时间\u然后\u测试
{
私人QueryParserFactory;
私有字典(private Dictionary)结果;;
给定的受保护覆盖无效()
{
_sut=新的QueryParserFactory();
}
受保护的覆盖在()时无效
{
_结果=_sut.CreateFromQuery(“”);
}
[事实]
public void然后\u It \u应该\u返回\u有效的\u结果()
{
_result.Should().NotBeNull();
}
[事实]
public void则\u It \u应该\u没有\u任何\u密钥()
{
_result.Keys.Count.Should()为(0);
}
[事实]
public void则\u It \u不应\u在\u Dictionary()中有\u任何\u项
{
_result.Count.Should()为(0);
}
}
当从查询创建时,公共类给出了带有空值的查询字符串
:给定\u时间\u然后\u测试
{
私人QueryParserFactory;
私有字典(private Dictionary)结果;;
私有列表_expectedValueForKey1;
私有列表_expectedValueForKey2;
给定的受保护覆盖无效()
{
_expectedValueForKey1=新列表
{
字符串。空
};
_expectedValueForKey2=新列表
{
字符串。空
};
_sut=新的QueryParserFactory();
}
受保护的覆盖在()时无效
{
_结果=_sut.CreateFromQuery(“?key1=&key2=”);
}
[事实]
public void然后\u It \u应该\u返回\u有效的\u结果()
{
_result.Should().NotBeNull();
}
[事实]
public void然后\u It \u应该\u有\u Key \u用于\u所有\u满足的\u参数()
{
_result.Keys.Count.Should()为(2);
}
[事实]
public void则\u It \u应该\u有\u空\u值\u作为\u First \u Key \u参数()
{
_结果[“key1”]应()与(_expectedValueForKey1)相等;
}
[事实]
public void则\u It \u应该\u有\u空\u值\u作为\u第二个\u键\u参数()
{
_结果[“key2”]应()与(_expectedValueForKey2)相等;
}
}
当从查询创建时,公共类给出了带有单个值的查询字符串
:给定\u时间\u然后\u测试
{
私人QueryParserFactory;
私有字典(private Dictionary)结果;;
私有列表_expectedValueForKey1;
私有列表_expectedValueForKey2;
给定的受保护覆盖无效()
{
_expectedValueForKey1=新列表()
{
“价值1”
};
_expectedValueForKey2=新列表()
{
“价值2”
};
_sut=新的QueryParserFactory();
}
受保护的覆盖在()时无效
{
_结果=_sut.CreateFromQuery(“?key1=value1&key2=value2”);
}
[事实]
public void然后\u It \u应该\u返回\u有效的\u结果()
{
_result.Should().NotBeNull();
}
[事实]
public void然后\u It \u应该\u有\u Key \u用于\u所有\u满足的\u参数()
{
_result.Keys.Count.Should()为(2);
}
[事实]
public void则\u It \u应该\u具有\u正确的\u多个\u值\u用于\u键\u和\u多个\u参数()
{
_结果[“key1”]应()与(_expectedValueForKey1)相等;
}
[事实]
public void则\u It \u应该\u具有\u正确的\u单个\u值\u以及\u一个\u参数()
{
_结果[“key2”]应()与(_expectedValueForKey2)相等;
}
[事实]
public void则\u It \u不应该\u有\u条目\u用于\u不存在\u参数()
{
_result.TryGetValue(“key3”,out List u2;).Should().BeFalse();
}
}
公共类给定了\u查询\u字符串\u和\u多个\u值\u当\u从\u查询创建\u时,为\u同一\u键\u
:给定\u时间\u然后\u测试
{
私人QueryParserFactory;
私有字典(private Dictionary)结果;;
私有列表_expectedValueForKey1;
给定的受保护覆盖无效()
{
_expectedValueForKey1=新列表()
{
“价值1”,
“价值2”,
“价值3”
};
_sut=新的QueryParserFactory();
}
受保护的覆盖在()时无效
{
_结果=_sut.CreateFromQuery(“?key1=value1&key1=value2&key1=value3”);
}
[事实]
public void然后\u It \u应该\u返回\u有效的\u结果()
{
_result.Should().NotBeNull();
}
[事实]
那公共空间呢_
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();
        }
    }
}
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;
}
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;
}
?key1=foo1&key1=foo2&key2=&key3=
?key1=foo1&key1=foo2&key2=
private string key2;
public string Key2
{
    get => key2 ?? string.Empty;
    set => key2 = value;
}