简体   繁体   English

ServiceStack请求中的复杂数组

[英]Complex array in ServiceStack request

I am sending the following request parameters to my service; 我正在将以下请求参数发送到我的服务; among which, is the filter parameter which is a multidimensional array: 其中是filter参数,它是一个多维数组:

filter[0][field]:homeCountry
filter[0][data][type]:string
filter[0][data][value]:united s
page:2
start:200
limit:200
sort:homeCountry
dir:ASC

The querystring is encoded like so: 查询字符串的编码如下:

paymentratetrip.json?filter%5B0%5D%5Bfield%5D=homeCountry&filter%5B0%5D%5Bdata%5D%5Btype%5D=string&filter%5B0%5D%5Bdata%5D%5Bvalue%5D=united%20s&page=2&start=200&limit=200&sort=homeCountry&dir=AS

Currently, my C# request object looks like this: 当前,我的C#请求对象如下所示:

public class PaymentRateTripRequest
{    
    public int start { get; set; }
    public int limit { get; set; }
    public string sort { get; set; }
    public string dir { get; set; }
}

How can I modify my request object to receive the filter parameter which could be a multidimensional array? 如何修改我的请求对象以接收可能是多维数组的filter参数?

Note: I am using ServiceStack. 注意:我正在使用ServiceStack。

The only way I can think is to send the entire request object as a parameter to my method like so: 我能想到的唯一方法是将整个请求对象作为参数发送给我的方法,如下所示:

public object Get(PaymentRateTripRequest req)
{
    return _repository.GetAllRates(req.start, req.limit, req.sort, req.dir, this.Request.OriginalRequest);
}

But, this doesn't seem like the best solution. 但是,这似乎不是最好的解决方案。

Edit: this.Request.QueryString 编辑: this.Request.QueryString

this.Request.QueryString
{filter%5b0%5d%5bfield%5d=homeCountry&filter%5b0%5d%5bdata%5d%5btype%5d=string&filter%5b0%5d%5bdata%5d%5bvalue%5d=united+s&page=2&start=200&limit=200&sort=homeCountry&dir=ASC}
    [System.Web.HttpValueCollection]: {filter%5b0%5d%5bfield%5d=homeCountry&filter%5b0%5d%5bdata%5d%5btype%5d=string&filter%5b0%5d%5bdata%5d%5bvalue%5d=united+s&page=2&start=200&limit=200&sort=homeCountry&dir=ASC}
    base {System.Collections.Specialized.NameObjectCollectionBase}: {filter%5b0%5d%5bfield%5d=homeCountry&filter%5b0%5d%5bdata%5d%5btype%5d=string&filter%5b0%5d%5bdata%5d%5bvalue%5d=united+s&page=2&start=200&limit=200&sort=homeCountry&dir=ASC}
    _all: null
    _allKeys: {string[8]}
    AllKeys: {string[8]}

Edit: filter is still empty. 编辑: filter仍为空。

在此处输入图片说明

You should add a property with the filter to your DTO, such as below: 您应将带有过滤器的属性添加到DTO,例如:

public class PaymentRateTripRequest
{   
    public int page { get; set; }
    public int start { get; set; }
    public int limit { get; set; }
    public string sort { get; set; }
    public string dir { get; set; }

    public FilterField[] filter { get; set; }
}

public class FilterField
{
    public string field { get; set; }
    public Dictionary<string,object> data { get; set; }
}

This will allow you to add any number of fields to filter by, and by making the data property of the FilterField a Dictionary<string, object> you can add as many data properties as needed. 这将允许您添加任意数量的字段以进行过滤,并且通过将FilterFielddata属性设置为Dictionary<string, object> ,可以根据需要添加任意多个数据属性。

Then you can populate the filter parameter in your PaymentRateTripRequest using JSV format. 然后,您可以使用JSV格式在您的PaymentRateTripRequest填充filter参数。 You can learn about JSV format here . 您可以在这里了解JSV格式 JSV Format (ie JSON-like Separated Values) is a JSON inspired format that uses CSV-style escaping for the least overhead and optimal performance. JSV格式(即类似JSON的分隔值)是受JSON启发的格式,它使用CSV样式的转义以最小化开销并获得最佳性能。

