@@ -138,6 +138,10 @@ | |||||
#endregion | #endregion | ||||
#region 8号库 | #region 8号库 | ||||
/// <summary> | |||||
/// sms | |||||
/// </summary> | |||||
public static int sms { get { return 8; } } | |||||
#endregion | #endregion | ||||
#region 9号库 | #region 9号库 | ||||
@@ -91,6 +91,24 @@ namespace Learun.Util | |||||
return sb.ToString(); | return sb.ToString(); | ||||
} | } | ||||
/// <summary> | |||||
/// 数字随机数 | |||||
/// </summary> | |||||
/// <param name="n">生成长度</param> | |||||
/// <returns></returns> | |||||
public static string RandNum(int n) | |||||
{ | |||||
char[] arrChar = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; | |||||
StringBuilder num = new StringBuilder(); | |||||
Random rnd = new Random(DateTime.Now.Millisecond); | |||||
for (int i = 0; i < n; i++) | |||||
{ | |||||
num.Append(arrChar[rnd.Next(0, 9)].ToString()); | |||||
} | |||||
return num.ToString(); | |||||
} | |||||
#endregion | #endregion | ||||
#region 删除最后一个字符之后的字符 | #region 删除最后一个字符之后的字符 | ||||
@@ -148,7 +148,33 @@ namespace Learun.Util | |||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
public static string HttpPost(string url, string json, Encoding encoding) | |||||
{ | |||||
string result = ""; | |||||
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url); | |||||
req.Method = "POST"; | |||||
req.ContentType = "application/x-www-form-urlencoded"; | |||||
byte[] data = encoding.GetBytes(json);//把字符串转换为字节 | |||||
req.ContentLength = data.Length; //请求长度 | |||||
using (Stream reqStream = req.GetRequestStream()) //获取 | |||||
{ | |||||
reqStream.Write(data, 0, data.Length);//向当前流中写入字节 | |||||
reqStream.Close(); //关闭当前流 | |||||
} | |||||
HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); //响应结果 | |||||
Stream stream = resp.GetResponseStream(); | |||||
//获取响应内容 | |||||
using (StreamReader reader = new StreamReader(stream, encoding)) | |||||
{ | |||||
result = reader.ReadToEnd(); | |||||
} | |||||
return result; | |||||
} | |||||
public static string HttpPosts(string url, string json, WebHeaderCollection header) | public static string HttpPosts(string url, string json, WebHeaderCollection header) | ||||
{ | { | ||||
string result = ""; | string result = ""; | ||||
@@ -0,0 +1,85 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Threading.Tasks; | |||||
using Aliyun.Acs.Core; | |||||
using Aliyun.Acs.Core.Exceptions; | |||||
using Aliyun.Acs.Core.Profile; | |||||
using Aliyun.Acs.Dysmsapi.Model.V20170525; | |||||
using Learun.Util; | |||||
using Newtonsoft.Json; | |||||
namespace Quanjiang.DigitalScholl.SendSms | |||||
{ | |||||
public class AliyunSms : ISms | |||||
{ | |||||
private static readonly string RegionIdForPop = ConfigManager.AppSettings["regionIdForPop"].Value; | |||||
private static readonly string AccessId = ConfigManager.AppSettings["accessId"].Value; | |||||
private static readonly string AccessSecret = ConfigManager.AppSettings["accessSecret"].Value; | |||||
private static readonly string Product = ConfigManager.AppSettings["product"].Value; | |||||
private static readonly string Domain = ConfigManager.AppSettings["domain"].Value; | |||||
private static readonly string SignName = ConfigManager.AppSettings["SignName"].Value; | |||||
/// <summary> | |||||
/// 发送短信 | |||||
/// </summary> | |||||
/// <param name="phoneNumber">手机号</param> | |||||
/// <param name="st">短信通知类型</param> | |||||
/// <returns>发送结果</returns> | |||||
public async Task<(string code, string randomNum, string message, string errorType)> SendSmsToSingle(string phoneNumber, SmsType st, List<string> sendParams = null) | |||||
{ | |||||
(string code, string randomNum, string message, string errorType) result; | |||||
IClientProfile profile = DefaultProfile.GetProfile(RegionIdForPop, AccessId, AccessSecret); | |||||
DefaultProfile.AddEndpoint(RegionIdForPop, RegionIdForPop, Product, Domain); | |||||
IAcsClient acsClient = new DefaultAcsClient(profile); | |||||
var request = new SendSmsRequest(); | |||||
try | |||||
{ | |||||
request.PhoneNumbers = phoneNumber; | |||||
request.SignName = SignName; | |||||
var (templatecode, templateparam, randomNum) = GetSmsTemplateBySmsType(st); | |||||
request.TemplateCode = templatecode; | |||||
request.TemplateParam = templateparam; | |||||
var sendSmsResponse = await Task.FromResult(acsClient.GetAcsResponse(request)); | |||||
result = (sendSmsResponse.Code, randomNum, sendSmsResponse.Message, ""); | |||||
} | |||||
catch (ServerException e) | |||||
{ | |||||
result = (e.ErrorCode, "", e.ErrorMessage, Enum.GetName(typeof(ErrorType), e.ErrorType)); | |||||
} | |||||
catch (ClientException e) | |||||
{ | |||||
result = (e.ErrorCode, "", e.ErrorMessage, Enum.GetName(typeof(ErrorType), e.ErrorType)); | |||||
} | |||||
return result; | |||||
} | |||||
public Task<(string code, string randomNum, string message, string errorType)> SendSmsToMulti(List<string> phoneNumbers, SmsType st, List<string> sendParams = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
/// <summary> | |||||
/// 根据短信通知类型获取短信模板 | |||||
/// </summary> | |||||
/// <param name="st"></param> | |||||
/// <returns></returns> | |||||
private (string templateCode, string templateParam, string randomNum) GetSmsTemplateBySmsType(SmsType st) | |||||
{ | |||||
(string templateCode, string templateParam, string randomNum) result; | |||||
var randomNum = CommonHelper.RandNum(6); | |||||
switch (st) | |||||
{ | |||||
case SmsType.LoginBind: | |||||
result = ("SMS_468910589", JsonConvert.SerializeObject(new { code = randomNum }), randomNum); | |||||
break; | |||||
case SmsType.ForgetPassWord: | |||||
result = ("SMS_468910589", JsonConvert.SerializeObject(new { code = randomNum }), randomNum); | |||||
break; | |||||
default: | |||||
throw new ArgumentOutOfRangeException(nameof(st), st, null); | |||||
} | |||||
return result; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,47 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<configuration> | |||||
<appSettings> | |||||
<!--阿里云短信平台参数--> | |||||
<add key="product" value="Dysmsapi" /> | |||||
<add key="domain" value="dysmsapi.aliyuncs.com" /> | |||||
<add key="accessId" value="" /> | |||||
<add key="accessSecret" value="" /> | |||||
<add key="regionIdForPop" value="cn-hangzhou" /> | |||||
<add key="SignName" value="" /> | |||||
<!--斑羚短信平台--> | |||||
<add key="sdkappid" value="140009369387" /> | |||||
<add key="appkey" value="4d2743a4233e5d8625eefa31f876721b" /> | |||||
<!--一信通短信平台--> | |||||
<add key="SpCode" value="" /> | |||||
<add key="LoginName" value="" /> | |||||
<add key="Password" value="" /> | |||||
<!--发布时使用下方配置文件--> | |||||
<!--<add key="SpCode" value="320328" /> | |||||
<add key="LoginName" value="9c34cbd5462e8034d9b779887c1e8398" /> | |||||
<add key="Password" value="29745012d0575978cd8c93d8d6c62f9d96e6b808eb9ac87845721c7c29b39c8f" />--> | |||||
<add key="ClientSettingsProvider.ServiceUri" value="" /> | |||||
</appSettings> | |||||
<startup> | |||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /> | |||||
</startup> | |||||
<runtime> | |||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> | |||||
<dependentAssembly> | |||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" /> | |||||
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" /> | |||||
</dependentAssembly> | |||||
</assemblyBinding> | |||||
</runtime> | |||||
<system.web> | |||||
<membership defaultProvider="ClientAuthenticationMembershipProvider"> | |||||
<providers> | |||||
<add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" /> | |||||
</providers> | |||||
</membership> | |||||
<roleManager defaultProvider="ClientRoleProvider" enabled="true"> | |||||
<providers> | |||||
<add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" cacheTimeout="86400" /> | |||||
</providers> | |||||
</roleManager> | |||||
</system.web> | |||||
</configuration> |
@@ -0,0 +1,100 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Net; | |||||
using System.Net.Http; | |||||
using System.Net.Http.Headers; | |||||
using System.Security.Cryptography; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Learun.Util; | |||||
using Newtonsoft.Json; | |||||
using Newtonsoft.Json.Linq; | |||||
using Quanjiang.DigitalScholl.SendSms.Banling.Sms; | |||||
namespace Quanjiang.DigitalScholl.SendSms.Banling | |||||
{ | |||||
/// <summary> | |||||
/// 斑羚短信平台 | |||||
/// </summary> | |||||
public class BanLingSms : ISms | |||||
{ | |||||
private static readonly string SdkAppId = ConfigManager.AppSettings["sdkappid"].Value; | |||||
private static readonly string AppKey = ConfigManager.AppSettings["appkey"].Value; | |||||
public async Task<(string code, string randomNum, string message, string errorType)> SendSmsToSingle(string phoneNumber, SmsType st, List<string> sendParams = null) | |||||
{ | |||||
(string code, string randomNum, string message, string errorType) result; | |||||
var (templatecode, templateparam, randomNum) = GetSmsTemplate(st, sendParams); | |||||
try | |||||
{ | |||||
var singleSender = new SmsSingleSender(SdkAppId, AppKey); | |||||
var singleResult = await Task.FromResult(singleSender.SendWithParam("86", phoneNumber, templatecode, templateparam, "深圳国际公益学院", "", "")); | |||||
result = singleResult.result==0 ? ("OK", randomNum, "", "") : (singleResult.result.ToString(), "", singleResult.errmsg, "Client"); | |||||
} | |||||
catch (Exception e) | |||||
{ | |||||
result = ("", "", e.Message, e.GetType().ToString()); | |||||
} | |||||
return result; | |||||
} | |||||
public async Task<(string code, string randomNum, string message, string errorType)> SendSmsToMulti(List<string> phoneNumbers, SmsType st, List<string> sendParams = null) | |||||
{ | |||||
(string code, string randomNum, string message, string errorType) result; | |||||
var (templatecode, templateparam, randomNum) = GetSmsTemplate(st, sendParams); | |||||
try | |||||
{ | |||||
var multiSender = new SmsMultiSender(SdkAppId, AppKey); | |||||
var multiResult = await Task.FromResult(multiSender.SendWithParam("86", phoneNumbers, templatecode, templateparam, "深圳国际公益学院", "", "")); | |||||
result = multiResult.result == 0 ? ("OK", randomNum, "", "") : (multiResult.result.ToString(), "", multiResult.errmsg, "Client"); | |||||
} | |||||
catch (Exception e) | |||||
{ | |||||
result = ("", "", e.Message, e.GetType().ToString()); | |||||
} | |||||
return result; | |||||
} | |||||
/// <summary> | |||||
/// 根据短信通知类型获取短信模板 | |||||
/// </summary> | |||||
/// <param name="st"></param> | |||||
/// <param name="sendParams"></param> | |||||
/// <returns></returns> | |||||
private (string templateCode, List<string> templateParam, string randomNum) GetSmsTemplate(SmsType st, List<string> sendParams) | |||||
{ | |||||
(string templateCode, List<string> templateParam, string randomNum) result; | |||||
var randomNum = CommonHelper.RandNum(6); | |||||
switch (st) | |||||
{ | |||||
case SmsType.Register: | |||||
result = ("141577", new List<string>() { randomNum, "5" }, randomNum); | |||||
break; | |||||
case SmsType.LoginBind: | |||||
result = ("141578", new List<string>() { randomNum, "5" }, randomNum); | |||||
break; | |||||
case SmsType.ForgetPassWord: | |||||
result = ("141581", new List<string>() { randomNum, "5" }, randomNum); | |||||
break; | |||||
case SmsType.LessionNotification: | |||||
result = ("141583", sendParams, randomNum); | |||||
break; | |||||
case SmsType.LeaveNotification: | |||||
result = ("141585", sendParams, randomNum); | |||||
break; | |||||
case SmsType.MakeUpMissedLessonsNotification: | |||||
result = ("141588", sendParams, randomNum); | |||||
break; | |||||
case SmsType.ClassManagerLeaveNotification: | |||||
result = ("156728", sendParams, randomNum); | |||||
break; | |||||
case SmsType.ClassManagerMakeUpMissedLessonsNotification: | |||||
result = ("156729", sendParams, randomNum); | |||||
break; | |||||
default: | |||||
throw new ArgumentOutOfRangeException(nameof(st), st, null); | |||||
} | |||||
return result; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,717 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Net; | |||||
using System.Security.Cryptography; | |||||
using System.Text; | |||||
using Newtonsoft.Json; | |||||
using Newtonsoft.Json.Linq; | |||||
// newtonsoft json 模块请自行到 http://www.newtonsoft.com/json 下载 | |||||
// 注意 json 库中有 .net 的多个版本,请开发者集成自己项目相应 .net 版本的 json 库 | |||||
namespace Quanjiang.DigitalScholl.SendSms.Banling | |||||
{ | |||||
namespace Sms | |||||
{ | |||||
class SmsSingleSender | |||||
{ | |||||
string sdkappid; | |||||
string appkey; | |||||
string url = "https://msg.yundashi.com/api/sms/sendsms"; | |||||
SmsSenderUtil util = new SmsSenderUtil(); | |||||
public SmsSingleSender(string sdkappid, string appkey) | |||||
{ | |||||
this.sdkappid = sdkappid; | |||||
this.appkey = appkey; | |||||
} | |||||
/** | |||||
* 普通单发短信接口,明确指定内容,如果有多个签名,请在内容中以【】的方式添加到信息内容中,否则系统将使用默认签名 | |||||
* @param type 短信类型,0 为普通短信,1 营销短信 | |||||
* @param nationCode 国家码,如 86 为中国 | |||||
* @param phoneNumber 不带国家码的手机号 | |||||
* @param msg 信息内容,必须与申请的模板格式一致,否则将返回错误 | |||||
* @param extend 扩展码,可填空 | |||||
* @param ext 服务端原样返回的参数,可填空 | |||||
* @return SmsSingleSenderResult | |||||
*/ | |||||
public SmsSingleSenderResult Send( | |||||
int type, | |||||
string nationCode, | |||||
string phoneNumber, | |||||
string msg, | |||||
string extend, | |||||
string ext) | |||||
{ | |||||
/* | |||||
请求包体 | |||||
{ | |||||
"tel": { | |||||
"nationcode": "86", | |||||
"mobile": "13788888888" | |||||
}, | |||||
"type": 0, | |||||
"msg": "你的验证码是1234", | |||||
"sig": "fdba654e05bc0d15796713a1a1a2318c", | |||||
"time": 1479888540, | |||||
"extend": "", | |||||
"ext": "" | |||||
} | |||||
应答包体 | |||||
{ | |||||
"result": 0, | |||||
"errmsg": "OK", | |||||
"ext": "", | |||||
"sid": "xxxxxxx", | |||||
"fee": 1 | |||||
} | |||||
*/ | |||||
if (0 != type && 1 != type) | |||||
{ | |||||
throw new Exception("type " + type + " error"); | |||||
} | |||||
if (null == extend) | |||||
{ | |||||
extend = ""; | |||||
} | |||||
if (null == ext) | |||||
{ | |||||
ext = ""; | |||||
} | |||||
long random = util.GetRandom(); | |||||
long curTime = util.GetCurTime(); | |||||
// 按照协议组织 post 请求包体 | |||||
JObject data = new JObject(); | |||||
JObject tel = new JObject(); | |||||
tel.Add("nationcode", nationCode); | |||||
tel.Add("mobile", phoneNumber); | |||||
data.Add("tel", tel); | |||||
data.Add("msg", msg); | |||||
data.Add("type", type); | |||||
data.Add("sig", util.StrToHash(String.Format( | |||||
"appkey={0}&random={1}&time={2}&mobile={3}", | |||||
appkey, random, curTime, phoneNumber))); | |||||
data.Add("time", curTime); | |||||
data.Add("extend", extend); | |||||
data.Add("ext", ext); | |||||
string wholeUrl = url + "?sdkappid=" + sdkappid + "&random=" + random; | |||||
HttpWebRequest request = util.GetPostHttpConn(wholeUrl); | |||||
byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data)); | |||||
request.ContentLength = requestData.Length; | |||||
Stream requestStream = request.GetRequestStream(); | |||||
requestStream.Write(requestData, 0, requestData.Length); | |||||
requestStream.Close(); | |||||
// 接收返回包 | |||||
HttpWebResponse response = (HttpWebResponse)request.GetResponse(); | |||||
Stream responseStream = response.GetResponseStream(); | |||||
StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")); | |||||
string responseStr = streamReader.ReadToEnd(); | |||||
streamReader.Close(); | |||||
responseStream.Close(); | |||||
SmsSingleSenderResult result; | |||||
if (HttpStatusCode.OK == response.StatusCode) | |||||
{ | |||||
result = util.ResponseStrToSingleSenderResult(responseStr); | |||||
} | |||||
else | |||||
{ | |||||
result = new SmsSingleSenderResult(); | |||||
result.result = -1; | |||||
result.errmsg = "http error " + response.StatusCode + " " + responseStr; | |||||
} | |||||
return result; | |||||
} | |||||
/** | |||||
* 指定模板单发 | |||||
* @param nationCode 国家码,如 86 为中国 | |||||
* @param phoneNumber 不带国家码的手机号 | |||||
* @param templId 模板 id | |||||
* @param templParams 模板参数列表,如模板 {1}...{2}...{3},那么需要带三个参数 | |||||
* @param extend 扩展码,可填空 | |||||
* @param ext 服务端原样返回的参数,可填空 | |||||
* @return SmsSingleSenderResult | |||||
*/ | |||||
public SmsSingleSenderResult SendWithParam( | |||||
string nationCode, | |||||
string phoneNumber, | |||||
string templId, | |||||
List<string> templParams, | |||||
string sign, | |||||
string extend, | |||||
string ext) | |||||
{ | |||||
/* | |||||
请求包体 | |||||
{ | |||||
"tel": { | |||||
"nationcode": "86", | |||||
"mobile": "13788888888" | |||||
}, | |||||
"sign": "云大师", | |||||
"tpl_id": 19, | |||||
"params": [ | |||||
"验证码", | |||||
"1234", | |||||
"4" | |||||
], | |||||
"sig": "fdba654e05bc0d15796713a1a1a2318c", | |||||
"time": 1479888540, | |||||
"extend": "", | |||||
"ext": "" | |||||
} | |||||
应答包体 | |||||
{ | |||||
"result": 0, | |||||
"errmsg": "OK", | |||||
"ext": "", | |||||
"sid": "xxxxxxx", | |||||
"fee": 1 | |||||
} | |||||
*/ | |||||
if (null == sign) | |||||
{ | |||||
sign = ""; | |||||
} | |||||
if (null == extend) | |||||
{ | |||||
extend = ""; | |||||
} | |||||
if (null == ext) | |||||
{ | |||||
ext = ""; | |||||
} | |||||
long random = util.GetRandom(); | |||||
long curTime = util.GetCurTime(); | |||||
// 按照协议组织 post 请求包体 | |||||
JObject data = new JObject(); | |||||
JObject tel = new JObject(); | |||||
tel.Add("nationcode", nationCode); | |||||
tel.Add("mobile", phoneNumber); | |||||
data.Add("tel", tel); | |||||
data.Add("sig", util.CalculateSigForTempl(appkey, random, curTime, phoneNumber)); | |||||
data.Add("tpl_id", templId); | |||||
data.Add("params", util.SmsParamsToJSONArray(templParams)); | |||||
data.Add("sign", sign); | |||||
data.Add("time", curTime); | |||||
data.Add("extend", extend); | |||||
data.Add("ext", ext); | |||||
string wholeUrl = url + "?sdkappid=" + sdkappid + "&random=" + random; | |||||
HttpWebRequest request = util.GetPostHttpConn(wholeUrl); | |||||
byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data)); | |||||
request.ContentLength = requestData.Length; | |||||
Stream requestStream = request.GetRequestStream(); | |||||
requestStream.Write(requestData, 0, requestData.Length); | |||||
requestStream.Close(); | |||||
// 接收返回包 | |||||
HttpWebResponse response = (HttpWebResponse)request.GetResponse(); | |||||
Stream responseStream = response.GetResponseStream(); | |||||
StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")); | |||||
string responseStr = streamReader.ReadToEnd(); | |||||
streamReader.Close(); | |||||
responseStream.Close(); | |||||
SmsSingleSenderResult result; | |||||
if (HttpStatusCode.OK == response.StatusCode) | |||||
{ | |||||
result = util.ResponseStrToSingleSenderResult(responseStr); | |||||
} | |||||
else | |||||
{ | |||||
result = new SmsSingleSenderResult(); | |||||
result.result = -1; | |||||
result.errmsg = "http error " + response.StatusCode + " " + responseStr; | |||||
} | |||||
return result; | |||||
} | |||||
} | |||||
class SmsSingleSenderResult | |||||
{ | |||||
/* | |||||
{ | |||||
"result": 0, | |||||
"errmsg": "OK", | |||||
"ext": "", | |||||
"sid": "xxxxxxx", | |||||
"fee": 1 | |||||
} | |||||
*/ | |||||
public int result { set; get; } | |||||
public string errmsg { set; get; } | |||||
public string ext { set; get; } | |||||
public string sid { set; get; } | |||||
public int fee { set; get; } | |||||
public override string ToString() | |||||
{ | |||||
return string.Format( | |||||
"SmsSingleSenderResult\nresult {0}\nerrMsg {1}\next {2}\nsid {3}\nfee {4}", | |||||
result, errmsg, ext, sid, fee); | |||||
} | |||||
} | |||||
class SmsMultiSender | |||||
{ | |||||
string sdkappid; | |||||
string appkey; | |||||
string url = "https://sms.banling.com/intf/sendmultisms"; | |||||
SmsSenderUtil util = new SmsSenderUtil(); | |||||
public SmsMultiSender(string sdkappid, string appkey) | |||||
{ | |||||
this.sdkappid = sdkappid; | |||||
this.appkey = appkey; | |||||
} | |||||
/** | |||||
* 普通群发短信接口,明确指定内容,如果有多个签名,请在内容中以【】的方式添加到信息内容中,否则系统将使用默认签名 | |||||
* 【注意】海外短信无群发功能 | |||||
* @param type 短信类型,0 为普通短信,1 营销短信 | |||||
* @param nationCode 国家码,如 86 为中国 | |||||
* @param phoneNumbers 不带国家码的手机号列表 | |||||
* @param msg 信息内容,必须与申请的模板格式一致,否则将返回错误 | |||||
* @param extend 扩展码,可填空 | |||||
* @param ext 服务端原样返回的参数,可填空 | |||||
* @return SmsMultiSenderResult | |||||
*/ | |||||
public SmsMultiSenderResult Send( | |||||
int type, | |||||
string nationCode, | |||||
List<string> phoneNumbers, | |||||
string msg, | |||||
string extend, | |||||
string ext) | |||||
{ | |||||
/* | |||||
请求包体 | |||||
{ | |||||
"tel": [ | |||||
{ | |||||
"nationcode": "86", | |||||
"mobile": "13788888888" | |||||
}, | |||||
{ | |||||
"nationcode": "86", | |||||
"mobile": "13788888889" | |||||
} | |||||
], | |||||
"type": 0, | |||||
"msg": "你的验证码是1234", | |||||
"sig": "fdba654e05bc0d15796713a1a1a2318c", | |||||
"time": 1479888540, | |||||
"extend": "", | |||||
"ext": "" | |||||
} | |||||
应答包体 | |||||
{ | |||||
"result": 0, | |||||
"errmsg": "OK", | |||||
"ext": "", | |||||
"detail": [ | |||||
{ | |||||
"result": 0, | |||||
"errmsg": "OK", | |||||
"mobile": "13788888888", | |||||
"nationcode": "86", | |||||
"sid": "xxxxxxx", | |||||
"fee": 1 | |||||
}, | |||||
{ | |||||
"result": 0, | |||||
"errmsg": "OK", | |||||
"mobile": "13788888889", | |||||
"nationcode": "86", | |||||
"sid": "xxxxxxx", | |||||
"fee": 1 | |||||
} | |||||
] | |||||
} | |||||
*/ | |||||
if (0 != type && 1 != type) | |||||
{ | |||||
throw new Exception("type " + type + " error"); | |||||
} | |||||
if (null == extend) | |||||
{ | |||||
extend = ""; | |||||
} | |||||
if (null == ext) | |||||
{ | |||||
ext = ""; | |||||
} | |||||
long random = util.GetRandom(); | |||||
long curTime = util.GetCurTime(); | |||||
// 按照协议组织 post 请求包体 | |||||
JObject data = new JObject(); | |||||
data.Add("tel", util.PhoneNumbersToJSONArray(nationCode, phoneNumbers)); | |||||
data.Add("type", type); | |||||
data.Add("msg", msg); | |||||
data.Add("sig", util.CalculateSig(appkey, random, curTime, phoneNumbers)); | |||||
data.Add("time", curTime); | |||||
data.Add("extend", extend); | |||||
data.Add("ext", ext); | |||||
string wholeUrl = url + "?sdkappid=" + sdkappid + "&random=" + random; | |||||
HttpWebRequest request = util.GetPostHttpConn(wholeUrl); | |||||
byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data)); | |||||
request.ContentLength = requestData.Length; | |||||
Stream requestStream = request.GetRequestStream(); | |||||
requestStream.Write(requestData, 0, requestData.Length); | |||||
requestStream.Close(); | |||||
// 接收返回包 | |||||
HttpWebResponse response = (HttpWebResponse)request.GetResponse(); | |||||
Stream responseStream = response.GetResponseStream(); | |||||
StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")); | |||||
string responseStr = streamReader.ReadToEnd(); | |||||
streamReader.Close(); | |||||
responseStream.Close(); | |||||
SmsMultiSenderResult result; | |||||
if (HttpStatusCode.OK == response.StatusCode) | |||||
{ | |||||
result = util.ResponseStrToMultiSenderResult(responseStr); | |||||
} | |||||
else | |||||
{ | |||||
result = new SmsMultiSenderResult(); | |||||
result.result = -1; | |||||
result.errmsg = "http error " + response.StatusCode + " " + responseStr; | |||||
} | |||||
return result; | |||||
} | |||||
/** | |||||
* 指定模板群发 | |||||
* 【注意】海外短信无群发功能 | |||||
* @param nationCode 国家码,如 86 为中国 | |||||
* @param phoneNumbers 不带国家码的手机号列表 | |||||
* @param templId 模板 id | |||||
* @param params 模板参数列表 | |||||
* @param sign 签名,如果填空,系统会使用默认签名 | |||||
* @param extend 扩展码,可以填空 | |||||
* @param ext 服务端原样返回的参数,可以填空 | |||||
* @return SmsMultiSenderResult | |||||
*/ | |||||
public SmsMultiSenderResult SendWithParam( | |||||
String nationCode, | |||||
List<string> phoneNumbers, | |||||
string templId, | |||||
List<string> templParams, | |||||
string sign, | |||||
string extend, | |||||
string ext) | |||||
{ | |||||
/* | |||||
请求包体 | |||||
{ | |||||
"tel": [ | |||||
{ | |||||
"nationcode": "86", | |||||
"mobile": "13788888888" | |||||
}, | |||||
{ | |||||
"nationcode": "86", | |||||
"mobile": "13788888889" | |||||
} | |||||
], | |||||
"type": 0, | |||||
"msg": "你的验证码是1234", | |||||
"sig": "fdba654e05bc0d15796713a1a1a2318c", | |||||
"time": 1479888540, | |||||
"extend": "", | |||||
"ext": "" | |||||
} | |||||
应答包体 | |||||
{ | |||||
"result": 0, | |||||
"errmsg": "OK", | |||||
"ext": "", | |||||
"detail": [ | |||||
{ | |||||
"result": 0, | |||||
"errmsg": "OK", | |||||
"mobile": "13788888888", | |||||
"nationcode": "86", | |||||
"sid": "xxxxxxx", | |||||
"fee": 1 | |||||
}, | |||||
{ | |||||
"result": 0, | |||||
"errmsg": "OK", | |||||
"mobile": "13788888889", | |||||
"nationcode": "86", | |||||
"sid": "xxxxxxx", | |||||
"fee": 1 | |||||
} | |||||
] | |||||
} | |||||
*/ | |||||
if (null == sign) | |||||
{ | |||||
sign = ""; | |||||
} | |||||
if (null == extend) | |||||
{ | |||||
extend = ""; | |||||
} | |||||
if (null == ext) | |||||
{ | |||||
ext = ""; | |||||
} | |||||
long random = util.GetRandom(); | |||||
long curTime = util.GetCurTime(); | |||||
// 按照协议组织 post 请求包体 | |||||
JObject data = new JObject(); | |||||
data.Add("tel", util.PhoneNumbersToJSONArray(nationCode, phoneNumbers)); | |||||
data.Add("sig", util.CalculateSigForTempl(appkey, random, curTime, phoneNumbers)); | |||||
data.Add("tpl_id", templId); | |||||
data.Add("params", util.SmsParamsToJSONArray(templParams)); | |||||
data.Add("sign", sign); | |||||
data.Add("time", curTime); | |||||
data.Add("extend", extend); | |||||
data.Add("ext", ext); | |||||
string wholeUrl = url + "?sdkappid=" + sdkappid + "&random=" + random; | |||||
HttpWebRequest request = util.GetPostHttpConn(wholeUrl); | |||||
byte[] requestData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data)); | |||||
request.ContentLength = requestData.Length; | |||||
Stream requestStream = request.GetRequestStream(); | |||||
requestStream.Write(requestData, 0, requestData.Length); | |||||
requestStream.Close(); | |||||
// 接收返回包 | |||||
HttpWebResponse response = (HttpWebResponse)request.GetResponse(); | |||||
Stream responseStream = response.GetResponseStream(); | |||||
StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")); | |||||
string responseStr = streamReader.ReadToEnd(); | |||||
streamReader.Close(); | |||||
responseStream.Close(); | |||||
SmsMultiSenderResult result; | |||||
if (HttpStatusCode.OK == response.StatusCode) | |||||
{ | |||||
result = util.ResponseStrToMultiSenderResult(responseStr); | |||||
} | |||||
else | |||||
{ | |||||
result = new SmsMultiSenderResult(); | |||||
result.result = -1; | |||||
result.errmsg = "http error " + response.StatusCode + " " + responseStr; | |||||
} | |||||
return result; | |||||
} | |||||
} | |||||
class SmsMultiSenderResult | |||||
{ | |||||
/* | |||||
{ | |||||
"result": 0, | |||||
"errmsg": "OK", | |||||
"ext": "", | |||||
"detail": [ | |||||
{ | |||||
"result": 0, | |||||
"errmsg": "OK", | |||||
"mobile": "13788888888", | |||||
"nationcode": "86", | |||||
"sid": "xxxxxxx", | |||||
"fee": 1 | |||||
}, | |||||
{ | |||||
"result": 0, | |||||
"errmsg": "OK", | |||||
"mobile": "13788888889", | |||||
"nationcode": "86", | |||||
"sid": "xxxxxxx", | |||||
"fee": 1 | |||||
} | |||||
] | |||||
} | |||||
*/ | |||||
public class Detail | |||||
{ | |||||
public int result { get; set; } | |||||
public string errmsg { get; set; } | |||||
public string mobile { get; set; } | |||||
public string nationcode { get; set; } | |||||
public string sid { get; set; } | |||||
public int fee { get; set; } | |||||
public override string ToString() | |||||
{ | |||||
return string.Format( | |||||
"\tDetail result {0} errmsg {1} mobile {2} nationcode {3} sid {4} fee {5}", | |||||
result, errmsg, mobile, nationcode, sid, fee); | |||||
} | |||||
} | |||||
public int result; | |||||
public string errmsg = ""; | |||||
public string ext = ""; | |||||
public IList<Detail> detail; | |||||
public override string ToString() | |||||
{ | |||||
if (null != detail) | |||||
{ | |||||
return String.Format( | |||||
"SmsMultiSenderResult\nresult {0}\nerrmsg {1}\next {2}\ndetail:\n{3}", | |||||
result, errmsg, ext, String.Join("\n", detail)); | |||||
} | |||||
else | |||||
{ | |||||
return String.Format( | |||||
"SmsMultiSenderResult\nresult {0}\nerrmsg {1}\next {2}\n", | |||||
result, errmsg, ext); | |||||
} | |||||
} | |||||
} | |||||
class SmsSenderUtil | |||||
{ | |||||
Random random = new Random(); | |||||
public HttpWebRequest GetPostHttpConn(string url) | |||||
{ | |||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); | |||||
request.Method = "POST"; | |||||
request.ContentType = "application/x-www-form-urlencoded"; | |||||
return request; | |||||
} | |||||
public long GetRandom() | |||||
{ | |||||
return random.Next(999999)%900000 + 100000; | |||||
} | |||||
public long GetCurTime() | |||||
{ | |||||
Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; | |||||
return unixTimestamp; | |||||
} | |||||
// 将二进制的数值转换为 16 进制字符串,如 "abc" => "616263" | |||||
private static string ByteArrayToHex(byte[] byteArray) | |||||
{ | |||||
string returnStr = ""; | |||||
if (byteArray != null) | |||||
{ | |||||
for (int i = 0; i < byteArray.Length; i++) | |||||
{ | |||||
returnStr += byteArray[i].ToString("x2"); | |||||
} | |||||
} | |||||
return returnStr; | |||||
} | |||||
public string StrToHash(string str) | |||||
{ | |||||
SHA256 sha256 = SHA256Managed.Create(); | |||||
byte[] resultByteArray = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(str)); | |||||
return ByteArrayToHex(resultByteArray); | |||||
} | |||||
// 将单发回包解析成结果对象 | |||||
public SmsSingleSenderResult ResponseStrToSingleSenderResult(string str) | |||||
{ | |||||
SmsSingleSenderResult result = JsonConvert.DeserializeObject<SmsSingleSenderResult>(str); | |||||
return result; | |||||
} | |||||
// 将群发回包解析成结果对象 | |||||
public SmsMultiSenderResult ResponseStrToMultiSenderResult(string str) | |||||
{ | |||||
SmsMultiSenderResult result = JsonConvert.DeserializeObject<SmsMultiSenderResult>(str); | |||||
return result; | |||||
} | |||||
public JArray SmsParamsToJSONArray(List<string> templParams) | |||||
{ | |||||
JArray smsParams = new JArray(); | |||||
foreach (string templParamsElement in templParams) | |||||
{ | |||||
smsParams.Add(templParamsElement); | |||||
} | |||||
return smsParams; | |||||
} | |||||
public JArray PhoneNumbersToJSONArray(string nationCode, List<string> phoneNumbers) | |||||
{ | |||||
JArray tel = new JArray(); | |||||
int i = 0; | |||||
do | |||||
{ | |||||
JObject telElement = new JObject(); | |||||
telElement.Add("nationcode", nationCode); | |||||
telElement.Add("mobile", phoneNumbers.ElementAt(i)); | |||||
tel.Add(telElement); | |||||
} while (++i < phoneNumbers.Count); | |||||
return tel; | |||||
} | |||||
public string CalculateSigForTempl( | |||||
string appkey, | |||||
long random, | |||||
long curTime, | |||||
List<string> phoneNumbers) | |||||
{ | |||||
string phoneNumbersString = phoneNumbers.ElementAt(0); | |||||
for (int i = 1; i < phoneNumbers.Count; i++) | |||||
{ | |||||
phoneNumbersString += "," + phoneNumbers.ElementAt(i); | |||||
} | |||||
return StrToHash(String.Format( | |||||
"appkey={0}&random={1}&time={2}&mobile={3}", | |||||
appkey, random, curTime, phoneNumbersString)); | |||||
} | |||||
public string CalculateSigForTempl( | |||||
string appkey, | |||||
long random, | |||||
long curTime, | |||||
string phoneNumber) | |||||
{ | |||||
List<string> phoneNumbers = new List<string>(); | |||||
phoneNumbers.Add(phoneNumber); | |||||
return CalculateSigForTempl(appkey, random, curTime, phoneNumbers); | |||||
} | |||||
public string CalculateSig( | |||||
string appkey, | |||||
long random, | |||||
long curTime, | |||||
List<string> phoneNumbers) | |||||
{ | |||||
string phoneNumbersString = phoneNumbers.ElementAt(0); | |||||
for (int i = 1; i < phoneNumbers.Count; i++) | |||||
{ | |||||
phoneNumbersString += "," + phoneNumbers.ElementAt(i); | |||||
} | |||||
return StrToHash(String.Format( | |||||
"appkey={0}&random={1}&time={2}&mobile={3}", | |||||
appkey, random, curTime, phoneNumbersString)); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,49 @@ | |||||
using System; | |||||
using System.Configuration; | |||||
namespace Quanjiang.DigitalScholl.SendSms | |||||
{ | |||||
internal static class ConfigManager | |||||
{ | |||||
private static readonly bool Error; | |||||
private static readonly Configuration AppConfig; | |||||
static ConfigManager() | |||||
{ | |||||
var dllPath =$"{AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory}\\Quanjiang.DigitalScholl.SendSms.dll"; | |||||
try | |||||
{ | |||||
AppConfig = ConfigurationManager.OpenExeConfiguration(dllPath); | |||||
} | |||||
catch (ConfigurationErrorsException) | |||||
{ | |||||
Error = true; | |||||
} | |||||
} | |||||
public static KeyValueConfigurationCollection AppSettings | |||||
{ | |||||
get | |||||
{ | |||||
if (Error) return null; | |||||
return AppConfig.AppSettings.Settings; | |||||
} | |||||
} | |||||
public static ConnectionStringSettingsCollection ConnectionStrings | |||||
{ | |||||
get | |||||
{ | |||||
if (Error) return null; | |||||
return AppConfig.ConnectionStrings.ConnectionStrings; | |||||
} | |||||
} | |||||
public static T GetSection<T>(string name) where T : ConfigurationSection | |||||
{ | |||||
if (Error) return null; | |||||
return AppConfig.GetSection(name) as T; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,64 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace Quanjiang.DigitalScholl.SendSms | |||||
{ | |||||
public interface ISms | |||||
{ | |||||
Task<(string code, string randomNum, string message, string errorType)> SendSmsToSingle(string phoneNumber, | |||||
SmsType st, List<string> sendParams = null); | |||||
Task<(string code, string randomNum, string message, string errorType)> SendSmsToMulti(List<string> phoneNumbers, | |||||
SmsType st, List<string> sendParams = null); | |||||
} | |||||
/// <summary> | |||||
/// 短信通知类型 | |||||
/// </summary> | |||||
public enum SmsType | |||||
{ | |||||
/// <summary> | |||||
/// 注册 | |||||
/// </summary> | |||||
Register, | |||||
/// <summary> | |||||
/// 第三方(QQ,微信)快捷登录绑定 | |||||
/// </summary> | |||||
LoginBind, | |||||
/// <summary> | |||||
/// 忘记密码 | |||||
/// </summary> | |||||
ForgetPassWord, | |||||
/// <summary> | |||||
/// 开课通知 | |||||
/// </summary> | |||||
LessionNotification, | |||||
/// <summary> | |||||
/// 学员请假通知 | |||||
/// </summary> | |||||
LeaveNotification, | |||||
/// <summary> | |||||
/// 学员补课通知 | |||||
/// </summary> | |||||
MakeUpMissedLessonsNotification, | |||||
/// <summary> | |||||
/// 班主任请假提醒 | |||||
/// </summary> | |||||
ClassManagerLeaveNotification, | |||||
/// <summary> | |||||
/// 班主任补课提醒 | |||||
/// </summary> | |||||
ClassManagerMakeUpMissedLessonsNotification, | |||||
/// <summary> | |||||
/// 教学工作安排推送 | |||||
/// </summary> | |||||
EADateArrangeNotification, | |||||
/// <summary> | |||||
/// 流程提醒 | |||||
/// </summary> | |||||
WorkFlowNotification | |||||
} | |||||
} |
@@ -0,0 +1,36 @@ | |||||
using System.Reflection; | |||||
using System.Runtime.CompilerServices; | |||||
using System.Runtime.InteropServices; | |||||
// 有关程序集的一般信息由以下 | |||||
// 控制。更改这些特性值可修改 | |||||
// 与程序集关联的信息。 | |||||
[assembly: AssemblyTitle("Quanjiang.DigitalScholl.SendSms")] | |||||
[assembly: AssemblyDescription("")] | |||||
[assembly: AssemblyConfiguration("")] | |||||
[assembly: AssemblyCompany("")] | |||||
[assembly: AssemblyProduct("Quanjiang.DigitalScholl.SendSms")] | |||||
[assembly: AssemblyCopyright("Copyright © 2018")] | |||||
[assembly: AssemblyTrademark("")] | |||||
[assembly: AssemblyCulture("")] | |||||
// 将 ComVisible 设置为 false 会使此程序集中的类型 | |||||
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 | |||||
//请将此类型的 ComVisible 特性设置为 true。 | |||||
[assembly: ComVisible(false)] | |||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID | |||||
[assembly: Guid("55f0f08d-2a9f-489a-be1b-2eeae80687e6")] | |||||
// 程序集的版本信息由下列四个值组成: | |||||
// | |||||
// 主版本 | |||||
// 次版本 | |||||
// 生成号 | |||||
// 修订号 | |||||
// | |||||
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 | |||||
//通过使用 "*",如下所示: | |||||
// [assembly: AssemblyVersion("1.0.*")] | |||||
[assembly: AssemblyVersion("1.0.0.0")] | |||||
[assembly: AssemblyFileVersion("1.0.0.0")] |
@@ -0,0 +1,96 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | |||||
<PropertyGroup> | |||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |||||
<ProjectGuid>{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}</ProjectGuid> | |||||
<OutputType>Library</OutputType> | |||||
<AppDesignerFolder>Properties</AppDesignerFolder> | |||||
<RootNamespace>Quanjiang.DigitalScholl.SendSms</RootNamespace> | |||||
<AssemblyName>Quanjiang.DigitalScholl.SendSms</AssemblyName> | |||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> | |||||
<FileAlignment>512</FileAlignment> | |||||
<SccProjectName>QJ.SendSms</SccProjectName> | |||||
<SccLocalPath>1~3d9d4e2a-0649-49e7-83e7-c48fae17202f</SccLocalPath> | |||||
<SccAuxPath>http://101.201.103.178:8090/VaultService</SccAuxPath> | |||||
<SccProvider>SourceGear Vault Visual Studio 2005 Client:{1EA47954-8515-402d-82D9-B5C332120A8D}</SccProvider> | |||||
<TargetFrameworkProfile /> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | |||||
<DebugSymbols>true</DebugSymbols> | |||||
<DebugType>full</DebugType> | |||||
<Optimize>false</Optimize> | |||||
<OutputPath>bin\Debug\</OutputPath> | |||||
<DefineConstants>DEBUG;TRACE</DefineConstants> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
<WarningLevel>4</WarningLevel> | |||||
<Prefer32Bit>false</Prefer32Bit> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||||
<DebugType>pdbonly</DebugType> | |||||
<Optimize>true</Optimize> | |||||
<OutputPath>bin\Release\</OutputPath> | |||||
<DefineConstants>TRACE</DefineConstants> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
<WarningLevel>4</WarningLevel> | |||||
<Prefer32Bit>false</Prefer32Bit> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<Reference Include="aliyun-net-sdk-core"> | |||||
<HintPath>..\packages\Sms\aliyun-net-sdk-core.dll</HintPath> | |||||
</Reference> | |||||
<Reference Include="aliyun-net-sdk-dybaseapi"> | |||||
<HintPath>..\packages\Sms\aliyun-net-sdk-dybaseapi.dll</HintPath> | |||||
</Reference> | |||||
<Reference Include="aliyun-net-sdk-dysmsapi"> | |||||
<HintPath>..\packages\Sms\aliyun-net-sdk-dysmsapi.dll</HintPath> | |||||
</Reference> | |||||
<Reference Include="Aliyun.MNS"> | |||||
<HintPath>..\packages\Sms\Aliyun.MNS.dll</HintPath> | |||||
</Reference> | |||||
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> | |||||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> | |||||
</Reference> | |||||
<Reference Include="System" /> | |||||
<Reference Include="System.Configuration" /> | |||||
<Reference Include="System.Core" /> | |||||
<Reference Include="System.Net" /> | |||||
<Reference Include="System.Net.Http" /> | |||||
<Reference Include="System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> | |||||
<HintPath>..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath> | |||||
</Reference> | |||||
<Reference Include="System.Web" /> | |||||
<Reference Include="System.Web.Extensions" /> | |||||
<Reference Include="System.Xml.Linq" /> | |||||
<Reference Include="System.Data.DataSetExtensions" /> | |||||
<Reference Include="Microsoft.CSharp" /> | |||||
<Reference Include="System.Data" /> | |||||
<Reference Include="System.Xml" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Compile Include="Yixintong\YixintongSms.cs" /> | |||||
<Compile Include="Banling\BanLingSms.cs" /> | |||||
<Compile Include="Banling\SmsSender.cs" /> | |||||
<Compile Include="ISms.cs" /> | |||||
<Compile Include="AliyunSms.cs" /> | |||||
<Compile Include="ConfigManager.cs" /> | |||||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<None Include="App.config"> | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||||
</None> | |||||
<None Include="packages.config" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<WCFMetadata Include="Connected Services\" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<ProjectReference Include="..\Learun.Framework.Module\Learun.Util\Learun.Util\Learun.Util.csproj"> | |||||
<Project>{cf8ae293-88ab-436c-9720-a8386ba5d7b7}</Project> | |||||
<Name>Learun.Util</Name> | |||||
</ProjectReference> | |||||
</ItemGroup> | |||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||||
</Project> |
@@ -0,0 +1,157 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Collections.Specialized; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using System.Web; | |||||
using Learun.Util; | |||||
using Newtonsoft.Json; | |||||
using Newtonsoft.Json.Linq; | |||||
namespace Quanjiang.DigitalScholl.SendSms | |||||
{ | |||||
/// <summary> | |||||
/// 一信通短信平台 | |||||
/// </summary> | |||||
public class YixintongSms:ISms | |||||
{ | |||||
private static readonly string SpCode = ConfigManager.AppSettings["SpCode"].Value;//企业编号 | |||||
private static readonly string LoginName = ConfigManager.AppSettings["LoginName"].Value;//用户名 | |||||
private static readonly string Password = ConfigManager.AppSettings["Password"].Value;//接口密钥 | |||||
public async Task<(string code, string randomNum, string message, string errorType)> SendSmsToSingle(string phoneNumber, SmsType st, List<string> sendParams = null) | |||||
{ | |||||
(string code, string randomNum, string message, string errorType) result; | |||||
var (templatecode, templateparam, randomNum) = GetSmsTemplateBySmsType(st); | |||||
try | |||||
{ | |||||
StringBuilder sb=new StringBuilder(); | |||||
// 按照协议组织 post 请求包体 | |||||
sb.Append("SpCode="+SpCode); | |||||
sb.Append("&LoginName=" + LoginName); | |||||
sb.Append("&Password=" + Password); | |||||
sb.Append("&MessageContent=" + sendParams.FirstOrDefault()); | |||||
sb.Append("&UserNumber=" + phoneNumber); | |||||
//sb.Append("&templateId=" + templatecode);//测试帐号去掉 | |||||
sb.Append("&SerialNumber=" + DateTime.Now.ToString("yyyyMMddHHmmssffffff")); | |||||
sb.Append("&f=1"); | |||||
//data.Add("ScheduleTime", ""); | |||||
//data.Add("signCode", ""); | |||||
//调接口 | |||||
string pushresult = Learun.Util.HttpMethods.HttpPost("https://opassapi.infocloud.cc/sms/Api/Send.do", sb.ToString(), Encoding.GetEncoding("utf-8")); | |||||
//返回体 | |||||
pushresult = pushresult.Replace("<br>", "&"); | |||||
NameValueCollection query = HttpUtility.ParseQueryString(pushresult, Encoding.GetEncoding("utf-8")); | |||||
var objresult = new SmsResult(); | |||||
objresult.result = Convert.ToInt32(query["result"]); | |||||
objresult.description = query["description"]; | |||||
objresult.taskid = query["taskid"]; | |||||
objresult.faillist = query["faillist"]; | |||||
result =(objresult.result.ToString(), phoneNumber, objresult.description, objresult.faillist); | |||||
} | |||||
catch (Exception e) | |||||
{ | |||||
result = ("", "", e.Message, e.GetType().ToString()); | |||||
} | |||||
return result; | |||||
} | |||||
public async Task<(string code, string randomNum, string message, string errorType)> SendSmsToMulti(List<string> phoneNumbers, SmsType st, List<string> sendParams = null) | |||||
{ | |||||
(string code, string randomNum, string message, string errorType) result; | |||||
var (templatecode, templateparam, randomNum) = GetSmsTemplateBySmsType(st); | |||||
try | |||||
{ | |||||
// 按照协议组织 post 请求包体 | |||||
JObject data = new JObject(); | |||||
data.Add("SpCode", SpCode); | |||||
data.Add("LoginName", LoginName); | |||||
data.Add("Password", Password); | |||||
data.Add("MessageContent", sendParams.FirstOrDefault()); | |||||
data.Add("UserNumber", string.Join(",", phoneNumbers.ToArray())); | |||||
data.Add("templateId", templatecode); | |||||
data.Add("SerialNumber", DateTime.Now.ToString("yyyyMMddHHmmssffffff")); | |||||
data.Add("ScheduleTime", ""); | |||||
data.Add("f", "1"); | |||||
data.Add("signCode", ""); | |||||
//调接口 | |||||
string pushresult = Learun.Util.HttpMethods.HttpPost("https://api.ums86.com:9600/sms/Api/Send.do", JsonConvert.SerializeObject(data), Encoding.GetEncoding("gb2312")); | |||||
//返回体 | |||||
pushresult = pushresult.Replace("<br>", "&"); | |||||
NameValueCollection query = HttpUtility.ParseQueryString(pushresult, Encoding.GetEncoding("gb2312")); | |||||
var objresult = new SmsResult(); | |||||
objresult.result = Convert.ToInt32(query["result"]); | |||||
objresult.description = query["description"]; | |||||
objresult.taskid = query["taskid"]; | |||||
objresult.faillist = query["faillist"]; | |||||
result = objresult.result == 0 ? ("OK", randomNum, "", "") : (objresult.result.ToString(), "", objresult.description, objresult.faillist); | |||||
} | |||||
catch (Exception e) | |||||
{ | |||||
result = ("", "", e.Message, e.GetType().ToString()); | |||||
} | |||||
return result; | |||||
} | |||||
/// <summary> | |||||
/// 根据短信通知类型获取短信模板 | |||||
/// </summary> | |||||
/// <param name="st"></param> | |||||
/// <returns></returns> | |||||
private (string templateCode, string templateParam, string randomNum) GetSmsTemplateBySmsType(SmsType st) | |||||
{ | |||||
(string templateCode, string templateParam,string randomNum) result; | |||||
var randomNum = CommonHelper.RandNum(6); | |||||
switch (st) | |||||
{ | |||||
case SmsType.Register: | |||||
result = ("SMS_137485060", JsonConvert.SerializeObject(new { code = randomNum }), randomNum); | |||||
break; | |||||
case SmsType.LoginBind: | |||||
result = ("SMS_137485060", JsonConvert.SerializeObject(new { code = randomNum }), randomNum); | |||||
break; | |||||
case SmsType.ForgetPassWord: | |||||
result = ("SMS_137485060", JsonConvert.SerializeObject(new { code = randomNum }), randomNum); | |||||
break; | |||||
case SmsType.EADateArrangeNotification: | |||||
result = ("1", JsonConvert.SerializeObject(new { code = randomNum }), randomNum); | |||||
break; | |||||
case SmsType.WorkFlowNotification: | |||||
result = ("0", "", ""); | |||||
break; | |||||
default: | |||||
throw new ArgumentOutOfRangeException(nameof(st), st, null); | |||||
} | |||||
return result; | |||||
} | |||||
/// <summary> | |||||
/// 发送短信返回内容 | |||||
/// </summary> | |||||
public class SmsResult { | |||||
/// <summary> | |||||
/// 错误代码(0:发送短信成功,0-34,) | |||||
/// </summary> | |||||
public int result { get; set; } | |||||
/// <summary> | |||||
/// 错误描述 | |||||
/// </summary> | |||||
public string description { get; set; } | |||||
/// <summary> | |||||
/// 任务编号 | |||||
/// </summary> | |||||
public string taskid { get; set; } | |||||
/// <summary> | |||||
/// 失败号码列表(可多个) | |||||
/// </summary> | |||||
public string faillist { get; set; } | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,5 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<packages> | |||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" /> | |||||
<package id="System.ValueTuple" version="4.3.0" targetFramework="net45" /> | |||||
</packages> |
@@ -0,0 +1,116 @@ | |||||
param($installPath, $toolsPath, $package, $project) | |||||
# open json.net splash page on package install | |||||
# don't open if json.net is installed as a dependency | |||||
try | |||||
{ | |||||
$url = "http://www.newtonsoft.com/json/install?version=" + $package.Version | |||||
$dte2 = Get-Interface $dte ([EnvDTE80.DTE2]) | |||||
if ($dte2.ActiveWindow.Caption -eq "Package Manager Console") | |||||
{ | |||||
# user is installing from VS NuGet console | |||||
# get reference to the window, the console host and the input history | |||||
# show webpage if "install-package newtonsoft.json" was last input | |||||
$consoleWindow = $(Get-VSComponentModel).GetService([NuGetConsole.IPowerConsoleWindow]) | |||||
$props = $consoleWindow.GetType().GetProperties([System.Reflection.BindingFlags]::Instance -bor ` | |||||
[System.Reflection.BindingFlags]::NonPublic) | |||||
$prop = $props | ? { $_.Name -eq "ActiveHostInfo" } | select -first 1 | |||||
if ($prop -eq $null) { return } | |||||
$hostInfo = $prop.GetValue($consoleWindow) | |||||
if ($hostInfo -eq $null) { return } | |||||
$history = $hostInfo.WpfConsole.InputHistory.History | |||||
$lastCommand = $history | select -last 1 | |||||
if ($lastCommand) | |||||
{ | |||||
$lastCommand = $lastCommand.Trim().ToLower() | |||||
if ($lastCommand.StartsWith("install-package") -and $lastCommand.Contains("newtonsoft.json")) | |||||
{ | |||||
$dte2.ItemOperations.Navigate($url) | Out-Null | |||||
} | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
# user is installing from VS NuGet dialog | |||||
# get reference to the window, then smart output console provider | |||||
# show webpage if messages in buffered console contains "installing...newtonsoft.json" in last operation | |||||
$instanceField = [NuGet.Dialog.PackageManagerWindow].GetField("CurrentInstance", [System.Reflection.BindingFlags]::Static -bor ` | |||||
[System.Reflection.BindingFlags]::NonPublic) | |||||
$consoleField = [NuGet.Dialog.PackageManagerWindow].GetField("_smartOutputConsoleProvider", [System.Reflection.BindingFlags]::Instance -bor ` | |||||
[System.Reflection.BindingFlags]::NonPublic) | |||||
if ($instanceField -eq $null -or $consoleField -eq $null) { return } | |||||
$instance = $instanceField.GetValue($null) | |||||
if ($instance -eq $null) { return } | |||||
$consoleProvider = $consoleField.GetValue($instance) | |||||
if ($consoleProvider -eq $null) { return } | |||||
$console = $consoleProvider.CreateOutputConsole($false) | |||||
$messagesField = $console.GetType().GetField("_messages", [System.Reflection.BindingFlags]::Instance -bor ` | |||||
[System.Reflection.BindingFlags]::NonPublic) | |||||
if ($messagesField -eq $null) { return } | |||||
$messages = $messagesField.GetValue($console) | |||||
if ($messages -eq $null) { return } | |||||
$operations = $messages -split "==============================" | |||||
$lastOperation = $operations | select -last 1 | |||||
if ($lastOperation) | |||||
{ | |||||
$lastOperation = $lastOperation.ToLower() | |||||
$lines = $lastOperation -split "`r`n" | |||||
$installMatch = $lines | ? { $_.StartsWith("------- installing...newtonsoft.json ") } | select -first 1 | |||||
if ($installMatch) | |||||
{ | |||||
$dte2.ItemOperations.Navigate($url) | Out-Null | |||||
} | |||||
} | |||||
} | |||||
} | |||||
catch | |||||
{ | |||||
try | |||||
{ | |||||
$pmPane = $dte2.ToolWindows.OutputWindow.OutputWindowPanes.Item("Package Manager") | |||||
$selection = $pmPane.TextDocument.Selection | |||||
$selection.StartOfDocument($false) | |||||
$selection.EndOfDocument($true) | |||||
if ($selection.Text.StartsWith("Attempting to gather dependencies information for package 'Newtonsoft.Json." + $package.Version + "'")) | |||||
{ | |||||
# don't show on upgrade | |||||
if (!$selection.Text.Contains("Removed package")) | |||||
{ | |||||
$dte2.ItemOperations.Navigate($url) | Out-Null | |||||
} | |||||
} | |||||
} | |||||
catch | |||||
{ | |||||
# stop potential errors from bubbling up | |||||
# worst case the splash page won't open | |||||
} | |||||
} | |||||
# still yolo |
@@ -130,6 +130,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quanjiang.DigitalSchool.Asp | |||||
EndProject | EndProject | ||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quanjiang.DigitalScholl.VisitService", "VisitService\Quanjiang.DigitalScholl.VisitService.csproj", "{1D482884-8749-41E7-B1E3-362612799615}" | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quanjiang.DigitalScholl.VisitService", "VisitService\Quanjiang.DigitalScholl.VisitService.csproj", "{1D482884-8749-41E7-B1E3-362612799615}" | ||||
EndProject | EndProject | ||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quanjiang.DigitalScholl.SendSms", "Quanjiang.DigitalScholl.SendSms\Quanjiang.DigitalScholl.SendSms.csproj", "{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}" | |||||
EndProject | |||||
Global | Global | ||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
Debug|Android = Debug|Android | Debug|Android = Debug|Android | ||||
@@ -1700,6 +1702,42 @@ Global | |||||
{1D482884-8749-41E7-B1E3-362612799615}.Release|Windows-x64.Build.0 = Release|Any CPU | {1D482884-8749-41E7-B1E3-362612799615}.Release|Windows-x64.Build.0 = Release|Any CPU | ||||
{1D482884-8749-41E7-B1E3-362612799615}.Release|Windows-x86.ActiveCfg = Release|Any CPU | {1D482884-8749-41E7-B1E3-362612799615}.Release|Windows-x86.ActiveCfg = Release|Any CPU | ||||
{1D482884-8749-41E7-B1E3-362612799615}.Release|Windows-x86.Build.0 = Release|Any CPU | {1D482884-8749-41E7-B1E3-362612799615}.Release|Windows-x86.Build.0 = Release|Any CPU | ||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Debug|Android.ActiveCfg = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Debug|Android.Build.0 = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Debug|iOS.ActiveCfg = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Debug|iOS.Build.0 = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Debug|Windows-ARM.ActiveCfg = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Debug|Windows-ARM.Build.0 = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Debug|Windows-x64.Build.0 = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Debug|Windows-x86.Build.0 = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Development|Android.ActiveCfg = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Development|Android.Build.0 = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Development|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Development|Any CPU.Build.0 = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Development|iOS.ActiveCfg = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Development|iOS.Build.0 = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Development|Windows-ARM.ActiveCfg = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Development|Windows-ARM.Build.0 = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Development|Windows-x64.ActiveCfg = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Development|Windows-x64.Build.0 = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Development|Windows-x86.ActiveCfg = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Development|Windows-x86.Build.0 = Debug|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Release|Android.ActiveCfg = Release|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Release|Android.Build.0 = Release|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Release|iOS.ActiveCfg = Release|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Release|iOS.Build.0 = Release|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Release|Windows-ARM.ActiveCfg = Release|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Release|Windows-ARM.Build.0 = Release|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Release|Windows-x64.ActiveCfg = Release|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Release|Windows-x64.Build.0 = Release|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Release|Windows-x86.ActiveCfg = Release|Any CPU | |||||
{55F0F08D-2A9F-489A-BE1B-2EEAE80687E6}.Release|Windows-x86.Build.0 = Release|Any CPU | |||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(SolutionProperties) = preSolution | GlobalSection(SolutionProperties) = preSolution | ||||
HideSolutionNode = FALSE | HideSolutionNode = FALSE | ||||
@@ -1751,7 +1789,7 @@ Global | |||||
{E05A2B9A-A939-450F-9A44-A8B3201D055A} = {ED258CD0-0A0C-490B-9D8F-B4CEC4467251} | {E05A2B9A-A939-450F-9A44-A8B3201D055A} = {ED258CD0-0A0C-490B-9D8F-B4CEC4467251} | ||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(ExtensibilityGlobals) = postSolution | GlobalSection(ExtensibilityGlobals) = postSolution | ||||
EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.0\lib\NET35 | |||||
SolutionGuid = {968C278F-4142-4DFF-96B0-B3D70A649451} | SolutionGuid = {968C278F-4142-4DFF-96B0-B3D70A649451} | ||||
EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.0\lib\NET35 | |||||
EndGlobalSection | EndGlobalSection | ||||
EndGlobal | EndGlobal |