I have a code to make HTTP web request and get the response.How to unit test invoke method and I found some links related to unit test HTTP web request and response but they are confusing for me.
I am looking to test response with out running any server.
Unit test code:
[TestMethod]
public void TestMethod()
{
string request = "request content";
WebServiceClass webServiceClass = new WebServiceClass();
string actual_response;
webServiceClass.InvokeService
(request,"POST","application/json","/invoke",out actual_response);
string expected_response="response content";
Assert.AreEqual(actual_response, expected_response);
}
Actual code:
class WebServiceClass {
private HttpWebRequest BuildHttpRequest(String requestMethod, String contentType,String uriExtension, int dataBytes)
{
String composeUrl = webServiceURL + "/" + uriExtension;
Uri srvUri = new Uri(composeUrl);
HttpWebRequest httprequest = (HttpWebRequest)HttpWebRequest.Create(srvUri);
httprequest.Method = requestMethod;
httprequest.ContentType = contentType;
httprequest.KeepAlive = false;
httprequest.Timeout = webSrvTimeOut;
httprequest.ContentLength = dataBytes;
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
httprequest.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
return httprequest;
}
public void InvokeService(String request, String requestMethod, String contentType,String uriExtension, out String response)
{
Encoding encoding = new UTF8Encoding();
String serviceResponse = String.Empty;
byte[] dataBytes = encoding.GetBytes(request);
try
{
int dataLength = dataBytes.Length;
HttpWebRequest httprequest = BuildHttpRequest(requestMethod, contentType, uriExtension, dataLength);
using (StreamWriter writes = new StreamWriter(httprequest.GetRequestStream()))
{
writes.Write(request);
}
using (HttpWebResponse httpresponse = (HttpWebResponse)httprequest.GetResponse())
{
String httpstatuscode = httpresponse.StatusCode.ToString();
using (StreamReader reader = new StreamReader(httpresponse.GetResponseStream(), Encoding.UTF8))
{
serviceResponse = reader.ReadToEnd().ToString();
}
}
}
}
Maybe late, but I think this is what you want.
//Copy Code and paste in C# Interactive Window
//(Existed in VS 2015+, "View->Other Window->C# Interactive")
//If you writen an http request and need a response test
//but the target API hasn't complated
//you can use this code to built a simple responder in C# Interactive window
//without to create a new webapi project for testing!
using System.Net;
var l = new HttpListener();
l.AuthenticationSchemes = AuthenticationSchemes.Anonymous;
l.Prefixes.Add("http://localhost:8080/API/XXXX/");//ATTACTION: Uri should end with "/"
//more target url
var t = Task.Run(() =>
{
Print("START!");
l.Start();
try
{
while (l.IsListening)
{
HttpListenerContext ctx = l.GetContext();//here for waiting
Print(new StreamReader(ctx.Request.InputStream).ReadToEnd());
////Set Response here
//ctx.Response.StatusCode = 200;
//ctx.Response.OutputStream.Write("true".Select(c => (byte)c).ToArray(), 0, 4);
ctx.Response.Close();//"Close" for return response
}
}
catch { Print("STOP!"); }
});
//l.Stop(); //Call this method to stop HttpListener
Welcome to star/fork my repository
https://github.com/Flithor/CSharpInteractive_Mini_HttpRequest_Responder
Related
I'm using Xamarin C# and php to create a simple android app that sends coordinate data to an apache sql database. When I use httpwebrequest to send a POST request to the server php, it sends a GET instead. Even though I set the request type to POST. The strange thing is that other requests that I have used using the exact same code work okay, this one specifically isn't working.
public class gpsGetterScript{
public static double longitude;
public static double latitude;
public static SimpleLocationManager locationManager = new SimpleLocationManager();
public static void startGetLocation()
{
Timer timer = new Timer();
timer.Interval = 6 * 1000;
void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
double lon = locationManager.LastLocation.Longitude;
double lat = locationManager.LastLocation.Latitude;
longitude = lon;
latitude = lat;
Console.WriteLine(lon.ToString());
Console.WriteLine(lat.ToString());
Dictionary<string, string> gpsData = new Dictionary<string, string>();
gpsData.Add("longitude", lon.ToString());
gpsData.Add("latitude", lat.ToString());
gpsData.Add("device_owner", "Test");
var url = "theURL";
var httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Method = "POST";
var contentType = "application/json";
//var contentType = "application/x-www-form-urlencoded";
httpRequest.ContentType = contentType;
var data = JsonConvert.SerializeObject(gpsData);
//var data = "longitude=" + lon.ToString() + "&latitude=" + lat.ToString() + "&device_owner=" + "Test";
using (var streamWriter = new StreamWriter(httpRequest.GetRequestStream()))
{
Console.WriteLine(data.ToString());
Console.WriteLine(httpRequest.RequestUri.ToString());
Console.WriteLine(httpRequest.Headers);
Console.WriteLine(httpRequest.Method);
streamWriter.Write(data);
}
var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
Console.WriteLine(result);
}
}
timer.Elapsed += Timer_Elapsed;
timer.AutoReset = true;
timer.Start();
locationManager.StartLocationUpdates(LocationAccuracy.Balanced, 5, TimeSpan.FromMinutes(.5), TimeSpan.FromSeconds(20));
SimpleLocationLogger.Enabled = true;
}
}
here is one of the httprequests from a related project that does work (same server being used)
public static string sendLoginRequest(string email, string password)
{
var url = "theURL";
var httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Method = "POST";
httpRequest.ContentType = "application/x-www-form-urlencoded";
var data = "email=" + email + "&password=" + password;
using (var streamWriter = new StreamWriter(httpRequest.GetRequestStream()))
{
streamWriter.Write(data);
}
var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
return result;
}
}
I know it is the app sending the wrong request, as when I made the php echo the request type it came back as GET. Strangely, when I use reqbin to make the POST request using the same URL, it works fine. It really is just for some reason the request in C# is not sending a POST. The other question about this was resolved by adding a www. to the api url, but that did not work for me.
UPDATE: 4/20/2022- Here is the php code
<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
include_once '../../../Database.php';
include_once '../location_obj.php';
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$database = new Database();
$db = $database->getConnection();
$data = json_decode(file_get_contents("php://input"));
$item = new location_obj($db);
$stmt = $item->InputCoordinates();
$item->longitude = $data->longitude;
$item->latitude = $data->latitude;
$item->device_owner = $data->device_owner;
if ($item->InputCoordinates()) {
echo json_encode(array("message" => "Successfully", "data" => $item, "Request Type" => $_SERVER['REQUEST_METHOD']));
}
else {
echo json_encode(array("error" => "failed! Check your data and try again.", "data" => $item, "Request Type" => $_SERVER['REQUEST_METHOD']));
}
}
else {
echo json_encode(array("error" => "Only the POST method is supported!", "Request Type" => $_SERVER['REQUEST_METHOD']));
}
?>`
I get the error {"error":"Only the POST method is supported!","Request Type":"GET"} but when I use reqbin I get "message": "Successfully", "data": { "longitude": "theLongitude", "latitude": "theLatitude", "device_owner": "Test" }, "Request Type": "POST"
I checked the url that is used using Console.WriteLine(url); , it is the right one.
I fixed it, seems I forgot to add a / at the end of the URL. It was https://example.com/api/v2/location/input instead of https://example.com/api/v2/location/input/
I have a working WEB API that I wrote, and I added basic authentication to the API (username is "testing", password is "123456"). However, when trying to call that API from my web form, I keep getting the "(401) Unauthorized" message. What should I change in the web code to call the API successfully?
string url = String.Format("http://example.com"); //here I have the correct url for my API
HttpWebRequest requestObj = (HttpWebRequest)WebRequest.Create(url);
requestObj.Method = "Get";
requestObj.PreAuthenticate = true;
requestObj.Credentials = new NetworkCredential("testing", "123456");
HttpWebResponse responseObj = null;
responseObj = (HttpWebResponse)requestObj.GetResponse();
string strresult = null;
using (Stream stream = responseObj.GetResponseStream())
{
StreamReader sr = new StreamReader(stream);
strresult = sr.ReadToEnd();
sr.Close();
}
This is what my API searches for in terms of authentication:
actionContext.Request.Headers.Authorization.Parameter
Should I be adding a header instead of NetworkCredential or is it the same thing?
This should help:
HttpMessageHandler handler = new HttpClientHandler()
{
};
var httpClient = new HttpClient(handler)
{
BaseAddress = new Uri(url),
Timeout = new TimeSpan(0, 2, 0)
};
httpClient.DefaultRequestHeaders.Add("ContentType", "application/json");
//This is the key section you were missing
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes("testing:123456");
string val = System.Convert.ToBase64String(plainTextBytes);
httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + val);
HttpResponseMessage response = httpClient.GetAsync(url).Result;
string content = string.Empty;
using (StreamReader stream = new StreamReader(response.Content.ReadAsStreamAsync().Result, System.Text.Encoding.GetEncoding(_encoding)))
{
content = stream.ReadToEnd();
}
This is the line I needed:
requestObj.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes("username:password"));
I just found out that with .NET Core 3.1 you could do it like this:
HttpRequestMessage request = new HttpRequestMessage(
HttpMethod.Post,
"your-api-url-here");
request.Headers.Authorization = new BasicAuthenticationHeaderValue(username, password);
I think your API might need a header being added to it (if you haven't done so already). Take a look at this article:
https://en.wikipedia.org/wiki/Basic_access_authentication#Client_side
But essentially, your API will need an Authorization header added to it. The Authorization key will contain the word Basic followed by a space, then the username and password encrypted using Base64. So in your instance, testing:123456 would be encrypted using base64 as dGVzdGluZzoxMjM0NTY=. So the header record will look like this:
Authorization: Basic dGVzdGluZzoxMjM0NTY=
(Basic Authentication) Here is the other solution to call Authenticated API
class Program
{
static void Main(string[] args)
{
BaseClient clientbase = new BaseClient("https://website.com/api/v2/", "username", "password");
BaseResponse response = new BaseResponse();
BaseResponse response = clientbase.GetCallV2Async("Candidate").Result;
}
public async Task<BaseResponse> GetCallAsync(string endpoint)
{
try
{
HttpResponseMessage response = await client.GetAsync(endpoint + "/").ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
baseresponse.ResponseMessage = await response.Content.ReadAsStringAsync();
baseresponse.StatusCode = (int)response.StatusCode;
}
else
{
baseresponse.ResponseMessage = await response.Content.ReadAsStringAsync();
baseresponse.StatusCode = (int)response.StatusCode;
}
return baseresponse;
}
catch (Exception ex)
{
baseresponse.StatusCode = 0;
baseresponse.ResponseMessage = (ex.Message ?? ex.InnerException.ToString());
}
return baseresponse;
}
}
public class BaseResponse
{
public int StatusCode { get; set; }
public string ResponseMessage { get; set; }
}
public class BaseClient
{
readonly HttpClient client;
readonly BaseResponse baseresponse;
public BaseClient(string baseAddress, string username, string password)
{
HttpClientHandler handler = new HttpClientHandler()
{
Proxy = new WebProxy("http://127.0.0.1:8888"),
UseProxy = false,
};
client = new HttpClient(handler);
client.BaseAddress = new Uri(baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var byteArray = Encoding.ASCII.GetBytes(username + ":" + password);
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
baseresponse = new BaseResponse();
}
}
I want to add a record to the json service in my application. How can I do this via Service Url. Here is my code.
CustomerModel customer = new CustomerModel();
customer.Name = entryCompanyName.Text;
customer.Title = entryCompanyTitle.Text;
customer.PhoneNumber = entryTelephone.Text;
customer.FaxNumber = entryFax.Text;
customer.Email = entryEmail.Text;
customer.CityId = 6444;
string json = JsonConvert.SerializeObject(customer);
string sContentType = "application/json";
string path = "service url";
HttpClient Client = new HttpClient();
var task = Client.PostAsync(path, new StringContent(json.ToString(), Encoding.UTF8, sContentType));
I'm trying M. Wiśnicki's solution, but I took this error
I did not get an error when I added System.net :( Where do i make mistakes?
This worked for me
public static async Task<string> PostEntityToApi<T>(string yourMethodUrl, T yourModel)
{
try
{
if (_httpClient == null)
{
_httpClient = new HttpClient { BaseAddress = new Uri(yourWebSiteUrl) };
}
var stringContentInput = new StringContent(JsonConvert.SerializeObject(dto), Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(new Uri(yourWebSiteUrl. + apiUrl), stringContentInput);
if (!response.IsSuccessStatusCode)
{
throw new Exception(response.StatusCode.ToString());
}
var stringAsync = await response.Content.ReadAsStringAsync();
LoggingManager.Error("Received error response: " + stringAsync);
return stringAsync;
}
catch (Exception exception)
{
return null;
}
}
You can use WebRequest, this sample working for me, i use it in my app.
This is System.Net.WebRequest class, here you find doc.
public async Task<string> PostSample(object data, string uri)
{
// Create an HTTP web request using the URL:
var request = (HttpWebRequest) WebRequest.Create(new Uri(uri));
request.ContentType = "application/json";
request.Method = "POST";
var itemToSend = JsonConvert.SerializeObject(data);
using (var streamWriter = new StreamWriter(await request.GetRequestStreamAsync()))
{
streamWriter.Write(itemToSend);
streamWriter.Flush();
streamWriter.Dispose();
}
// Send the request to the server and wait for the response:
using (var response = await request.GetResponseAsync())
{
// Get a stream representation of the HTTP web response:
using (var stream = response.GetResponseStream())
{
var reader = new StreamReader(stream);
var message = JsonConvert.DeserializeObject<string>(reader.ReadToEnd());
return message;
}
}
}
I have done POSTING and GETing from server using string post data, but now i have the next WebService:
submitFeedback(String token, String subject, String body, byte[] photo, byte[] video);
private void PostFeedbackData()
{
if (GS.online != true)
{
MessageBox.Show(GS.translations["ErrorMsg0"]);
}
else
{
HttpWebRequest request = HttpWebRequest.CreateHttp("https://****/feedback");
request.Method = "POST";
request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);
}
}
void GetRequestStreamCallback(IAsyncResult callbackResult)
{
HttpWebRequest myRequest = (HttpWebRequest)callbackResult.AsyncState;
// End the stream request operation
Stream postStream = myRequest.EndGetRequestStream(callbackResult);
// Create the post data
string postData = "";
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
postData = "{\"jsonrpc\": \"2.0\", \"method\": \"getUserSchedule\", \"params\":[" + "\"" + (App.Current as App).UserToken + "\",\"" + FeedbackTitle.Text + "\",\"" + FeedbackContent.Text + "\",\"" + imageBytes + "\"], \"id\": 1}";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Add the post data to the web request
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
// Start the web request
myRequest.BeginGetResponse(new AsyncCallback(GetResponsetStreamCallback), myRequest);
});
}
Look at post data - it is a string, i can't place there imageBytes array. How to do it?
Is there any reason for using HttpWebRequest ?
I am asking that because i think that the correct way of sending files to a service is by multipartform data. With HttpWebRequest you have to manually implement that.
Here is an example that is using Microsoft's HttpClient that might work for you:
public async Task<string> submitFeedback(String token, String subject, String body, byte[] photo, byte[] video) {
var client = new HttpClient();
var content = new MultipartFormDataContent();
// Some APIs do not support quotes in boundary field
foreach (var param in content.Headers.ContentType.Parameters.Where(param => param.Name.Equals("boundary")))
param.Value = param.Value.Replace("\"", String.Empty);
var tok = new StringContent(token);
content.Add(tok, "\"token\"");
var sub = new StringContent(subject);
content.Add(tok, "\"subject\"");
// Add the Photo
var photoContent = new StreamContent(new MemoryStream(photo));
photoContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"photo\"",
FileName = "\"photoname.jpg\""
};
photoContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
content.Add(photoContent);
// Add the video
var videoContent = new StreamContent(new MemoryStream(video));
videoContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"video\"",
FileName = "\"videoname.jpg\""
};
videoContent.Headers.ContentType = MediaTypeHeaderValue.Parse("video/mp4");
content.Add(videoContent);
HttpResponseMessage resp;
try {
resp = await client.PostAsync("SERVER_URL_GOES_HERE", content);
}
catch (Exception e)
{
return "EXCEPTION ERROR";
}
if (resp.StatusCode != HttpStatusCode.OK)
{
return resp.StatusCode.ToString();
}
var reponse = await resp.Content.ReadAsStringAsync();
return reponse;
}
Change accordingly.
Note: HttpClient is also using HttpWebRequest under the hood.
Also I don't think its a good idea to have the UI thread making the request. That makes no sense since you are blocking the interface and making the async theory useless.
I have searched everywhere and have not found an answer to my question. Let me get straight to the point. I have developed an android messaging app for the purpose of experimenting with C2DM. My app get's the registration ID and it gets displayed in my Log correctly. I then send that key through to my C# web service.
The C# Web service then applies for an auth token, which works fine. No problem so far. But, as soon as I POST my body items (registration_id, collapse_key, data.<key>, delay_while_idle) with my header(GoogleLogin auth=[AUTH_TOKEN]) I get the response: "Error=InvalidRegistration".
There is no reason for this not to work. And yes, I have tried every solution available here in stack overflow, but remained unsuccessful. Here is my main code for my server side:
WebRequest theRequest;
HttpWebResponse theResponse;
ArrayList theQueryData;
theRequest = WebRequest.Create("https://www.google.com/accounts/ClientLogin");
theRequest.Method = "POST";
theQueryData = new ArrayList();
String [] test = new String[5];
test[0] = "accountType=HOSTED_OR_GOOGLE";
test[1] = "Email=XXXXXXXXXXXXXXXXX";
test[2] = "Passwd=XXXXXXXXXXXXXXXX";
test[3] = "Source=Domokun";
test[4] = "service=ac2dm";
// Set the encoding type
theRequest.ContentType = "application/x-www-form-urlencoded";
// Build a string containing all the parameters
string Parameters = String.Join("&", (String[])test);
theRequest.ContentLength = Parameters.Length;
// We write the parameters into the request
StreamWriter sw = new StreamWriter(theRequest.GetRequestStream());
sw.Write(Parameters);
sw.Close();
// Execute the query
theResponse = (HttpWebResponse)theRequest.GetResponse();
StreamReader sr = new StreamReader(theResponse.GetResponseStream());
String value = sr.ReadToEnd();
String token = ParseForAuthTokenKey(value);
String value2 = "";
if (value != null)
{
WebRequest theRequest2;
HttpWebResponse theResponse2;
ArrayList theQueryData2;
theRequest2 = WebRequest.Create("http://android.clients.google.com/c2dm/send");
theRequest2.Method = "POST";
theQueryData2 = new ArrayList();
String[] test2 = new String[4];
test[0] = "registration_id=" + registerid;
test[1] = "collapse_key=0";
test[2] = "data.payload=Jannik was hier";
test[3] = "delay_while_idle=0";
// Set the encoding type
theRequest2.ContentType = "application/x-www-form-urlencoded";
// Build a string containing all the parameters
string Parameters2 = String.Join("&", (String[])test2);
theRequest2.ContentLength = Parameters2.Length;
theRequest2.Headers.Add(HttpRequestHeader.Authorization, "GoogleLogin auth=" + token);
// We write the parameters into the request
StreamWriter sw2 = new StreamWriter(theRequest2.GetRequestStream());
sw2.Write(Parameters2);
sw2.Close();
// Execute the query
theResponse2 = (HttpWebResponse)theRequest2.GetResponse();
StreamReader sr2= new StreamReader(theResponse2.GetResponseStream());
value2 = sr2.ReadToEnd();
public static bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
return true;
}
private static string ParseForAuthTokenKey(string webResponse)
{
string tokenKey = String.Empty;
if (webResponse.Contains(AuthTokenHeader))
{
tokenKey = webResponse.Substring(webResponse.IndexOf(AuthTokenHeader) + AuthTokenHeader.Length);
if (tokenKey.Contains(Environment.NewLine))
{
tokenKey.Substring(0, tokenKey.IndexOf(Environment.NewLine));
}
}
return tokenKey.Trim();
}
All I can think is that my C2DM account isn't registered correctly. Could this be it? Or are there an error in my code that I'm missing?
OK. I've found the solution.
string requestBody = string.Format("registration_id={0}&collapse_key{1}&data.key=value",
HttpUtility.UrlEncode(registrationId), "collapse");
string responseBody = null;
WebHeaderCollection requestHeaders = new WebHeaderCollection();
WebHeaderCollection responseHeaders = null;
requestHeaders.Add(HttpRequestHeader.Authorization, string.Format("GoogleLogin auth={0}", authToken));
httpClient.DoPostWithHeaders(c2dmPushUrl,
requestBody,
"application/x-www-form-urlencoded",
out responseBody,
out responseHeaders,
requestHeaders);
public bool DoPostWithHeaders(string url,
string requestBody,
string contextType,
out string responseBody,
out WebHeaderCollection responseHeaders,
WebHeaderCollection requestHeaders = null)
{
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
// FIRST SET REQUEST HEADERS
httpWebRequest.Headers = requestHeaders;
httpWebRequest.Method = "POST";
// THEN SET CONTENT TYPE - THE ORDER IS IMPORTANT
httpWebRequest.ContentType = contextType;
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] data = encoding.GetBytes(requestBody);
httpWebRequest.ContentLength = data.Length;
stream = httpWebRequest.GetRequestStream();
stream.Write(data, 0, data.Length);
....
....
....
}