In previous post Code – Sonus in C# – Part 01 of 05 we made a basis for using Sonus API in C#.
In this post we will extend our prototype with logon and logout, providing the basics for our first GET. In the staring sample we just want to retrieve the serial number of our Sonus session border controller.
The button Logon will attempt authentication via /rest/login, and needs in the POST the REST user and password information as defined in the Sonus session border controller. If successful the HTTP response HEADER will carry the session token in a cookie. REST clients need to lookup this cookie in the response header and cache it to use it for subsequent REST calls by setting the cookie back in the HTTP request header. We will use the variable restCookie to store this session token for subsequent REST functions on Sonus API.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
private void button_Logon_Click(object sender, EventArgs e) { label_info.Text = String.Format("Logon in progress. Please wait..."); restFqdn = textBox_Fqdn.Text; restUser = textBox_User.Text; restPassword = textBox_Password.Text; restLogFile = String.Format("{0}-{1}-{2}.txt", DateTime.Now.ToString("yyyy.MM.dd"), DateTime.Now.ToString("hh.mm.ss"), restFqdn); Logon_Step01(); } public void Logon_Step01() { label_info.Text = String.Format("Logon in progress. Please wait..."); string xmlElement = ""; string xmlText = ""; string xmlValue = ""; try { httpClient.DefaultRequestHeaders.Remove("Accept"); string url_00 = String.Format("https://{0}/rest/login", restFqdn); Log("1",String.Format("Step 01 : POST : {0}", url_00)); HttpResponseMessage res_00 = new HttpResponseMessage(); var authDic_00 = new Dictionary<string, string>(); authDic_00.Add("Username", restUser); authDic_00.Add("Password", restPassword); Log("3", String.Format(">> Request: {0}", "POST")); Log("3", String.Format(">> URL: {0}", url_00)); Log("3", String.Format("\r\n{0}", httpClient.DefaultRequestHeaders.ToString())); Log("3", String.Format(">> {0}={1}", "Username", restUser)); Log("3", String.Format(">> {0}={1}", "Password", restPassword)); res_00 = httpClient.PostAsync(url_00, new FormUrlEncodedContent(authDic_00)).Result; string res_00_request = res_00.RequestMessage.ToString(); string res_00_headers = res_00.Headers.ToString(); string res_00_status = res_00.StatusCode.ToString(); string res_00_content = res_00.Content.ReadAsStringAsync().Result; Log("3", String.Format(">> Response: {0}", res_00_status)); Log("3", String.Format("{0}", res_00_headers)); Log("3", String.Format("\r\n{0}", res_00_content)); if (res_00_status == "OK") { string[] res_00_A = res_00_headers.Split('\n'); foreach (string res_00_a in res_00_A) { // PHPSESSID=69rm7071vl08329cgi9m372kl3; path=/; secure if (res_00_a.StartsWith("Set-Cookie:")) { // We remember restCookie="PHPSESSID=69rm7071vl08329cgi9m372kl3" restCookie = res_00_a.Substring(12,36); label_Cookie.Text = restCookie; } } Log("2",String.Format("<< restCookie : {0}", restCookie)); res_00_content = res_00_content.Replace("\n", ""); XmlBrowserDisplay(res_00_content); using (XmlReader reader = XmlReader.Create(new StringReader(res_00_content))) while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: xmlElement = reader.Name; switch (xmlElement) { case "http_code": xmlValue = xmlElement; break; case "CallStateChangeEvent": xmlValue = xmlElement; if (reader.HasAttributes) { xmlValue = reader.GetAttribute("CallReference"); xmlValue = reader.GetAttribute("CallState"); break; } break; default: break; } break; case XmlNodeType.Text: xmlText = reader.Value; switch (xmlElement) { case "http_code": restHttpCode = xmlText; // 200 break; default: break; } break; case XmlNodeType.XmlDeclaration: break; case XmlNodeType.ProcessingInstruction: break; case XmlNodeType.Comment: break; case XmlNodeType.EndElement: break; } } Log("3", String.Format("<< http_code: {0}", restHttpCode)); if (restHttpCode == "200") { label_info.Text = String.Format("Logon completed normally. Session: {0}", restCookie); Log("0", String.Format("Logon completed normally. Session: {0}", restCookie)); button_Logon.Enabled = false; button_Get.Enabled = true; button_Logout.Enabled = true; } else { button_Logon.Enabled = true; button_Get.Enabled = false; button_Logout.Enabled = false; } } else { Log("1", String.Format(">> Error in step 01. {0}", "No OK received")); Log("1", String.Format("Error. Logon ended abnormally.")); label_info.Text = String.Format("Error. Logon ended abnormally."); } } catch (Exception ex) { Log("1", String.Format(">> Error in step 01. {0}", ex.InnerException.Message)); Log("1", String.Format("Error. Logon ended abnormally.")); label_info.Text = String.Format("Error. Logon ended abnormally."); } } |
It is recommended that an explicit POST is done on logout resource to cleanup session specific resources the Sonus SBC 1000/2000 node. This is implemented by the code below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
private void button_Logout_Click(object sender, EventArgs e) { Logout_Step01(); } public void Logout_Step01() { label_info.Text = String.Format("Logout in progress. Please wait..."); string xmlElement = ""; string xmlText = ""; string xmlValue = ""; try { httpClient.DefaultRequestHeaders.Remove("Accept"); string url_00 = String.Format("https://{0}/rest/logout",restFqdn); Log("1",String.Format("Step 01 : POST : {0}", url_00)); var authDic_00 = new Dictionary<string, string>(); authDic_00.Add("Username", restUser); authDic_00.Add("Password", restPassword); Log("3", String.Format(">> Request: {0}", "POST")); Log("3", String.Format(">> URL: {0}", url_00)); Log("3", String.Format("\r\n{0}", httpClient.DefaultRequestHeaders.ToString())); Log("3", String.Format(">> {0}={1}", "Username", restUser)); Log("3", String.Format(">> {0}={1}", "Password", restPassword)); HttpResponseMessage res_00 = new HttpResponseMessage(); res_00 = httpClient.PostAsync(url_00, new FormUrlEncodedContent(authDic_00)).Result; string res_00_request = res_00.RequestMessage.ToString(); string res_00_headers = res_00.Headers.ToString(); string res_00_status = res_00.StatusCode.ToString(); string res_00_content = res_00.Content.ReadAsStringAsync().Result; Log("3", String.Format(">> Response: {0}", res_00_status)); Log("3", String.Format("{0}", res_00_headers)); Log("3", String.Format("\r\n{0}", res_00_content)); if (res_00_status == "OK") { res_00_content = res_00_content.Replace("\n", ""); XmlBrowserDisplay(res_00_content); // check http_code - 200 or 401 using (XmlReader reader = XmlReader.Create(new StringReader(res_00_content))) // Parse the file and display each of the nodes. while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: xmlElement = reader.Name; switch (xmlElement) { case "http_code": xmlValue = xmlElement; break; case "CallStateChangeEvent": xmlValue = xmlElement; if (reader.HasAttributes) { xmlValue = reader.GetAttribute("CallReference"); xmlValue = reader.GetAttribute("CallState"); break; } break; default: break; } break; case XmlNodeType.Text: xmlText = reader.Value; switch (xmlElement) { case "http_code": restHttpCode = xmlText; // 200 break; default: break; } break; case XmlNodeType.XmlDeclaration: break; case XmlNodeType.ProcessingInstruction: break; case XmlNodeType.Comment: break; case XmlNodeType.EndElement: break; } } Log("2", String.Format("<< http_code: {0}", restHttpCode)); if (restHttpCode == "200") { label_info.Text = String.Format("Logout completed normally."); Log("0", String.Format("Logout completed normally.")); button_Logon.Enabled = true; button_Get.Enabled = false; button_Logout.Enabled = false; restCookie = ""; label_Cookie.Text = restCookie; label_SerialNumber.Text = ""; } else { button_Get.Enabled = true; button_Logout.Enabled = true; } } else { Log("3",res_00_content); Log("2", String.Format("Error in step 01. {0}", "No OK received")); } res_00.Dispose(); } catch (Exception ex) { Log("2", String.Format("Error in step 01. {0}", ex.Message)); } } |
Off course prior to performing logout, we should perform our GET, POST, PUT and DELETE operations using the session token obtained during the login process. Here is off course where the actual power of the Sonus API is available at your disposal. In the sample below we perform a GET to the URL that is selected from the textBox_URL. For your convenience I populated a comboBox_Url with frequently used GET resources. In the code below we assume the textBox_URL.Text has value “system”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
private void button_Get_Click(object sender, EventArgs e) { restUrl = textBox_URL.Text; //comboBox_Url.Text; Get_Step01(); } public void Get_Step01() { label_info.Text = String.Format("Get {0} in progress. Please wait...", restUrl); string xmlElement = ""; string xmlText = ""; string xmlValue = ""; try { string url_00 = String.Format("https://{0}/rest/{1}", restFqdn, restUrl); Log("1", String.Format("Step 01 : GET : {0}", url_00)); Log("3", String.Format(">> Request: {0}", "GET")); Log("3", String.Format(">> URL: {0}", url_00)); Log("3", String.Format("\r\n{0}", httpClient.DefaultRequestHeaders.ToString())); HttpResponseMessage res_00 = new HttpResponseMessage(); res_00 = httpClient.GetAsync(url_00).Result; string res_00_request = res_00.RequestMessage.ToString(); string res_00_headers = res_00.Headers.ToString(); string res_00_status = res_00.StatusCode.ToString(); string res_00_content = res_00.Content.ReadAsStringAsync().Result; Log("3", String.Format(">> Response: {0}", res_00_status)); Log("3", String.Format("{0}", res_00_headers)); Log("3", String.Format("\r\n{0}", res_00_content)); if (res_00_status == "OK") { label_info.Text = String.Format("Get {0} completed normally.", restUrl); /* * <?xml version="1.0"?> * <root> * <status> * <http_code>200</http_code> * </status> * <system href="https://be-kok-sbc01.micciaen.local/rest/system"> * <DomainName>missiaen.local</DomainName> * <IsDHCPServerEnabled>0</IsDHCPServerEnabled> * <IsNtp1AuthEnabled>0</IsNtp1AuthEnabled> * <IsNtp1Enabled>1</IsNtp1Enabled> * <IsNtp2AuthEnabled>0</IsNtp2AuthEnabled> * <IsNtp2Enabled>0</IsNtp2Enabled> * <MfgWeek>06</MfgWeek> * <MfgYear>16</MfgYear> * <NodeName>SBC2000</NodeName> * <Ntp1ServerKey></Ntp1ServerKey> * <Ntp1ServerKeyId>1</Ntp1ServerKeyId> * <Ntp1ServerName>time.missiaen.local</Ntp1ServerName> * <Ntp2ServerKey></Ntp2ServerKey> * <Ntp2ServerKeyId>2</Ntp2ServerKeyId> * <Ntp2ServerName>0.0.0.0</Ntp2ServerName> * <PartNumber>40079</PartNumber> * <PrimaryDNSServer>192.168.111.1</PrimaryDNSServer> * <SecondaryDNSServer>0.0.0.0</SecondaryDNSServer> * <SerialNumber>C4007911060036</SerialNumber> * <Status>0</Status> * <TimeZoneGeoName>Europe/Paris</TimeZoneGeoName> * <Vendor>Sonus</Vendor> * <VersionNumber></VersionNumber> * <rt_DNSServer1IP>192.168.111.1</rt_DNSServer1IP> * <rt_DNSServer2IP></rt_DNSServer2IP> * <rt_DomainName>missiaen.local</rt_DomainName> * <rt_NTPServer1>time.missiaen.local</rt_NTPServer1> * <rt_NTPServer2></rt_NTPServer2> * <sysContact>Francis Missiaen</sysContact> * <sysDescription>SBC2000 Personal Home Lab CEBP</sysDescription> * <sysLocation>BE - Koksijde</sysLocation> * <useDynamicNetSettings>0</useDynamicNetSettings> * <rt_ASM_BIOSDescription></rt_ASM_BIOSDescription> * <rt_ASM_BIOSManufacturer></rt_ASM_BIOSManufacturer> * <rt_ASM_BIOSVersion></rt_ASM_BIOSVersion> * <rt_ASM_ComputerManufacturer></rt_ASM_ComputerManufacturer> * <rt_ASM_ComputerModel></rt_ASM_ComputerModel> * <rt_ASM_HDDSize></rt_ASM_HDDSize> * <rt_ASM_ImageType>Unknown</rt_ASM_ImageType> * <rt_ASM_PhysicalMemory></rt_ASM_PhysicalMemory> * <rt_ASM_ProcessorCPUs></rt_ASM_ProcessorCPUs> * <rt_ASM_ProcessorClockSpeed></rt_ASM_ProcessorClockSpeed> * <rt_ASM_ProcessorName></rt_ASM_ProcessorName> * <rt_Chassis_BoardBottom_Temp1>28</rt_Chassis_BoardBottom_Temp1> * <rt_Chassis_BoardTop_Temp2>27</rt_Chassis_BoardTop_Temp2> * <rt_Chassis_CoreSwitch_Temp>34</rt_Chassis_CoreSwitch_Temp> * <rt_Chassis_Fan1_Speed>10752</rt_Chassis_Fan1_Speed> * <rt_Chassis_Fan2_Speed>10496</rt_Chassis_Fan2_Speed> * <rt_Chassis_Fan3_Speed>11264</rt_Chassis_Fan3_Speed> * <rt_Chassis_Fan4_Speed>11520</rt_Chassis_Fan4_Speed> * <rt_Chassis_Fan5_Speed>11264</rt_Chassis_Fan5_Speed> * <rt_Chassis_Fan6_Speed>11776</rt_Chassis_Fan6_Speed> * <rt_Chassis_Fan7_Speed>11520</rt_Chassis_Fan7_Speed> * <rt_Chassis_Fan8_Speed>11520</rt_Chassis_Fan8_Speed> * <rt_Chassis_Fan9_Speed>11520</rt_Chassis_Fan9_Speed> * <rt_Chassis_Hardware_ID>89aa6b1a029fac3c047abf</rt_Chassis_Hardware_ID> * <rt_Chassis_Main_MAC_Address></rt_Chassis_Main_MAC_Address> * <rt_Chassis_Type>SBC2000</rt_Chassis_Type> * <rt_PSU1_ACInputGood>0</rt_PSU1_ACInputGood> * <rt_PSU1_CurrentIn>1021.500</rt_PSU1_CurrentIn> * <rt_PSU1_CurrentOut>1021.500</rt_PSU1_CurrentOut> * <rt_PSU1_Fan1_Speed>0</rt_PSU1_Fan1_Speed> * <rt_PSU1_Fan2_Speed>0</rt_PSU1_Fan2_Speed> * <rt_PSU1_PowerIn>0</rt_PSU1_PowerIn> * <rt_PSU1_PowerOut>0</rt_PSU1_PowerOut> * <rt_PSU1_Present>1</rt_PSU1_Present> * <rt_PSU1_Temp>0</rt_PSU1_Temp> * <rt_PSU1_VoltageIn>0</rt_PSU1_VoltageIn> * <rt_PSU1_VoltageOut>1021.500</rt_PSU1_VoltageOut> * <rt_PSU2_ACInputGood>1</rt_PSU2_ACInputGood> * <rt_PSU2_CurrentIn>0.252</rt_PSU2_CurrentIn> * <rt_PSU2_CurrentOut>3.738</rt_PSU2_CurrentOut> * <rt_PSU2_Fan1_Speed>6665</rt_PSU2_Fan1_Speed> * <rt_PSU2_Fan2_Speed>6957</rt_PSU2_Fan2_Speed> * <rt_PSU2_PowerIn>58</rt_PSU2_PowerIn> * <rt_PSU2_PowerOut>44</rt_PSU2_PowerOut> * <rt_PSU2_Present>1</rt_PSU2_Present> * <rt_PSU2_Temp>42</rt_PSU2_Temp> * <rt_PSU2_VoltageIn>230</rt_PSU2_VoltageIn> * <rt_PSU2_VoltageOut>12.000</rt_PSU2_VoltageOut> * <rt_Software_Base_Version>5.0.2</rt_Software_Base_Version> * <rt_Software_Base_BuildNumber>395</rt_Software_Base_BuildNumber> * <rt_Software_Patch_Version>None</rt_Software_Patch_Version> * </system> * </root> */ using (XmlReader reader = XmlReader.Create(new StringReader(res_00_content))) // Parse the file and display each of the nodes. while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: xmlElement = reader.Name; switch (xmlElement) { case "http_code": xmlValue = xmlElement; break; case "SerialNumber": xmlValue = xmlElement; break; case "CallStateChangeEvent": xmlValue = xmlElement; if (reader.HasAttributes) { xmlValue = reader.GetAttribute("CallReference"); xmlValue = reader.GetAttribute("CallState"); break; } break; default: break; } break; case XmlNodeType.Text: xmlText = reader.Value; switch (xmlElement) { case "http_code": restHttpCode = xmlText; // 200 break; case "SerialNumber": restSerialNumber = xmlText; Log("2", String.Format("<< SerialNumber: {0}", restSerialNumber)); label_SerialNumber.Text = restSerialNumber; break; default: break; } break; case XmlNodeType.XmlDeclaration: break; case XmlNodeType.ProcessingInstruction: break; case XmlNodeType.Comment: break; case XmlNodeType.EndElement: break; } } } else { Log("2", String.Format("Error in step 01. {0}", "No OK received")); } } catch (Exception ex) { Log("2", String.Format("Error in step 01. {0}", ex.Message)); } } |
In order to follow the XML response during prototyping, I also added in the user interface an XML browser display.
1 2 3 4 |
private void XmlBrowserDisplay(string XML) { webBrowser_XML.DocumentText = XML; } |