当POST
请求时,RestSharp
可以非常简单的实现application/x-www-form-urlencoded
、form-data
等方式的请求,对于application/json
其也有着比较好的支持,对于application/xml
方式,如果请求实体属性与xml
格式定义完全一致那也是没问题的。
通常情况下,上述情况已经可以满足我们大部分的需求,但是,却可能存在这些情况
- Json序列化不一致
- Xml序列化不一致
- 服务端要你传递一段按指定格式组织的字符串(常见的RPC请求)
- 服务端要你传递byte数组(这个数组有可能是经过处理的,比如加密)
- ……
你可以在这里找到RestSharp
默认支持的序列化定义。你也可以通过RestClient.UseSerializer
来替换对应的序列化类,其内部通过RestSharp.DataFormat
来判断如何替换,所以如果默认的Json
或Xml
序列化不满足你的业务需求时,你可以自定义IRestSerializer
来实现自己的序列化实现。
当然,自定义IRestSerializer
只能解决序列化问题,不能解决指定格式字符串或byte数组的问题。对于Json
和Xml
之外的数据,通过源代码Http.WriteRequestBody
using (var requestStream = webRequest.GetRequestStream())
{
if (HasFiles || AlwaysMultipartFormData)
WriteMultipartFormData(requestStream);
else if (RequestBodyBytes != null)
requestStream.Write(RequestBodyBytes, 0, RequestBodyBytes.Length);
else if (RequestBody != null)
WriteStringTo(requestStream, RequestBody);
}
以及RestRequestExtensions.AddBody
的关键代码
if (!http.AlwaysMultipartFormData && !http.Files.Any())
{
var val = value;
if (val is byte[] bytes)
http.RequestBodyBytes = bytes;
else
http.RequestBody = value.ToString();
}
可以发现通过指定当前请求格式为DataFormat.None
if (body.DataFormat == DataFormat.None)
http.AddBody(body.ContentType, body.Name, body.Value);
可以解决上述直接传递数据的问题,而这个枚举只能通过Parameter.DataFormat
来指定,在之后顺藤摸瓜,可以发现只有RestRequest.AddParameter
或RestRequest.AddOrUpdateParameter
这两个方法才有Parameter
参数,所以最终我们只需要通过如下代码来构建RestRequest
即可
var request = new RestRequest(url, Method.POST);
//这里假设不符合默认的xml序列化情况
//其它json,数组,自定义格式字符串也只要替换contentType和data即可
var contentType = "application/xml";
var data = "<root></root>";
request.AddParameter(new Parameter
{
ContentType = contentType,
Type = ParameterType.RequestBody,
DataFormat = DataFormat.None,
Value = data,
Name = ""
});
最后,顺便贴个基于上述内容实现的亿美软通发短信功能代码,你可以通过这里获取亿美软通发短信的Demo及文档,当然这里我只是简单实现了单个短信发送以及批量发送两个功能,方法中用到的AESHelper
可见此处。
/// <summary>
/// 短信接口
/// </summary>
public interface ISms
{
/// <summary>
/// 发送单条短信
/// </summary>
/// <param name="mobile"></param>
/// <param name="content"></param>
/// <param name="bizId"></param>
/// <param name="sendTime"></param>
/// <returns></returns>
bool SendMessage(string mobile, string content, string bizId = null, DateTime? sendTime = null);
/// <summary>
/// 发送单条短信
/// </summary>
/// <param name="mobile"></param>
/// <param name="content"></param>
/// <param name="bizId"></param>
/// <param name="sendTime"></param>
/// <returns></returns>
Task<bool> SendMessageAsync(string mobile, string content, string bizId = null, DateTime? sendTime = null);
/// <summary>
/// 批量发送短信
/// </summary>
/// <param name="content"></param>
/// <param name="mobiles"></param>
/// <param name="bizIds">该值要么为null,要么Count要与mobiles的Count一致,否则会引发异常</param>
/// <param name="sendTime"></param>
/// <returns></returns>
bool SendMessageBatch(string content, IList<string> mobiles, IList<string> bizIds = null, DateTime? sendTime = null);
/// <summary>
/// 批量发送短信
/// </summary>
/// <param name="content"></param>
/// <param name="mobiles"></param>
/// <param name="bizIds">该值要么为null,要么Count要与mobiles的Count一致,否则会引发异常</param>
/// <param name="sendTime"></param>
/// <returns></returns>
Task<bool> SendMessageBatchAsync(string content, IList<string> mobiles, IList<string> bizIds = null, DateTime? sendTime = null);
}
/// <summary>
/// 亿美短信 http://www.emay.cn/
/// </summary>
public class EmaySms : ISms
{
private string _appId;
private byte[] _secretKey;
private IRestClient _client;
public EmaySms(string host, string appId, string secretKey)
{
if (string.IsNullOrWhiteSpace(host) || string.IsNullOrWhiteSpace(appId) || string.IsNullOrWhiteSpace(secretKey))
{
throw new ArgumentNullException();
}
this._appId = appId;
var key = new Byte[16];
Array.Copy(Encoding.UTF8.GetBytes(secretKey.PadRight(key.Length)), key, key.Length);
this._secretKey = key;
this._client = new RestClient(string.Format("http://{0}", host));
this._client.AddDefaultHeader("appId", this._appId);
}
/// <summary>
/// 请求有效期(秒),默认60
/// </summary>
public int ValidPeriod { get; set; } = 60;
/ <summary>
/ 请求时是否需要Gzip压缩,默认否
/ </summary>
//public bool UseGzip { get; set; }
private const string SendSingleSmsUrl = "/inter/sendSingleSMS";
private const string SendBatchSmsUrl = "/inter/sendBatchSMS";
private IRestRequest GetRestRequest(object data,string url)
{
var str = JsonConvert.SerializeObject(data);
var encryptData = AESHelper.Encrypt(Encoding.UTF8.GetBytes(str), this._secretKey, null, CipherMode.ECB, PaddingMode.PKCS7);
var request = new RestRequest(url, Method.POST);
request.AddParameter(new Parameter
{
Type = ParameterType.RequestBody,
DataFormat = DataFormat.None,
Value = encryptData,
Name = ""
});
return request;
}
private object GetSingleSmsObj(string mobile, string content, string bizId, DateTime? sendTime)
{
var data = new
{
mobile,
content,
timerTime = sendTime.HasValue ? sendTime.Value.ToString("yyyy-MM-dd HH:mm:ss") : string.Empty,
customSmsId = bizId,
requestTime = DateTime.Now.Ticks,
requestValidPeriod = this.ValidPeriod
};
return data;
}
private bool IsResponseSuccess(IRestResponse response)
{
return response.Headers.FirstOrDefault(p => p.Name == "result")?.Value.ToString() == "SUCCESS";
}
private string GetResponseContent(IRestResponse response)
{
var data = AESHelper.Decrypt(response.RawBytes, this._secretKey, null, CipherMode.ECB, PaddingMode.PKCS7);
return Encoding.UTF8.GetString(data);
}
public bool SendMessage(string mobile, string content, string bizId = null, DateTime? sendTime = null)
{
var data = this.GetSingleSmsObj(mobile, content, bizId, sendTime);
var request = this.GetRestRequest(data, SendSingleSmsUrl);
var response = this._client.Execute(request);
return this.IsResponseSuccess(response);
}
public async Task<bool> SendMessageAsync(string mobile, string content, string bizId = null, DateTime? sendTime = null)
{
var data = this.GetSingleSmsObj(mobile, content, bizId, sendTime);
var request = this.GetRestRequest(data, SendSingleSmsUrl);
var response = await this._client.ExecuteTaskAsync(request).ConfigureAwait(false);
return this.IsResponseSuccess(response);
}
public bool SendMessageBatch(string content, IList<string> mobiles, IList<string> bizIds = null, DateTime? sendTime = null)
{
var data = this.GetBatchSMSObj(content, mobiles, bizIds, sendTime);
var request = this.GetRestRequest(data, SendBatchSmsUrl);
var response = this._client.Execute(request);
return this.IsResponseSuccess(response);
}
private object GetBatchSMSObj(string content, IList<string> mobiles, IList<string> bizIds, DateTime? sendTime)
{
if (bizIds != null && bizIds.Count > 0 && mobiles.Count != bizIds.Count)
{
throw new ArgumentException($"{nameof(mobiles)}.Count not equals {nameof(bizIds)}.Count");
}
if (bizIds != null && bizIds.Count == 0)
{
bizIds = null;
}
var items = new ArrayList();
for (var i = 0; i < mobiles.Count; i++)
{
items.Add(new
{
mobile = mobiles[i],
customSmsId = bizIds?[i]
});
}
var obj = new
{
smses = items,
content,
timerTime = sendTime.HasValue ? sendTime.Value.ToString("yyyy-MM-dd HH:mm:ss") : string.Empty,
requestTime = DateTime.Now.Ticks,
requestValidPeriod = this.ValidPeriod
};
return obj;
}
public async Task<bool> SendMessageBatchAsync(string content, IList<string> mobiles, IList<string> bizIds = null, DateTime? sendTime = null)
{
var data = this.GetBatchSMSObj(content, mobiles, bizIds, sendTime);
var request = this.GetRestRequest(data, SendBatchSmsUrl);
var response = await this._client.ExecuteTaskAsync(request).ConfigureAwait(false);
return this.IsResponseSuccess(response);
}
}