c#有一种序列化到UrlEncoded的方法吗?

时间:2016-03-24 13:33:36

标签: c# facebook-graph-api serialization urlencode

我想使用facebook的API,我觉得很难将对象转换为urlEncoded。 所以,现在我有类似的东西:

string postData = JsonConvert.SerializeObject(req);

            postData = postData.Replace(@"\", "");
            postData = HttpUtility.UrlEncode(postData);

            byte[] data = Encoding.UTF8.GetBytes(postData);

            string facebookUrl = "https://graph.facebook.com/v2.5/";

问题是facebook不接受jsons但是UrlEncoded数据,如果我错了,就会纠正我。

所以,我非常确定将对象转换为UrlEncoded字符串在.Net 4.5.1中是不可能的,因为我试图使用这些问题的一些答案,这些问题在此之前它们并不适用于我。

例如:

var result = new List<string>();
            foreach (var property in TypeDescriptor.GetProperties(req))
            {
                result.Add(property.Name + "=" + property.GetValue(req));
            }

            postData = string.Join("&", result);

但根本没有定义.Name.GetValue

希望得到一些帮助,TIA。

我使用的对象:

internal sealed class FacebookValidationRequest
{
    public string access_token;
    public fbReq[] batch;
    public string method;
    public string format;
    public int pretty;
    public int suppress_http_code;
    public string debug;

    public FacebookValidationRequest(string appId, string userToken)
    {
        access_token = userToken;
        batch = new[]
        {
            //test code
            new fbReq("GET", "me"),
            new fbReq("GET", "me/friends?limit=50") //,
            //new fbReq("GET", "app?access_token=" + userToken)
        };
        method = "post";
        format = "json";
        pretty = 0;
        suppress_http_code = 1;
        debug = "all";
    }

}

internal sealed class fbReq
{
    public string method;
    public string relative_url;

    public fbReq(string m, string url)
    {
        method = m;
        relative_url = url;
    }
}

FacebookValidationRequest req = new FacebookValidationRequest(appToken, userToken);

此外,还获取了facebook debugger site

的令牌

facebook在编码后想要反对的样子:

  

的access_token =即为MyToken&安培;批次=%5B%7B%22method%22%3A%22GET%22%2C%20%22relative_url%22%3A%22me%22%7D%2C%7B%22method%22%3A% 22GET%22%2C%20%22relative_url%22%3A%22me%2Ffriends%3Flimit%3D50%22%7D%5D&安培;调试=所有&安培;字段= ID%2Cname&安培;格式= JSON&安培;方法=交&安培;漂亮= 0&安培; suppress_http_code = 1

1 个答案:

答案 0 :(得分:1)

在我看来,最简单的方法是使用Attributes来描述你的属性,就像.Net Json的DataContract系统一样。基本上,您为要序列化的每个属性分配一个属性,并使该属性包含将其序列化为的名称。我不认为你想要实际编写自己的DataContractSerializer,所以简单地创建你自己的Property类和使用反射的简单序列化器可能更容易。

属性类:

[AttributeUsage(AttributeTargets.Property)]
public sealed class UrlEncodeAttribute : System.Attribute
{
    public String Name { get; private set; }

    public UrlEncodeAttribute(String name)
    {
        this.Name = name;
    }
}

然后,要应用于您的数据类......将属性放在所有属性上:

internal sealed class FacebookValidationRequest
{
    [UrlEncodeAttribute("access_token")]
    public String AccessToken { get; set; }
    [UrlEncodeAttribute("method")]
    public String Method { get; set; }
    [UrlEncodeAttribute("format")]
    public String Format { get; set; }
    [UrlEncodeAttribute("pretty")]
    public Int32 Pretty { get; set; }
    [UrlEncodeAttribute("suppress_http_code")]
    public Int32 SuppressHttpCode { get; set; }
    [UrlEncodeAttribute("debug")]
    public string Debug { get; set; }

    public fbReq[] Batch { get; set; }

    [UrlEncodeAttribute("batch")]
    public String BatchString
    {
        get
        {
            // put your json serialization code here to return
            // the contents of Batch as json string.
        }
    }
}

如您所见,Batch 拥有UrlEncodeAttribute,而其字符串代表BatchString 确实。它的get是序列化程序调用的,因此您可以将转换代码放在那里。

另请注意,由于您在属性中提供的文本名称,您的属性不需要具有您在序列化中实际获得的名称,在我看来,它看起来很多更清洁。 C#自己对xml和json的序列化工作方式相同。

现在,让我们看一下实际的序列化,使用反射来获取这些属性:

public static String Serialize(Object obj, Boolean includeEmpty)
{
    // go over the properties, see which ones have a UrlEncodeAttribute, and process them.
    StringBuilder sb = new StringBuilder();
    PropertyInfo[] properties = obj.GetType().GetProperties();
    foreach (PropertyInfo p in properties)
    {
        object[] attrs = p.GetCustomAttributes(true);
        foreach (Object attr in attrs)
        {
            if (attr is UrlEncodeAttribute)
            {
                UrlEncodeAttribute fldAttr = ((UrlEncodeAttribute)attr);
                String objectName = fldAttr.Name;
                Object objectDataObj = p.GetValue(obj, null);
                String objectData = objectDataObj == null ? String.Empty : objectDataObj.ToString();
                if (!String.IsNullOrEmpty(objectData) || includeEmpty)
                {
                    objectData = HttpUtility.UrlEncode(objectData);
                    objectName= HttpUtility.UrlEncode(objectName);
                    if (sb.Length > 0)
                        sb.Append("&");
                    sb.Append(objectName).Append("=").Append(objectData);
                }
                break; // Only handle one UrlEncodeAttribute per property.
            }
        }
    }
    return sb.ToString();
}

可以通过在UrlEncodeAttribute类中包含序列化方法属性(可能最好使用枚举)来实现更高级的版本,因此您可以简单地指定使用json动态序列化数组。您显然需要将实际的json转换器放入Serialize函数中。我认为在虚拟属性上使用getter,因为准备方法更简单,这里。

显然,调用它只是这样:(假设此处Serialize()函数位于名为UrlEncodeSerializer的类中

FacebookValidationRequest fbreq = new FacebookValidationRequest();
// fill your data into fbreq here
// ...

// includeEmpty is set to true for testing here, but normally in
// UrlEncoded any missing property is just seen as empty anyway, so
// there should be no real difference.
String serialized = UrlEncodeSerializer.Serialize(fbreq, true);