C# https request always tunnel to server but Java only once - c#

I'm converting JAVA program to C# that send https request to server. Here is my program that log in to server and then log-out from server.
var login_httpWebRequest = (HttpWebRequest)WebRequest.Create(m_base_url + "session/login");
login_httpWebRequest.ContentType = "application/json; charset=UTF-8";
var logout_httpWebRequest = (HttpWebRequest)WebRequest.Create(m_base_url + "session/logout");
logout_httpWebRequest.ContentType = "application/json; charset=UTF-8";
CookieContainer cookieJar = new CookieContainer();
login_httpWebRequest.CookieContainer = cookieJar;
using (StreamWriter streamWriter = new StreamWriter(login_httpWebRequest.GetRequestStream()))
{
streamWriter.Write("{username:xxxxxx,password:yyyyyyy}");
}
var httpResponse = (HttpWebResponse)login_httpWebRequest.GetResponse();
var login_cookies = httpResponse.Cookies;
logout_httpWebRequest.CookieContainer = new CookieContainer();
httpWebRequest.CookieContainer.Add(login_cookies);
using (StreamWriter streamWriter = new StreamWriter(logout_httpWebRequest.GetRequestStream()))
{
streamWriter.Write("{}");
}
var httpResponse = (HttpWebResponse)login_httpWebRequest.GetResponse();
But my C# program takes more time than the original JAVA program and then I checked the request using Fiddler tool. So I found for every request C# Tunnel to server. but JAVA program only once.
Bellow image
Green color shows requests (tunnel->login->logout) sent to server by JAVA program.
Red color shows C# program requests(tunnel->login->tunnel->logout) sent to server by C# program.
Anyone knows how to avoid tunneling for each request by C# Http client.

Have you tried using HttpClient instead of WebRequest? I wrote this up with no way to test it so hopefully it's close....
using (HttpClientHandler handler = new HttpClientHandler())
{
CookieContainer cookies = new CookieContainer();
handler.CookieContainer = cookies;
using (HttpClient httpClient = new HttpClient(handler))
{
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json; charset=UTF-8"));
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, m_base_url + "session/login");
requestMessage.Content = new StringContent("{username:xxxxxx,password:yyyyyyy}"); ;
HttpResponseMessage loginResponse = await httpClient.SendAsync(requestMessage);
// The HttpClient should already have the cookies from the login so
// no need to transfer
requestMessage = new HttpRequestMessage(HttpMethod.Get, m_base_url + "session/logout");
requestMessage.Content = new StringContent("{}");
HttpResponseMessage logoutResponse = await httpClient.SendAsync(requestMessage);
}
}

Related

Sending serialized data in Get/Post Requests

Hi I have a method in my webservice as follows
[HttpGet]
public HttpResponseMessage RegenerateReport(/*string reportObject*/)
{
var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StringContent("Operation completed.");
return result;
}
It works fine but i actually want to be able to send a serialized JSON object to this function.
Alternatively, I tried using [HttpPost] tag on this function and calling from my code as follows
var data = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(obj));
string _BaseUrl = ConfigurationManager.AppSettings["WebAPIBaseURL"];
HttpWebRequest request = WebRequest.Create(string.Format("{0}{1}",
_BaseUrl,
"test/RegenerateReport?FileName=" + RCFileName)) as HttpWebRequest;
// Set type to POST
request.Method = "Post";
request.ContentType = "application/xml";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
It returns
The requested resource does not support http method 'GET'.
Update
This error is now removed as i have added both tags [HttpGet] and [HttpPost] to my web method. Now the thing is how to pass serialized object to the web service method. Thanks!
If you want to submit some data in web service, you should always use [HttpPost].
I think your consumer is wrong and not doing a POST request. I typically use Microsoft.AspNet.WebApi.Client package and the sample code may look like this:
static async Task TestApiAsync()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:33854/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var result = await client.PostAsync("api/School", "hello", new JsonMediaTypeFormatter());
result.EnsureSuccessStatusCode();
// if it something returns
string resultString = await result.Content.ReadAsAsync<string>();
Console.WriteLine(resultString);
}
}
Just substitute the parameters for your need (URL, type, body)
As told by #MacakM, while HttpClient seems to be the ultimate solution I am sharing the exact code that worked for me.
HttpClient _client = new HttpClient();
var apiParams = new Dictionary<string, string>();
apiParams.Add("FileName", RCFileName ?? string.Empty);
string _BaseUrl = ConfigurationManager.AppSettings["WebAPIBaseURL"];
_client.BaseAddress = new Uri(_BaseUrl);
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = _client.GetAsync(string.Format("{0}{1}",
_BaseUrl,
"test/RegenerateReport?FileName=" + RCFileName)
);
if (response.IsCompleted)
_client.Dispose();//Dispose the client object

write a http post request to bot framework running on localhost

