In c# convert anonymous type into key/value array?

前端 未结 9 1444
囚心锁ツ
囚心锁ツ 2020-12-04 23:28

I have the following anonymous type:

new {data1 = \"test1\", data2 = \"sam\", data3 = \"bob\"}

I need a method that will take this in, and

相关标签:
9条回答
  • 2020-12-04 23:44

    Building on @GWB's suggestion of using a RouteValueDictionary, I wrote this recursive function to support nested anonymous types, prefixing those nested parameters by their parents' keys.

    public static string EncodeHtmlRequestBody(object data, string parent = null) {
        var keyValuePairs = new List<string>();
        var dict = new RouteValueDictionary(data);
    
        foreach (var pair in dict) {
            string key = parent == null ? pair.Key : parent + "." + pair.Key;
            var type = pair.Value.GetType();
            if (type.IsPrimitive || type == typeof(decimal) || type == typeof(string)) {
                keyValuePairs.Add(key + "=" + Uri.EscapeDataString((string)pair.Value).Replace("%20", "+"));
            } else {
                keyValuePairs.Add(EncodeHtmlRequestBody(pair.Value, key));
            }
        }
    
        return String.Join("&", keyValuePairs);
    }
    

    Example usage:

    var data = new {
        apiOperation = "AUTHORIZE",
        order = new {
            id = "order123",
            amount = "101.00",
            currency = "AUD"
        },
        transaction = new {
            id = "transaction123"
        },
        sourceOfFunds = new {
            type = "CARD",
            provided = new {
                card = new {
                    expiry = new {
                        month = "1",
                        year = "20"
                    },
                    nameOnCard = "John Smith",
                    number = "4444333322221111",
                    securityCode = "123"
                }
            }
        }
    };
    
    string encodedData = EncodeHtmlRequestBody(data);
    

    encodedData becomes:

    "apiOperation=AUTHORIZE&order.id=order123&order.amount=101.00&order.currency=AUD&transaction.id=transaction123&sourceOfFunds.type=CARD&sourceOfFunds.provided.card.expiry.month=1&sourceOfFunds.provided.card.expiry.year=20&sourceOfFunds.provided.card.nameOnCard=John+Smith&sourceOfFunds.provided.card.number=4444333322221111&sourceOfFunds.provided.card.securityCode=123"

    Hope this helps someone else in a similar situation.

    Edit: As DrewG pointed out, this doesn't support arrays. To properly implement support for arbitrarily nested arrays with anonymous types would be non-trivial, and as none of the APIs I've used have accepted arrays either (I'm not sure there's even a standardised way of serialising them with form encoding), I'll leave that to you folks if you need to support them.

    0 讨论(0)
  • 2020-12-04 23:50

    There is a built-in method of converting anonymous objects to dictionaries:

    HtmlHelper.AnonymousObjectToHtmlAttributes(yourObj)
    

    It also returns RouteValueDictionary. Note that it's static

    0 讨论(0)
  • 2020-12-04 23:50

    It is too late but anyway I would add this for a more robust solution. The ones I see here have some kind of problems (like they wouldn't work right with say DateTime). For that reason, I suggest first converting to a json (Newtonsoft Json.Net):

    var data = new {data1 = "test1", data2 = "sam", data3 = "bob"};
    
    var result = string.Join("&",
                JsonConvert.DeserializeObject<Dictionary<string, string>>(
                JsonConvert.SerializeObject(data))
                .Select(x => $"{x.Key}={x.Value}")
            );
    
    0 讨论(0)
提交回复
热议问题