You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

249 lines
8.8 KiB
C#

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Common;
namespace Common.Tools.Message
{
/// <summary>
/// 阿里云短信发送
/// </summary>
public class aliyunSmsservice : ISmsService
{
private string RegionId = "cn-hangzhou";
private string Version = "2017-05-25";
private string Action = "SendSms";
private string Format = "JSON";
private string Domain = "dysmsapi.aliyuncs.com";
private int MaxRetryNumber = 3;
private bool AutoRetry = true;
private const string SEPARATOR = "&";
private int TimeoutInMilliSeconds = 100000;
private string AccessKeyId= "LTAIvkPRG12jmvyP";
private string AccessKeySecret= "j2bkq5jDbfj05r6RpcXtLx5BiLPZzo";
/// <summary>
/// 短信发送 阿里云
/// </summary>
/// <param name="MobileList">接收手机号列表多个用,间隔最多不能超过1000个</param>
/// <param name="TemplateCode">模版ID</param>
/// <param name="TemplateParam">模版变量</param>
/// <param name="SignName">短信签名</param>
/// <returns></returns>
public async Task<ReturnResult<object>> SendSmsAsync(List<string> MobileList,string SmsValue=null, string TemplateCode=null, Dictionary<string, string> TemplateParam = null, string SignName = null)
{
var r = new ReturnResult<object>();
if ( TemplateCode == null)
{
r.Not("模版Id不能为空");
}
StringBuilder jsonstr = new StringBuilder();
#region 阿里云短信发送实现
foreach (var item in MobileList)
{
var sms = new SmsObject
{
Mobile = item,
Signature = SignName,
TempletKey = TemplateCode,
Data = TemplateParam,
OutId = "OutId"
};
var res = await _SendSms(sms);
System.Threading.Thread.Sleep(10);
}
r.OK();
#endregion
return await Task.Run(() => r);
}
private async Task<(bool success, string response)> _SendSms(SmsObject sms)
{
var paramers = new Dictionary<string, string>();
paramers.Add("PhoneNumbers", sms.Mobile);
paramers.Add("SignName", sms.Signature);
paramers.Add("TemplateCode", sms.TempletKey);
paramers.Add("TemplateParam", JsonConvert.SerializeObject(sms.Data));
paramers.Add("OutId", sms.OutId);
paramers.Add("AccessKeyId", AccessKeyId);
try
{
string url = GetSignUrl(paramers, AccessKeySecret);
int retryTimes = 1;
var reply = await HttpGetAsync(url);
while (500 <= reply.StatusCode && AutoRetry && retryTimes < MaxRetryNumber)
{
url = GetSignUrl(paramers, AccessKeySecret);
reply = await HttpGetAsync(url);
retryTimes++;
}
if (!string.IsNullOrEmpty(reply.response))
{
var res = JsonConvert.DeserializeObject<Dictionary<string, string>>(reply.response);
if (res != null && res.ContainsKey("Code") && "OK".Equals(res["Code"]))
{
return (true, response: reply.response);
}
}
return (false, response: reply.response);
}
catch (Exception ex)
{
return (false, response: ex.Message);
}
}
private string GetSignUrl(Dictionary<string, string> parameters, string accessSecret)
{
var imutableMap = new Dictionary<string, string>(parameters);
imutableMap.Add("Timestamp", FormatIso8601Date(DateTime.Now));
imutableMap.Add("SignatureMethod", "HMAC-SHA1");
imutableMap.Add("SignatureVersion", "1.0");
imutableMap.Add("SignatureNonce", Guid.NewGuid().ToString());
imutableMap.Add("Action", Action);
imutableMap.Add("Version", Version);
imutableMap.Add("Format", Format);
imutableMap.Add("RegionId", RegionId);
IDictionary<string, string> sortedDictionary = new SortedDictionary<string, string>(imutableMap, StringComparer.Ordinal);
StringBuilder canonicalizedQueryString = new StringBuilder();
foreach (var p in sortedDictionary)
{
canonicalizedQueryString.Append("&")
.Append(PercentEncode(p.Key)).Append("=")
.Append(PercentEncode(p.Value));
}
StringBuilder stringToSign = new StringBuilder();
stringToSign.Append("GET");
stringToSign.Append(SEPARATOR);
stringToSign.Append(PercentEncode("/"));
stringToSign.Append(SEPARATOR);
stringToSign.Append(PercentEncode(canonicalizedQueryString.ToString().Substring(1)));
string signature = SignString(stringToSign.ToString(), accessSecret + "&");
imutableMap.Add("Signature", signature);
return ComposeUrl(Domain, imutableMap);
}
private static string FormatIso8601Date(DateTime date)
{
return date.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss'Z'", CultureInfo.CreateSpecificCulture("en-US"));
}
/// <summary>
/// 签名
/// </summary>
public static string SignString(string source, string accessSecret)
{
using (var algorithm = new HMACSHA1(Encoding.UTF8.GetBytes(accessSecret.ToCharArray())))
{
return Convert.ToBase64String(algorithm.ComputeHash(Encoding.UTF8.GetBytes(source.ToCharArray())));
}
}
private static string ComposeUrl(string endpoint, Dictionary<String, String> parameters)
{
StringBuilder urlBuilder = new StringBuilder("");
urlBuilder.Append("http://").Append(endpoint);
if (-1 == urlBuilder.ToString().IndexOf("?"))
{
urlBuilder.Append("/?");
}
string query = ConcatQueryString(parameters);
return urlBuilder.Append(query).ToString();
}
private static string ConcatQueryString(Dictionary<string, string> parameters)
{
if (null == parameters)
{
return null;
}
StringBuilder sb = new StringBuilder();
foreach (var entry in parameters)
{
String key = entry.Key;
String val = entry.Value;
sb.Append(HttpUtility.UrlEncode(key, Encoding.UTF8));
if (val != null)
{
sb.Append("=").Append(HttpUtility.UrlEncode(val, Encoding.UTF8));
}
sb.Append("&");
}
int strIndex = sb.Length;
if (parameters.Count > 0)
sb.Remove(strIndex - 1, 1);
return sb.ToString();
}
public static string PercentEncode(string value)
{
StringBuilder stringBuilder = new StringBuilder();
string text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
byte[] bytes = Encoding.GetEncoding("UTF-8").GetBytes(value);
foreach (char c in bytes)
{
if (text.IndexOf(c) >= 0)
{
stringBuilder.Append(c);
}
else
{
stringBuilder.Append("%").Append(
string.Format(CultureInfo.InvariantCulture, "{0:X2}", (int)c));
}
}
return stringBuilder.ToString();
}
private async Task<(int StatusCode, string response)> HttpGetAsync(string url)
{
HttpClientHandler handler = new HttpClientHandler();
handler.Proxy = null;
handler.AutomaticDecompression = DecompressionMethods.GZip;
using (var http = new HttpClient(handler))
{
http.Timeout = new TimeSpan(TimeSpan.TicksPerMillisecond * TimeoutInMilliSeconds);
HttpResponseMessage response = await http.GetAsync(url);
return ((int)response.StatusCode, await response.Content.ReadAsStringAsync());
}
}
}
}