paymentratetrip.json?filter=[{field:homeCountry,data:{type:string,value:"united s"}},{field:other,data:{type:int,value:34,special:true}}]&page=2&start=200&limit=200&sort=homeCountry&dir=ASC paymentratetrip.json?filter = [{field:homeCountry,data:{type:string,value:“ united s”}}},{field:other,data:{type:int,value:34,special:true}}] &页= 2&开始= 200&限= 200&排序= homeCountry&DIR = ASC

Then you can access the filter as a regular property on your request. 然后,您可以根据请求将过滤器作为常规属性进行访问。

Hope this helps. 希望这可以帮助。

This is an alternative solution that requires no changes to your client and therefore will accept the query string in the format you have currently: 这是一种替代解决方案,不需要更改您的客户端,因此将接受您当前具有的格式的查询字符串:

paymentratetrip.json?filter%5B0%5D%5Bfield%5D=homeCountry&filter%5B0%5D%5Bdata%5D%5Btype%5D=string&filter%5B0%5D%5Bdata%5D%5Bvalue%5D=united%20s&page=2&start=200&limit=200&sort=homeCountry&dir=AS paymentratetrip.json?过滤%5B0%5D%5Bfield%5D = homeCountry及过滤%5B0%5D%5Bdata%5D%5Btype%5D =串过滤%5B0%5D%5Bdata%5D%5Bvalue%5D =团结%20S&页= 2&开始= 200&限= 200排序= homeCountry&DIR = AS

The disadvantage of this method is that it's more code to maintain. 这种方法的缺点是需要维护更多的代码。 The JSV method is simpler. JSV方法更简单。

Request attribute to populate the filter from the querystring: 请求属性以从查询字符串填充过滤器:

We can use a ServiceStack filter to intercept the query string before it reaches the action method. 我们可以使用ServiceStack筛选器在查询字符串到达​​操作方法之前对其进行拦截。 It can then parse the custom filter format and populate the filter object of the DTO. 然后,它可以解析自定义过滤器格式并填充DTO的过滤器对象。

public class FilterAttribute : Attribute, IHasRequestFilter
{
    IHasRequestFilter IHasRequestFilter.Copy()
    {
        return this;
    }

    public int Priority { get { return int.MinValue; } }

    FilterField CreateOrUpdateField(ref Dictionary<string, FilterField> filter, string id)
    {
        if(filter.ContainsKey(id))
            return filter[id];

        var field = new FilterField { Data = new Dictionary<string, object>() };
        filter.Add(id, field);

        return field;
    }

    public void RequestFilter(IRequest req, IResponse res, object requestDto)
    {
        var filteredDto = requestDto as IFilter;
        if(filteredDto == null)
            return;

        const string fieldPattern = @"filter\[([A-Za-z0-9]+)\]\[field\]";
        const string dataPattern = @"filter\[([A-Za-z0-9]+)\]\[data\]\[([A-Za-z0-9]+)\]";

        Dictionary<string, FilterField> filter = new Dictionary<string, FilterField>();
        foreach(var property in req.QueryString.AllKeys)
        {
            Match match = Regex.Match(property, fieldPattern, RegexOptions.IgnoreCase);
            if(match.Success)
            {
                // Field
                var id = match.Groups[1].Value;
                var field = CreateOrUpdateField(ref filter, id);
                field.Field = req.QueryString[property];

            } else {
                match = Regex.Match(property, dataPattern, RegexOptions.IgnoreCase);
                if(match.Success)
                {
                    // Data value
                    var id = match.Groups[1].Value;
                    var keyName = match.Groups[2].Value;
                    var field = CreateOrUpdateField(ref filter, id);
                    if(!field.Data.ContainsKey(keyName))
                        field.Data.Add(keyName, req.QueryString[property]);
                }
            }
        }

        filteredDto.Filter = filter.Values.ToArray();
    }
}

You will also need to add this interface and FilterField class: 您还需要添加此接口和FilterField类:

public class FilterField
{
    public string Field { get; set; }
    public Dictionary<string,object> Data { get; set; }
}

public interface IFilter
{
    FilterField[] filter { get; set; }
}

Then you simply need to update your DTO so it looks like this: 然后,您只需要更新DTO,使其看起来像这样:

[Route("/paymentratetrip", "GET"]
[Filter]
public class PaymentRateTripRequest : IFilter
{   
    public int page { get; set; }
    public int start { get; set; }
    public int limit { get; set; }
    public string sort { get; set; }
    public string dir { get; set; }

    public FilterField[] filter { get; set; }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM