Unit Testing of Remote API calls, How it works with JSON Objects - json

In my web api, I have a method that call a service that return a deserialized JSON object. I can't find a way for unit testing that is working for me.
the following is the code from the controller:
[RequireHttps]
[Route("api/GetItem/{id}")]
public class GetItemController : ControllerBase
{
private static HttpClient client = new HttpClient();
private Item item = new Item();
[RequireHttps]
[Route("api/GetItem/{id}")]
public Item GetItem(string name, string password)
{
string url = "https://localhost:5001/";
string uri = url + "api/item/" + name+ "/" + password "/" ;
client.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage Res = client.GetAsync(uri).Result;
if (Res.IsSuccessStatusCode)
{
var MemResponse = Res.Content.ReadAsStringAsync().Result;
member = JsonConvert.DeserializeObject<Item>
(MemResponse);
}
return Ok(item);
}
}
The unit test I wrote suppose to check the wrong user name and password, but when running the test it just gray out and never runs
[TestMethod]
public void GetItemWithWrongPassword()
{
var username = "Hellow";
var pass = "There";
var controller = new GetItemController();
var response = controller.GetItem(username, pass);
var s = response.ToString();
Assert.AreEqual(s, "System.Web.Http.Results.NotFoundResult");
}
what I'm doing wrong?
Later on I want to test if the connection to the remote API.

Creating an instance of GetItemController and calling its methods is not a good idea, because the whole message pipeline is skipped in the process.
I see two options here:
Put the code (including the HttpClient) that is contained in GetItem into another class and call the method on an instance of that class, e.g.:
public class ItemClient
{
private static HttpClient client = new HttpClient();
public Item GetItem(string name, string password)
{
Item item = null;
string url = "https://localhost:5001/";
string uri = url + "api/item/" + name + "/" + password;
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage Res = client.GetAsync(uri).Result;
if (Res.IsSuccessStatusCode)
{
var MemResponse = Res.Content.ReadAsStringAsync().Result;
item = JsonConvert.DeserializeObject<Item>(MemResponse);
}
return item;
}
}
Controller method:
[RequireHttps]
[Route("api/GetItem/{name}/{password}")]
public Item GetItem(string name, string password)
{
ItemClient client = new ItemClient();
var item = client.GetItem(name, password);
return Ok(item);
}
Test method:
[TestMethod]
public void GetItemWithWrongPassword()
{
var username = "Hellow";
var password = "There";
ItemClient client = new ItemClient();
var item = client.GetItem(username, password);
Assert.IsNull(item);
}
Call the controller method using a HttpClient in the test method:
[TestMethod]
public void GetItemWithWrongPassword()
{
var username = "Hellow";
var password = "There";
string url = "https://localhost/"; // Host of your Web API
string uri = url + "api/GetItemController/GetItem/" + username + "/" + password;
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage Res = client.GetAsync(uri).Result;
var s = Res.ToString();
Assert.AreEqual(s, "System.Web.Http.Results.NotFoundResult");
}
I personally prefer option 1 due to two benefits:
Debugging the test is easier. Debugging a call by HttpClient (option 2)
usually means that you have to start a second instance of Visual
Studio and set a breakpoint there.
The code can be used in other projects that are not Web API services. The endpoints become simple wrappers around the actual business logic.

Related

Xamarin.Android - How to get JSON from website

I want to get JSON data from Site
Nothing shows up about it and Xamarin and I tried these 3 from youtube and it didn't work for me
public void ValidateNumber()
{
string URL = "http://android-householdinventory-api.epizy.com/ValidateNumber.php?";
WebClient client = new WebClient();
Uri uri = new Uri(URL + "number=10");
client.DownloadDataAsync(uri);
client.DownloadDataCompleted += Client_DownloadDataCompleted;
}
private void Client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
//throw new NotImplementedException();
string json = Encoding.UTF8.GetString(e.Result);
System.Console.WriteLine(json);
}
public async void Validationv2()
{
using (var client = new HttpClient())
{
var uri = "http://android-householdinventory-api.epizy.com/ValidateNumber.php?number=100";
var Result = await client.GetStringAsync(uri);
System.Console.WriteLine(Result);
}
}
public void Validationv3()
{
WebClient wclient = new WebClient();
string a = wclient.DownloadString("http://android-householdinventory-api.epizy.com/ValidateNumber.php?number=100");
System.Console.WriteLine(a);
}
All Results to this:
<html><body><script type="text/javascript" src="/aes.js" ></script><script>function toNumbers(d){var e=[];d.replace(/(..)/g,function(d){e.push(parseInt(d,16))});return e}function toHex(){for(var d=[],d=1==arguments.length&&arguments[0].constructor==Array?arguments[0]:arguments,e="",f=0;f<d.length;f++)e+=(16>d[f]?"0":"")+d[f].toString(16);return e.toLowerCase()}var a=toNumbers("f655ba9d09a112d4968c63579db590b4"),b=toNumbers("98344c2eee86c3994890592585b49f80"),c=toNumbers("304feeb55638873348a9f20961a94049");document.cookie="__test="+toHex(slowAES.decrypt(c,2,a,b))+"; expires=Thu, 31-Dec-37 23:55:55 GMT; path=/"; location.href="http://android-householdinventory-api.epizy.com/ValidateNumber.php?number=10&i=1";</script><noscript>This site requires Javascript to work, please enable Javascript in your browser or use a browser with Javascript support</noscript></body></html>
How to fix this?
I'm new to c# and Xamarin
Your API server is returning HTML response for this "http://android-householdinventory-api.epizy.com/ValidateNumber.php?number=100" end point that's why it is showing HTML in response. You will have to correct the api response on server side.
try this! working example
private async void btn_Login_Clicked(object sender, EventArgs e)
{
List<LoginDetails> UserDetails = await _services.LoginAsync(string username, string password)
}
public async Task<List<LoginDetails>> LoginAsync(string username, string password)
{
List<LoginDetails> UserList;
using (var client = new HttpClient())
{
LoginDetails Ld = new LoginDetails();
Ld.UserName = username;
Ld.Password = password;
string url = "";
//HttpClient client = new HttpClient();
string jsonData = JsonConvert.SerializeObject(Ld);
StringContent content = new StringContent(jsonData, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(url, content);
string result = await response.Content.ReadAsStringAsync();
UserList = JsonConvert.DeserializeObject<List<LoginDetails>>(result);
//loginDetails = new ObservableCollection<LoginDetails>(UserList);
}
return UserList;
}
I was hosting on InfinityFree and it has aes.js so it may be causing that result.
This helped me in getting the solution
Setting Authorization Header of HttpClient
ByetHost server passing html values "Checking your browser" with JSON String
[I added this before client.GetAsync]
client.DefaultRequestHeaders.Add("Cookie", "__test=<COOKIE_CONTENT>; expires=<COOKIE_EXPIRATION>; path=/");

ASPC C# - (500) Internal Server Error when posting JSON

I am trying to POST some JSON data to a remote server and read JSON response back from the remote server. My code is jumping in to the catch exception block with the error ex = {"The remote server returned an error: (500) Internal Server Error."} when it gets to this line near the bottom:
var httpResponse = (HttpWebResponse)request.GetResponse();
I have read a few posts on this forum and tried the code other suggest but I don't understand/can't get it to work.
Please can you help me understand what I am doing wrong? You can see my previous attempt which is commented out near the bottom of the code block.
using System;
using System.Text;
using System.Net;
// include
using System.IO;
using System.Web.UI.WebControls;
using HobbsDPDJSONLibrary;
using System.Web;
using Newtonsoft.Json;
namespace DPDAPILibrary
{
public class DPD_API
{
#region public class variables
private static string dpdapiun = "xxx";
private static string dpdapipw = "xxx";
private static string dpdAccountNumber = "xxx";
private static string dpdapihost = "api.dpd.co.uk";
private static string dpdapiinserttestshipment = "https://api.dpd.co.uk/shipping/shipment?test=true";
private static string dpdapiinsertshipment = "https://api.dpd.co.uk/shipping/shipment";
#endregion
/// <summary>
/// Send consignment data to the DPD API to create a shipment and return a consignment number (if successful).
/// </summary>
/// <param name="geoClientData"></param>
/// <param name="JSONData"></param>
/// <returns></returns>
public Boolean insertShipment(string geoSession, bool test, out string JSONdata)
{
try
{
// default output values
JSONdata = "";
bool returnValue = false;
#region create new insert shipment object
// a large block of code here that serialises a class into JSON, this bit works so I have omitted it to reduce the code I post on the forum
#endregion
string InsertShipmentData = JsonConvert.SerializeObject(NewShipmentObject);
// convert the 'insert shipment' JSON data to byte array for posting
//byte[] postBytes = Encoding.UTF8.GetBytes(InsertShipmentData);
// set the target uri for the insert shipment request (defaults to test, or switch to live as per input parameter)
Uri targetURI = new Uri(dpdapiinserttestshipment);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(dpdapiinserttestshipment);
if(!test)
{
targetURI = new Uri(dpdapiinsertshipment);
request = (HttpWebRequest)WebRequest.Create(dpdapiinsertshipment);
}
// add headers to the web request for inserting a new shipment
request.Host = dpdapihost;
request.ContentType = "application/json";
request.Accept = "application/json";
request.Method = "POST";
request.Timeout = 30000;
request.KeepAlive = true;
request.AllowAutoRedirect = false;
request.Headers["GEOClient"] = "thirdparty/" + dpdAccountNumber;
request.Headers["GeoSession"] = geoSession;
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(InsertShipmentData);
}
var httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
//// run the request and read the response header
//using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
//{
// using (var sr = new StreamReader(response.GetResponseStream()))
// {
// JSONdata = Convert.ToString(sr.ReadToEnd());
// }
// // check if OK (status 200) returned
// if (response.StatusCode.ToString() == "OK")
// {
// returnValue = true;
// }
// else
// {
// returnValue = false;
// }
// return returnValue;
//}
return returnValue;
}
catch (Exception ex)
{
JSONdata = Convert.ToString(ex);
return false;
}
}
}
}

