[C#.NET][SMS] 使用 Every8D Web Service API 2.0 查詢 Batch ID
上篇文章[C#.NET][Every8D] 使用 Every8D Web Service API 2.1 發送簡訊寫到,要查詢簡訊發送/簡訊回傳資料必須要有有Batch ID,Batch ID 可以在發送簡訊後自己寫code記下來,也可以透過Web Service API 2.0版本去取得,我在API 2.1版本沒有找到查詢 Batch ID 的功能,只在 API 2.0 版本找到。
API 2.0版本的登錄機制與2.1版本不同,以下兩個WS擇一加入,然後調用Login方法
http://tw.every8d.com/API20/Security.asmx?wsdl
https://oms.every8d.com/API20/Security.asmx?wsdl
調用Login方法後會回傳Xml格式。
看到Xml後,定義相關的Entity Class:
/// <summary>
/// 登入後回傳的欄位
/// </summary>
[Serializable, XmlRoot("USER")]
public class LoginResponse
{
[XmlElement("ERROR_CODE")]
public string ErrorCode { get; set; }
[XmlElement("DESC")]
public string Description { get; set; }
[XmlElement("COMPANY_NO")]
public string CompanyNo { get; set; }
[XmlElement("USER_NO")]
public string UserNo { get; set; }
[XmlElement("USER_NAME")]
public string UserName { get; set; }
[XmlElement("CREDIT")]
public string Credit { get; set; }
[XmlElement("MOBILE")]
public string Mobile { get; set; }
[XmlElement("SPECIAL_ACCOUNT")]
public string SpecialAccount { get; set; }
[XmlElement("DUE")]
public LoginDUE DUE { get; set; }
[XmlElement("UPLOAD_FILE_URL")]
public string UploadFileURL { get; set; }
[XmlElement("APPLY_SERVICE")]
public string ApplyService { get; set; }
[XmlElement("CHARGE")]
public string Charge { get; set; }
[XmlElement("EDM_COMMON")]
public string EDMCommand { get; set; }
[XmlElement("EDM_PRIVATE")]
public string EDMPrivate { get; set; }
[XmlElement("TEMPLATE")]
public LoginTemplate Template { get; set; }
}
[Serializable, XmlRoot("DUE")]
public class LoginDUE
{
[XmlElement("TW")]
public string TW { get; set; }
[XmlElement("OTHER")]
public string Other { get; set; }
}
[Serializable, XmlRoot("TEMPLATE")]
public class LoginTemplate
{
[XmlElement("ITEM")]
public List<LoginItem> Item { get; set; }
}
[Serializable, XmlRoot("ITEM")]
public class LoginItem
{
[XmlAttribute("FILENAME")]
public string FileName { get; set; }
[XmlAttribute("DESC")]
public string Description { get; set; }
}
@LoginRequest 登入參數類別:
/// 登入參數
/// <summary>
/// 登入參數
/// </summary>
public class LoginRequest
{
public string UserID { get; set; }
public string Password { get; set; }
public string APIType { get; set; }
public string Version { get; set; }
}
@globalParameter共用常數:
internal class globalParameter
{
public readonly static string SendMessageTimeFormat = "yyyyMMddHHmmss";
public readonly static string GetReportTimeFormat = "yyyyMMdd";
public readonly static string CustID = "av8d20";//這是固定的,文件有寫
}
@ReportFactory Class,這是用來存放實作AIP 2.0 方法的類別
SecurityWebService.Security _security = new SecurityWebService.Security();private LoginRequest _LoginRequest;
public LoginRequest LoginRequest
{
get { return _LoginRequest; }
set { _LoginRequest = value; }
}
private LoginResponse _LoginResponse;
public LoginResponse LoginResponse
{
get { return _LoginResponse; }
private set
{
_LoginResponse = value;
}
}
private string _UserNo;
public string UserNo
{
get { return _UserNo; }
private set { _UserNo = value; }
}
/// 建構子
/// <summary>
/// 建構子
/// </summary>
/// <param name="LoginRequest"></param>
public ReportFactory(LoginRequest LoginRequest)
{
if (LoginRequest == null)
{
throw new ArgumentNullException("LoginRequest");
}
this.LoginRequest = LoginRequest;
}
Login方法調用了API 2.0的Login方法,再透過反序列化將Login的資料轉成Class。
/// 登入
/// <summary>
/// 登入
/// </summary>
/// <returns></returns>
public string Login()
{
string data = this._security.Login(globalParameter.CustID, this.LoginRequest.UserID, this.LoginRequest.Password, this.LoginRequest.APIType, this.LoginRequest.Version);
if (string.IsNullOrEmpty(data))
{
this.LoginResponse = null;
this.UserNo = null;
return null;
}
this.LoginResponse = this._deSerial.FromXmlString<LoginResponse>(data);
this.UserNo = this.LoginResponse.UserNo;
return this.UserNo;
}
PS.FromXmlString是我自己寫的反序列化類別,若不知如合反序列化,請參考以下: [C#.NET] 利用 泛型方法 重構 反序列化
[XML][C#.NET] 處理 ezTRACK 的 EPCIS Xml文件
Login單元測試這樣寫:
[TestMethod()]
public void LoginTest()
{
LoginRequest LoginRequest = new LoginRequest()
{
UserID = "xxx",帳號
Password = "xxx",密碼
};
ReportFactory target = new ReportFactory(LoginRequest);
string expected = "xxx";//期望客戶編號
var actual = target.Login();
Assert.AreEqual(expected, actual);
}
下圖是中斷觀察,因為UserNo是後面的查詢必要條件,所以我的Login是回傳UserNo並驗証測試結果。
拿到了UserID後,便可查詢Batch ID了,這時後就需要另一組WS,以下則一加入。
http://tw.every8d.com/API20/Report.asmx?wsdl
https://oms.every8d.com/API20/Report.asmx?wsdl
查詢 Batch ID 的時間格式是"yyyyMMdd",這部份文件沒寫,是我try出來的
/// 取得所有的 BatchID 網址
/// <summary>
/// 取得所有的 BatchID 網址
/// </summary>
/// <param name="StartTime">開始時間</param>
/// <param name="EndTime">結束時間</param>
/// <returns>回傳網址</returns>
public string GetBatchIDsUri(DateTime StartTime, DateTime EndTime)
{
if (string.IsNullOrEmpty(this.UserNo))
{
throw new ArgumentNullException("UserNo", "UserID No Exist");
}
string startTime = StartTime.ToString(globalParameter.GetReportTimeFormat);
string endTime = EndTime.ToString(globalParameter.GetReportTimeFormat);
string result = this._report.getMessageStatusList(globalParameter.CustID, this.LoginResponse.UserNo, startTime, endTime);
return result;
}
很好,到目前為止都很順,讚,資料拿到後就打完收工了,嘿嘿。
/// <summary>
/// A test for GetBatchIDsUri
/// </summary>
[TestMethod()]
public void GetBatchIDsUriTest()
{
LoginRequest LoginRequest = new LoginRequest()
{
UserID = "0956778187",
Password = "1980690911",
};
ReportFactory target = new ReportFactory(LoginRequest);
DateTime StartTime = new DateTime(2012, 04, 24);
DateTime EndTime = new DateTime(2012, 04, 26);
target.Login();
bool expected = true;
string actual;
actual = target.GetBatchIDsUri(StartTime, EndTime);
Assert.AreEqual(expected, actual.IsUri());
}
設定中斷觀察一下結果,什麼!!!是Link Zip檔!!!(『想打完,嘿嘿,沒有那麼容易』every8d API 2.0 竊笑著)
PS.當初知道後,右手食指,抖了好幾下,咆哮了好幾聲(抱頭);不過,食指抖歸抖,遇到了還是要做;接續著把單元測試寫完,IsUri()是我自己寫的string擴充方法,用來判斷字串是否為Uri。
PS.提醒下,別忘了測試失敗結果是否如預期,這裡就不多描述了;失敗會回傳-1,-2。
1.把StartTime跟EndTime 參數教換或輪流帶空值進去
2.UserID帶空字串/null
3.全部帶空字串/null
變數越多測試矩陣就越大,這時候就可以借助驅動測試來處理。參考 [TFS] 資料驅動單元測試
有點扯遠了,拉回來。既然已經知道是網路連結,就把它抓下來吧。
/// 下載網址資料,存放在Memory
/// <summary>
/// 下載網址資料,存放在Memory
/// </summary>
/// <param name="Uri">網址</param>
/// <returns>回傳網址串流</returns>
public Stream DownloadUri(string Uri)
{
if (string.IsNullOrEmpty(this.UserNo))
{
throw new ArgumentNullException("UserNo", "UserID No Exist");
}
if (string.IsNullOrEmpty(Uri))
{
throw new ArgumentNullException(Uri);
}
if (!Uri.IsUri())
{
throw new NotSupportedException("Uri");
}
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Uri);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream dataStream = response.GetResponseStream())
{
MemoryStream memory = new MemoryStream();
byte[] buffer = new byte[1024];
int size = 0;
do
{
size = dataStream.Read(buffer, 0, buffer.Length);
if (size > 0)
memory.Write(buffer, 0, size);
} while (size > 0);
memory.Position = 0;
return memory;
}
}
/// 下載網址資料,存放在實體IO
/// <summary>
/// 下載網址資料,存放在實體IO
/// </summary>
/// <param name="Uri">網址</param>
/// <param name="OutputFileName">輸出檔案名稱</param>
public void DownloadUri(string Uri, string OutputFileName)
{
if (string.IsNullOrEmpty(OutputFileName))
{
throw new ArgumentNullException("OutputFileName");
}
var input = this.DownloadUri(Uri);
using (FileStream output = new FileStream(OutputFileName, FileMode.Create, FileAccess.Write))
{
byte[] buffer = new byte[1024];
int size = 0;
do
{
size = input.Read(buffer, 0, buffer.Length);
if (size > 0)
output.Write(buffer, 0, size);
} while (size > 0);
}
}
檔案已經知道是Zip了,當然還需要解壓縮,用法請參考以下。
[C#.NET] 使用 7-zip 解壓縮檔案
[.NET] 解決 單元測試 Can not load 7-zip library or internal COM error! Message: failed to load library. 問題
我已經觀察出解壓縮後是一個csv的格式檔案
用法請參考,是為它撰寫處理它而寫的 [.Net Tools][C#.NET] 使用 LinqToCSV 處理 CSV 檔案格式;不過這裡的解壓縮方式有點不一樣,是因為後來才發現解壓檔案可能會有一個以上,原本的寫法只能解第一個檔案,所以我把它改成回傳IEnumerable<T>。
public class DecompressionContent
{
public string FileName { get; set; }
public Stream DecompressionStream { get; set; }
}
/// 解壓縮到串流集合
/// <summary>
/// 解壓縮到串流集合
/// </summary>
/// <param name="CompressionFileName">壓縮檔檔案名稱</param>
/// <returns>回傳解壓縮串流集合</returns>
public IEnumerable<DecompressionContent> Decompression(string CompressionFileName)
{
using (FileStream fileStream = new FileStream(CompressionFileName, FileMode.Open, FileAccess.Read))
{
return Decompression(fileStream);
}
}
/// 解壓縮到串流集合
/// <summary>
/// 解壓縮到串流集合
/// </summary>
/// <param name="CompressionFileStream">壓縮檔串流</param>
/// <returns>回傳解壓縮串流集合</returns>
public IEnumerable<DecompressionContent> Decompression(Stream CompressionFileStream)
{
List<DecompressionContent> streamList = new List<DecompressionContent>();
using (SevenZipExtractor zip = new SevenZipExtractor(CompressionFileStream))
{
for (int i = 0; i < zip.ArchiveFileData.Count; i++)
{
DecompressionContent content = new DecompressionContent();
MemoryStream decompressionStream = new MemoryStream();
zip.ExtractFile(i, decompressionStream);
decompressionStream.Position = 0;
content.FileName = zip.ArchiveFileData[i].FileName;
content.DecompressionStream = decompressionStream;
streamList.Add(content);
}
return streamList;
}
}
GetBatchIDs方法就是上述方法的集成,下載→解壓→處理CSV
/// 取得Batch ID集合
/// <summary>
/// 取得Batch ID集合
/// </summary>
/// <param name="StartTime">開始時間</param>
/// <param name="EndTime">結束時間</param>
/// <returns>返回Batch ID 集合</returns>
public IEnumerable<BatchIdResponse> GetBatchIDs(DateTime StartTime, DateTime EndTime)
{
if (string.IsNullOrEmpty(this.UserNo))
{
throw new ArgumentNullException("UserNo", "UserID No Exist");
}
var uri = this.GetBatchIDsUri(StartTime, EndTime);
var stream = this.DownloadUri(uri);
var decompression = this._zip.Decompression(stream);//參考http://www.dotblogs.com.tw/yc421206/archive/2012/04/30/71911.aspx
IEnumerable<BatchIdResponse> content = null;
//解壓檔案可能有兩個以上 foreach (var item in decompression)
{
//資料編碼是UTF8
using (StreamReader reader = new StreamReader(item.DecompressionStream, Encoding.UTF8))
{
CsvContext csv = new CsvContext();
content = csv.Read<BatchIdResponse>(reader).ToList();
}
}
return content;
}
GetBatchIDs的單元測試程式碼
/// <summary>
///A test for GetBatchIDs
///</summary>
[TestMethod()]
public void GetBatchIDsTest()
{
LoginRequest LoginRequest = new LoginRequest()
{
UserID = "0956778187",
Password = "1980690911",
};
ReportFactory target = new ReportFactory(LoginRequest);
target.Login();
DateTime StartTime = new DateTime(2012, 04, 24);
DateTime EndTime = new DateTime(2012, 04, 26);
int expected = 1;
var actual = target.GetBatchIDs(StartTime, EndTime);
Assert.IsTrue(actual.Count() >= expected);
}
設定中斷觀察,確定有查詢到Batch ID
真的打完收工,有了Batch ID我們便能進一步的取得我們想要的資料,今天就到此先告一段落,後面再寫有哪些資料可以拿。
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET