用于SMS的.NET代码

大家好。

我正在研究一些通过Zeep Mobile发送/接收SMS消息的代码( http://zeepmobile.com/developers/ )。

我看过他们的谷歌小组,甚至联系了他们的支持,但他们不太善于沟通,我现在真的失明了。

我必须与它们集成(工作需要它),我不确定为什么我的代码不起作用。 所以,我想知道是否有人有任何C#.Net代码,他们不介意分享,以便我可以将其集成到我的应用程序中。

当然,这完全取决于您是否有使用Zeep的经验。 如果你想让我发布我的代码,我也可以这样做。 让我知道。

谢谢,我真的很感激帮助。

**

编辑:我已经在这里添加了源代码,任何人都可以帮助这个!

**

请原谅邋code的代码。 它只是我扔在一起测试Zeep的东西,我希望有人可以试一试。 (.Net 3.5控制台应用程序,以防你想要构建它)。

using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; using System.Net.Security; using System.Web; using System.Web.Handlers; using System.IO; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; namespace ConsoleApplication1 { class Program { public static string API_KEY = "MY_API_KEY"; public static string SECRET_ACCESS_KEY = "MY_SECRET_KEY"; public static string PATTERN_RFC1123 = "ddd, dd MMM yyyy HH:mm:ss " + "GMT"; static void Main(string[] args) { // URL for sending message - // send_message = "https://api.zeepmobile.com/messaging/2008-07-14/send_message"; // blast_message = "https://api.zeepmobile.com/messaging/2008-07-14/blast_message"; string apiurl = "https://api.zeepmobile.com/messaging/2008-07-14/blast_message"; // FORMAT must be Sun, 06 Nov 1994 08:49:37 GMT string http_date = DateTime.UtcNow.ToString("r"); // Text to send string body = HttpUtility.UrlEncode("Test message.", System.Text.Encoding.UTF8); // NOTE: Use 'user_id=22&body=' instead of just 'body=' when sending a message to a user. // 22 is a user I have previously registered with ZEEP and is used for testing purposes. string parameters = "body=" + body; // String that will be converted into a signature. string canonicalString = API_KEY + http_date + parameters; //------------START HASH COMPUTATION--------------------- // Compute the Base64 HMACSHA1 value HMACSHA1 hmacsha1 = new HMACSHA1(SECRET_ACCESS_KEY.ToByteArray()); // Compute the hash of the input file. byte[] hashValue = hmacsha1.ComputeHash(canonicalString.ToByteArray()); String b64Mac = hashValue.ToBase64String(); String authentication = String.Format("Zeep {0}:{1}", API_KEY, b64Mac); //-----------END HASH COMPUTATION------------------------ // We are using TCPClient instead of an HTTPWebRequest because we need to manually // set the "Headers" such as Date, Authorization etc which cannot easily be done with HTTPWebRequest. Uri reqUrl = new Uri(apiurl); TcpClient client = new TcpClient(reqUrl.Host, reqUrl.Port); NetworkStream netStream = client.GetStream(); // SSLStream is used for secure communication. ZEEP requires the use of SSL to send and SMS. System.Net.Security.SslStream sslStream = new System.Net.Security.SslStream( netStream, false, new System.Net.Security.RemoteCertificateValidationCallback(ValidateServerCertificate)); sslStream.AuthenticateAsClient(reqUrl.Host); // POST content we are going to transmit over the SSL channel. // See. http://zeepmobile.com/developers/documentation/messaging/2008-07-14/rest_api#send_message System.IO.StreamWriter s = new System.IO.StreamWriter(sslStream); s.WriteLine(String.Format("POST {0} HTTP/1.1", "/api/blast")); s.WriteLine(String.Format("Host: {0}", "api.zeepmobile.com")); s.WriteLine(String.Format("Authorization: Zeep {0}:{1}", API_KEY, b64Mac)); s.WriteLine(String.Format("Date: {0}", http_date)); s.WriteLine(String.Format("Content-Type: {0}", "application/x-www-form-urlencoded")); s.WriteLine(String.Format("Content-Length: {0}", parameters.Length)); s.WriteLine(String.Format("{0}", parameters)); s.Flush(); System.IO.StreamReader r = new StreamReader(sslStream); string resp = r.ReadToEnd(); Console.WriteLine(resp); r.Close(); } // The following method is invoked by the RemoteCertificateValidationDelegate. // We want to make sure the SSL has no Policy errors and is safe. public static bool ValidateServerCertificate( object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.None) return true; Console.WriteLine("Certificate error: {0}", sslPolicyErrors); // Do not allow this client to communicate with unauthenticated servers. return false; } } public static class Extensions { public static byte[] ToByteArray(this string input) { UTF8Encoding encoding = new UTF8Encoding(); return encoding.GetBytes(input); } public static string ToBase64String(this byte[] input) { return Convert.ToBase64String(input); } } } 

错误

运行此代码时发生的错误是下图中显示的错误。

替代文字

解:

好。 昨晚我一直在努力,我取得了一些进展。 我使用Fiddler构建POST消息,以查看我上面的内容与服务器预期之间的任何差异。

我已经让它发送消息并返回HTTP 200 OK响应。 同样,这段代码还没有生产就绪,它只是测试一下,看看我是否能让Zeep工作。 感谢所有回复的人,如果您正在寻找ZEEP代码,我希望这可以帮到您。


 using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; using System.Net.Security; using System.Web; using System.Web.Handlers; using System.IO; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; namespace ConsoleApplication1 { class Program { public static string API_KEY = "YOUR_API_KEY_GOES_HERE! INCLUDE DASHES!"; public static string SECRET_ACCESS_KEY = "YOUR_SECRET_KEY_GOES_HERE!"; static void Main(string[] args) { Console.WriteLine("BLAST - \r\n\r\n"); BlastTcpPost(); Console.WriteLine("SEND - \r\n\r\n"); SendTcpPost(); } ///  /// Send a BLAST to all users in your ZEEP account. ///  public static void BlastTcpPost() { SendSMS( "https://api.zeepmobile.com/messaging/2008-07-14/blast_message", // URL for Send_Message "You are on blast", // Message to send string.Empty // No UserId to send. ); } ///  /// Send a single message to a user in your ZEEP account. ///  public static void SendTcpPost() { // Note:- 22 I use for the UserId is just a user I have signed up. Yours may be different and you // might want to pass that in as a parameter. SendSMS( "https://api.zeepmobile.com/messaging/2008-07-14/send_message", // URL for Send_Message "You are a user...good job!", // Message to send "22" // User Id in your system. ); } ///  /// Uses a TCPClient and SSLStream to perform a POST. ///  /// URL that the POST must be directed to. /// Message that is to be sent. /// UserId in your Zeep System. Only required if your sending a Single Message to a User. /// Otherwise, just send a string.Empty. /// Response from the server. (although it will write the response to console) public static string SendSMS(string requestUrl, string body, string user) { string parameters = ""; string requestHeaders = ""; string responseData = ""; // FORMAT must be Sun, 06 Nov 1994 08:49:37 GMT string http_date = DateTime.UtcNow.ToString("r"); // Clean the text to send body = HttpUtility.UrlEncode(body, System.Text.Encoding.UTF8); if (user.Length > 0) parameters += "user_id=" + user + "&"; if (body.Length > 0) parameters += "body=" + body; // String that will be converted into a signature. string canonicalString = API_KEY + http_date + parameters; //------------START HASH COMPUTATION--------------------- // Compute the Base64 HMACSHA1 value HMACSHA1 hmacsha1 = new HMACSHA1(SECRET_ACCESS_KEY.ToByteArray()); // Compute the hash of the input file. byte[] hashValue = hmacsha1.ComputeHash(canonicalString.ToByteArray()); String b64Mac = hashValue.ToBase64String(); String authentication = String.Format("Zeep {0}:{1}", API_KEY, b64Mac); //-----------END HASH COMPUTATION------------------------ string auth = String.Format("Zeep {0}:{1}", API_KEY, b64Mac); System.Uri uri = new Uri(requestUrl); System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient(uri.Host, uri.Port); string requestMethod = "POST " + uri.LocalPath + " HTTP/1.1\r\n"; // Set Headers for the POST message requestHeaders += "Host: api.zeepmobile.com\r\n"; requestHeaders += "Authorization: " + auth + "\r\n"; requestHeaders += "Date: " + DateTime.UtcNow.ToString("r") + "\r\n"; requestHeaders += "Content-Type: application/x-www-form-urlencoded\r\n"; requestHeaders += "Content-Length: " + parameters.ToByteArray().Length + "\r\n"; requestHeaders += "\r\n"; // Get the data to be sent as a byte array. Byte[] data = System.Text.Encoding.UTF8.GetBytes(requestMethod + requestHeaders + parameters + "\r\n"); // Send the message to the connected TcpServer. NetworkStream stream = client.GetStream(); // SSL Authentication is used because the Server requires https. System.Net.Security.SslStream sslStream = new System.Net.Security.SslStream( stream, false, new System.Net.Security.RemoteCertificateValidationCallback(ValidateServerCertificate)); sslStream.AuthenticateAsClient(uri.Host); // Send the data over the SSL stream. sslStream.Write(data, 0, data.Length); sslStream.Flush(); // Receive the TcpServer.response. for (int i = 0; i < 100; i++) { if (stream.DataAvailable) { break; } System.Threading.Thread.Sleep(100); } Byte[] bytes = new byte[1024]; System.Text.StringBuilder sb = new System.Text.StringBuilder(); while (stream.DataAvailable) { int count = sslStream.Read(bytes, 0, 1024); if (count == 0) { break; } sb.Append(System.Text.Encoding.UTF8.GetString(bytes, 0, count)); } responseData = sb.ToString(); Console.WriteLine(responseData); // Close everything. client.Close(); return responseData; } // The following method is invoked by the RemoteCertificateValidationDelegate. // We want to make sure the SSL has no Policy errors and is safe. public static bool ValidateServerCertificate( object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { // Somehow the cert always has PolicyErrors so I am returning true regardless. return true; //if (sslPolicyErrors == SslPolicyErrors.None) // return true; //Console.WriteLine("Certificate error: {0}", sslPolicyErrors); //// Do not allow this client to communicate with unauthenticated servers. //return false; } } public static class Extensions { public static byte[] ToByteArray(this string input) { UTF8Encoding encoding = new UTF8Encoding(); return encoding.GetBytes(input); } public static string ToBase64String(this byte[] input) { return Convert.ToBase64String(input); } } } 

您确定需要使用TcpClientSslStream在代码中手动实现HTTP协议以与Zeep通信吗? 我尝试使用HttpWebRequest对象,让.NET Framework为您处理HTTP特定的协议位。 特别是因为您收到的错误消息似乎指向您发送的请求的方向,远程服务器无法理解。

(在HTTP标头和实际内容之间是否需要额外的空行?我从来没有真正记住,如果我只是执行正确的.NET Framework WebRequest我就不必这么做了……)

祝好运!