How to run JUnit testing on Firebase Java with authentication?

I am currently using Firebase Authentication in my mobile app. The back end is a Spring boot application. The REST APIs on the back end relies on a token generated from Firebase Authentication to retrieve the Firebase UID (verifyIDToken method) of a user to perform further functions.
Currently, I notice that in Firebase Java API (server-based), there is no way of generating a token for a user, thus there is no easy way for me to do JUnit testing on the server that relies on user authentication. Anyone has clues on how to do so?
This is the sample code that does not work:
#RequestMapping(value = "/api/subscribeChannel/{channelid}", method = RequestMethod.GET, produces = "application/json")
public DeferredResult<Object> subscribeChannel(#PathVariable Long channelid,#RequestHeader(value=FIREBASETOKEN, required = true) String idToken) {
DeferredResult<Object> result = new DeferredResult<Object>(DEFERREDTIMEOUT);
// test it out with a locally generated token
idToken = FirebaseAuth.getInstance().createCustomToken("valid Uid");
Task<FirebaseToken> task = FirebaseAuth.getInstance().verifyIdToken(idToken)
.addOnSuccessListener(new OnSuccessListener<FirebaseToken>() {
#Override
public void onSuccess(FirebaseToken decodedToken) {
String uid = decodedToken.getUid();
logger.info("Subscribe channel on success");
// do something
ret.setStatus("success");
ret.setMessage("channel id " + channelid + " subscribed");
result.setResult(ret);
} else {
result.setErrorResult(retStatus.getMessage());
}
}
}) .addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(Exception arg0) {
Exception te = new TokenNotFoundException(idToken);
logger.error("Token Not Found for " + idToken);
result.setErrorResult(te);
}
});
return result;
}
The custom token you get is different from the ID token that you use to log on. To get an id token from a custom token, do this:
private static final String ID_TOOLKIT_URL =
"https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken";
private static final JsonFactory jsonFactory = Utils.getDefaultJsonFactory();
private static final HttpTransport transport = Utils.getDefaultTransport();
private static final String FIREBASE_API_KEY = "<your api key here>";
private String signInWithCustomToken(String customToken) throws IOException {
GenericUrl url = new GenericUrl(ID_TOOLKIT_URL + "?key="
+ FIREBASE_API_KEY);
Map<String, Object> content = ImmutableMap.<String, Object>of(
"token", customToken, "returnSecureToken", true);
HttpRequest request = transport.createRequestFactory().buildPostRequest(url,
new JsonHttpContent(jsonFactory, content));
request.setParser(new JsonObjectParser(jsonFactory));
com.google.api.client.http.HttpResponse response = request.execute();
try {
GenericJson json = response.parseAs(GenericJson.class);
return json.get("idToken").toString();
} finally {
response.disconnect();
}
}
The Java API to generate custom tokens is documented under Create custom tokens using the Firebase SDK.
From there:
String uid = "some-uid";
String customToken = FirebaseAuth.getInstance().createCustomToken(uid);

Why are PostAsJsonAsync's parameters not included in the post as JSON content?

