c# 是否有序列化为 UrlEncoded 的方法?
c# is there a method to serialize to UrlEncoded?
我想使用 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&batch=%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&debug=all&fields=id%2Cname&format=json&method=post&pretty=0&suppress_http_code=1
在我看来,最简单的方法是使用属性来描述您的属性,就像 .Net Json 的 DataContract
系统所做的那样。基本上,您为每个要序列化的 属性 分配一个属性,并使该属性包含将其序列化为的名称。不过,我认为您不想陷入实际编写自己的 DataContractSerializer 的混乱之中,因此简单地创建自己的 属性 class 和使用反射的简单序列化程序可能更容易。
属性class:
[AttributeUsage(AttributeTargets.Property)]
public sealed class UrlEncodeAttribute : System.Attribute
{
public String Name { get; private set; }
public UrlEncodeAttribute(String name)
{
this.Name = name;
}
}
然后,应用于您的数据class...将属性放在所有属性上:
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)
{
UrlEncodeAttribute fldAttr = attr as UrlEncodeAttribute;
if (attr == null)
continue;
String objectName = fldAttr.Name;
Object objectDataObj = p.GetValue(obj, null);
String objectData = objectDataObj == null ? String.Empty : objectDataObj.ToString();
if (objectData.Length > 0 || 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 class 中包含序列化方法 属性 来实现(最好使用枚举来完成),因此您可以简单地指定序列化数组即时使用 json。您显然需要将实际的 json 转换器放入 Serialize 函数中。我认为在虚拟 属性 上使用 getter 作为准备方法更简单,在这里。
显然,调用它很简单:(假设这里的 Serialize()
函数在一个名为 UrlEncodeSerializer
的 class 中)
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);
我想使用 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&batch=%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&debug=all&fields=id%2Cname&format=json&method=post&pretty=0&suppress_http_code=1
在我看来,最简单的方法是使用属性来描述您的属性,就像 .Net Json 的 DataContract
系统所做的那样。基本上,您为每个要序列化的 属性 分配一个属性,并使该属性包含将其序列化为的名称。不过,我认为您不想陷入实际编写自己的 DataContractSerializer 的混乱之中,因此简单地创建自己的 属性 class 和使用反射的简单序列化程序可能更容易。
属性class:
[AttributeUsage(AttributeTargets.Property)]
public sealed class UrlEncodeAttribute : System.Attribute
{
public String Name { get; private set; }
public UrlEncodeAttribute(String name)
{
this.Name = name;
}
}
然后,应用于您的数据class...将属性放在所有属性上:
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)
{
UrlEncodeAttribute fldAttr = attr as UrlEncodeAttribute;
if (attr == null)
continue;
String objectName = fldAttr.Name;
Object objectDataObj = p.GetValue(obj, null);
String objectData = objectDataObj == null ? String.Empty : objectDataObj.ToString();
if (objectData.Length > 0 || 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 class 中包含序列化方法 属性 来实现(最好使用枚举来完成),因此您可以简单地指定序列化数组即时使用 json。您显然需要将实际的 json 转换器放入 Serialize 函数中。我认为在虚拟 属性 上使用 getter 作为准备方法更简单,在这里。
显然,调用它很简单:(假设这里的 Serialize()
函数在一个名为 UrlEncodeSerializer
的 class 中)
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);