I have a bot running on http://localhost:3978/api/messages.
Instead of debugging it using an emulator, can I go about using a http post request to the messaging endpoint of the bot?
If so, how do I go about doing it?
I am using c# microsoft bot framework, and I am new to this application.
I do not want to use any channels or DirectLine api, just using Httpclient.
You can do this with C# using code similar to below. Note that you would have to construct an Activity to send by setting the appropriate properties for your needs, which is not included in this code.
//make a call to get an auth token
string token;
using (var client = new WebClient())
{
var values = new NameValueCollection();
values["grant_type"] = "client_credentials";
values["client_id"] = "YOUR APP ID";
values["client_secret"] = "NcOXRwb51joibEfzUuNE04u";
values["scope"] = "YOUR APP ID/.default";
var response =
client.UploadValues("https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token", values);
var responseString = Encoding.Default.GetString(response);
var result = JsonConvert.DeserializeObject<ResponseObject>(responseString);
token = result.access_token;
}
//you will need to adjust this value for your project.
//this example for a proxy project so the service url here is
//just an arbitrary endpoint I was using to send activities to
activity.ServiceUrl = "http://localhost:4643/api/return";
var jsonActivityAltered = JsonConvert.SerializeObject(activity);
using (var client = new WebClient())
{
client.Headers.Add("Content-Type", "application/json");
client.Headers.Add("Authorization", $"Bearer {token}");
try
{
var btmResponse = client.UploadString("http://localhost:3971/api/messages", jsonActivityAltered);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
Have you tried using something like postman? (it's free and easy to use)
https://www.getpostman.com/
You can also write scripts in postman
otherwise you can just go to the endpoint of your API in the browser
http://localhost:3978/api/
I see you mentioned you wanted to make a console application.
You could do that. I'd suggest using postman though.
Here is an example of sending a file as well as some querystring data and Authentication using a Bearer token.
Sorry it may not be exact. Had to do a bit of copy pasting/deleting from some code examples if have
using (HttpClient client = new HttpClient())
{
JObject jsonModel = new JObject();
client.BaseAddress = new Uri("http://localhost:3978/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken);
using (var multipartFormDataContent = new MultipartFormDataContent())
{
var values = new[]
{
new KeyValuePair<string, string>("firstname", lastname),
new KeyValuePair<string, string>("lastname", lastname),
new KeyValuePair<string, string>("payloadFile", FileName)
};
foreach (var keyValuePair in values)
{
multipartFormDataContent.Add(new StringContent(keyValuePair.Value),
String.Format("\"{0}\"", keyValuePair.Key));
}
ByteArrayContent fileContent = new ByteArrayContent(File.ReadAllBytes(HttpContext.Current.Server.MapPath("~/uploads/output/" + FileName)));
string FullxmlString = File.ReadAllText(Path.Combine(HttpContext.Current.Server.MapPath("~/uploads/output/" + FileName)));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("payloadFile") { FileName = "payloadFile" };
multipartFormDataContent.Add(fileContent);
HttpResponseMessage response = client.PostAsync("api/message", multipartFormDataContent).Result;
string returnString = response.Content.ToString();
using (HttpContent content = response.Content)
{
string res = "";
Task<string> result = content.ReadAsStringAsync();
res = result.Result;
}
}
}

Emulating Curl --user --insecure in c#

I have the following Curl Call that works.
curl --insecure --user user#applicationname:password "https://someURL"
I cannot for the life of me get HttpWebRequest to emulate this.
Currently I am trying
var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://someURL);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Accept = "*/*";
httpWebRequest.Method = "POST";
httpWebRequest.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("USER#Account:Password"));
I am getting the error Authentication failed because the remote party has closed the transport stream
I am guessing it has to do with the curl command having the insecure option but I cannot for the life of me see how to do this in the request.
Do to network restrictions/policies I cannot download restSharp or any other 3rd party libraries...
Add this line before doing the request
System.Net.ServicePointManager.ServerCertificateValidationCallback = (obj, X509certificate, chain, errors) => true;
I ended up using HttpClient instead. In combination with using the info obtained from #Alberto Monteiro above, I was able to get the my code to work as expected.
string url = Request.Form["Url"];
using (var client = new HttpClient())
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11;
ServicePointManager.ServerCertificateValidationCallback = (obj, x509Certificate, chain, errors) => true;
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("text/xml"));
var byteArray = Encoding.ASCII.GetBytes(Request.Form["User"] + "#ACCOUNT:" + Request.Form["Pass"]);
var header = new AuthenticationHeaderValue(
"Basic", Convert.ToBase64String(byteArray));
client.DefaultRequestHeaders.Authorization = header;
var response = client.GetAsync(url).Result;
HttpContent content = response.Content;
string result = content.ReadAsStringAsync().Result;
}

Windows 8.1 store app Download file using authentication and header

I'm trying to download a file from a server and adding authentication and range header in my app, so is this syntax correct?
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
request.Headers["Range"] = "bytes=0-";
request.Credentials = new NetworkCredential("username","password");
Of course the code has other parts for reading the file as a stream and storing it but i'm concerned with the range header and authentication part because it's not working.
I get an exception
{"The 'Range' header must be modified using the appropriate property or method.\r\nParameter name: name"}
Here's how to do it:
public async Task<byte[]> DownloadFileAsync(string requestUri)
{
// Service URL
string serviceURL = "http://www.example.com";
// Http Client Handler and Credentials
HttpClientHandler httpClientHandler = new HttpClientHandler();
httpClientHandler.Credentials = new NetworkCredential(username, passwd, domain);
// Initialize Client
HttpClient client = new HttpClient(httpClientHandler)
client.BaseAddress = new Uri(serviceURL);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/bson"));
// Add Range Header
client.DefaultRequestHeaders.Add("Range", "bytes=0-");
// Deserialize
MemoryStream result = new MemoryStream();
Stream stream = await client.GetStreamAsync(requestUri);
await stream.CopyToAsync(result);
result.Seek(0, SeekOrigin.Begin);
// Bson Reader
byte[] output = null;
using (BsonReader reader = new BsonReader(result))
{
var jsonSerializer = new JsonSerializer();
output = jsonSerializer.Deserialize<byte[]>(reader);
}
return output;
}
I'm current using the BSON media format. If you need addtional information regarding BSON in your backend, herre's a great article on how to implement it and consume it:
http://www.strathweb.com/2012/07/bson-binary-json-and-how-your-web-api-can-be-even-faster/
Here is another way to do it
var httpClientHandler = new HttpClientHandler();
httpClientHandler.Credentials = new System.Net.NetworkCredential("username", "password");
var client = new HttpClient(httpClientHandler);
System.Net.Http.HttpRequestMessage request = new System.Net.Http.HttpRequestMessage(HttpMethod.Post, new Uri(url));
request.Headers.Range = new RangeHeaderValue(0, null);
HttpResponseMessage response = await client.SendAsync(request);

RestSharp - Authorization Header not coming across to WCF REST service

I am trying to call a locally hosted WCF REST service over HTTPS with basic auth.
This works and the Authorization header comes thru just fine and all is happy:
ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertficate;
var request = (HttpWebRequest)WebRequest.Create("https://localhost/MyService/MyService.svc/");
request.Method = "GET";
request.ContentType = "application/json";
request.Headers.Add(
System.Net.HttpRequestHeader.Authorization,
"Basic " + this.EncodeBasicAuthenticationCredentials("UserA", "123"));
WebResponse webResponse = request.GetResponse();
using (Stream webStream = webResponse.GetResponseStream())
{
if (webStream != null)
{
using (StreamReader responseReader = new StreamReader(webStream))
{
string response = responseReader.ReadToEnd();
}
}
}
When I try to use RestSharp however, the Authorization header never comes thru on the request:
ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertficate;
var credentials = this.EncodeBasicAuthenticationCredentials("UserA", "123");
var client = new RestSharp.RestClient("https://localhost/MyService/MyService.svc/");
var restRq = new RestSharp.RestRequest("/");
restRq.Method = Method.GET;
restRq.RootElement = "/";
restRq.AddHeader("Authorization", "Basic " + credentials);
var restRs = client.Execute(restRq);
What am i doing wrong with the RestSharp method?
I know that the AddHeader method works because this:
restRq.AddHeader("Rum", "And Coke");
will come thru, only "Authorization" seems stripped out/missing.
instead of adding the header 'manually' do the following:
var client = new RestSharp.RestClient("https://localhost/MyService/MyService.svc/");
client.Authenticator = new HttpBasicAuthenticator("UserA", "123");
I used milano's answer to get my REST service call to work (using GET)
Dim client2 As RestClient = New RestClient("https://api.clever.com")
Dim request2 As RestRequest = New RestRequest("me", Method.GET)
request2.AddParameter("Authorization", "Bearer " & j.access_token, ParameterType.HttpHeader)
Dim response2 As IRestResponse = client2.Execute(request2)
Response.Write("** " & response2.StatusCode & "|" & response2.Content & " **")
The key was making sure there was a space after the word 'Bearer' but this may apply to any type of custom token authorization header
You have to use ParameterType.HttpHeader parameter:
request.AddParameter("Authorization", "data", ParameterType.HttpHeader);
I was able to get the response from my rest API using this piece of code:
My API was returning server error and I used:
request.AddHeader("Authorization", $"Bearer {accessToken}");
var request = new RestRequest("/antiforgerytokensso", Method.Get);
restClient.Authenticator = new JwtAuthenticator(accessToken);
var response = await restClient.ExecuteAsync(request);
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));

Categories

Resources