IT is very disapointing that after one week i cannot solve a simple problem of posting a JSON content to a Web Server's API. I think I will quit this attempt to use Xamarin.
I am trying to post the JSON parameters below using PostAsJsonAsync in a Xamarin app. The program does post the site but the parameters are not encoded as JSON content. Does anyone know why?
public async void Login()
{
var formcontent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string,string>("email","marcio#netopen.com.br"),
new KeyValuePair<string, string>("password","Xy345")
});
var FlyVIPAPI = new HttpClient();
var request = await FlyVIPAPI.PostAsJsonAsync("http://www.ik.com.br/app/api/LoginUser.php", formcontent);
var response = await request.Content.ReadAsStringAsync();
//var res = JsonConvert.DeserializeObject(response);
var RepostaJson = Newtonsoft.Json.Linq.JObject.Parse(response);
System.Diagnostics.Debug.WriteLine(RepostaJson["success"]);
System.Diagnostics.Debug.WriteLine(RepostaJson["error"]);
return;
}
public class LoginRequest
{
public string email { get; set; }
public string password { get; set; }
}
public async void Login()
{
using (var FlyVIPAPI = new HttpClient())
{
// Create Request object
var requestObj = new LoginRequest { email = "marcio#netopen.com.br", password = "Xy345" };
// Serialize to JSON string
var formcontent = JsonConvert.SerializeObject(requestObj);
// Create HTTP content
var content = new StringContent(formcontent, Encoding.UTF8, "application/json");
// POST Request
var request = await FlyVIPAPI.PostAsync("http://www.ik.com.br/app/api/LoginUser.php", content);
// Read Response
var response = await request.Content.ReadAsStringAsync();
....
}
}
Additionally, I would suggest wrapping your HttpClient in a using statement so that is will be disposed of once your code block is done. Freeing up resources.

Connecting SSIS WebService task to Spring WevService

I have a SSIS package in which i use a WebService task to call a Spring WS.
The authentication is done by client certificate and username & password.
I have tried to do it like this a simple HttpConnection and a WebService task - Error 504 Gateway Timeout. When i edit the HttpConnection and click on Test Connection i get an error that states:
"The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel."
I have tried doing it with a script task and the same error.
I have even tried with a dummy console application and the same result.
I also have a java written app that actually does the job but i do not have access to it's code-behind. This basically proves that the problem is not from the server itself.
The java application has it's own keystore and the same certificates that i have installed on the server.
I opened a wireshark capture and i saw that when i used either of my apps the host made a DNS request for an address that i did not configure anywhere(it seems like a proxy address from the intranet), while the java app made a DNS request with the correct address.
I am stuck here, and i have no idea what the problem might be or what else i can do so that i would get a proper error.
Please advise!
Edit:
This is the code that calls the WS:
public static void CallWebService()
{
var _url = "https://<IP>/App/soap/DataService";
string action = "getData";
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("param1", "0");
parameters.Add("param2", "0");
parameters.Add("param3", "value");
XmlDocument soapEnvelopeXml = CreateSoapEnvelope(action, parameters);
HttpWebRequest webRequest = CreateWebRequest(_url);
InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest);
// begin async call to web request.
IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);
// suspend this thread until call is complete. You might want to
// do something usefull here like update your UI.
asyncResult.AsyncWaitHandle.WaitOne();
// get the response from the completed web request.
string soapResult;
using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
{
using (StreamReader rd = new StreamReader(webResponse.GetResponseStream()))
{
soapResult = rd.ReadToEnd();
}
}
Console.WriteLine(soapResult);
}
private static HttpWebRequest CreateWebRequest(string url)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
string thumbprint = "CERTIFICATE THUMBPRINT";
byte[] thumbprintArray = new byte[thumbprint.Split(new char[]{ ' ' }).Length];
string[] stringArray = thumbprint.Split(new char[] { ' ' });
for (int i = 0; i < thumbprintArray.Length; i++)
{
thumbprintArray[i] = Convert.ToByte(stringArray[i], 16);
}
X509Store localStore = new X509Store("My");
localStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCol = localStore.Certificates.Find(X509FindType.FindByTimeValid, DateTime.Now, true);
foreach (X509Certificate cert in certCol)
{
if (cert.GetCertHashString() == thumbprint)
{
webRequest.ClientCertificates.Add(cert);
break;
}
}
webRequest.UseDefaultCredentials = false;
webRequest.Credentials = new NetworkCredential("USER", "PASSWORD");
return webRequest;
}
private static XmlDocument CreateSoapEnvelope(string action, Dictionary<string, string> parameters)
{
string formatedParameters = string.Empty;
string paramFormat = "<{0}>{1}</{0}>";
foreach (string key in parameters.Keys)
{
formatedParameters += string.Format(paramFormat, key, parameters[key]);
}
XmlDocument soapEnvelop = new XmlDocument();
soapEnvelop.LoadXml(string.Format(#"
<soapenv:Envelope xmlns:soap=""http://custom/soap/"" xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"">
<soapenv:Header/>
<soapenv:Body>
<soap:{0}>
{1}
</soap:{0}>
</soapenv:Body>
</soapenv:Envelope>", action, formatedParameters));
return soapEnvelop;
}
private static void InsertSoapEnvelopeIntoWebRequest(XmlDocument soapEnvelopeXml, HttpWebRequest webRequest)
{
using (Stream stream = webRequest.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
}