Why Can I Only Call GetResponseStream() Once - c#

I've just noticed some behavior in C# that's thrown me off a little. I'm using C# 5 and .NET 4.5. When I call GetResponseStream() on a HTTPResponse object I am able to get the response stream, but if I call it again on the same object the response is blank.
// Works! Body of the response is in the source variable.
HttpResponse response = (HttpWebResponse)request.GetResponse();
String source = new StreamReader(response.GetResponseStream()).ReadToEnd();
// Does Not Work. Source is empty;
String source2 = new StreamReader(response.GetResponseStream()).ReadToEnd();
The above is just an example to demonstrate the problem.
Edit
This is what I'm trying to do. Basically if an event is attached to the HTTP object it will pass a response back to the callback method.
HttpWebResponse public Get(String url)
{
// HttpWebRequest ...
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
// postRequest is an event handler. The response is passed to the
// callback to do whatever it needs to do.
if (this.postRequest != null)
{
RequestEventArgs requestArgs = new RequestEventArgs();
requestArgs.source = response;
postRequest.Invoke(this, requestArgs);
}
return response;
}
In the callback method I may want to check the body of the response. If I do, I lose the the data from the response when Get() returns the response.

The response stream reads directly from the network connection.
Once you read it to the end (in the 2nd line), there is no more data to read.

Related

Connecting to PHP api from c# project

I have an api
http://cbastest.cadvilpos.com/module/posmodule/customapi
with parameters
{
"action":4,
"device_token": "3e8ea119a90ee6d2",
"key":"9475962085b3a1b8c475d52.95782804",
"shop":1,
"language":1
}
This is working fine in postman. But when I try to connect from c# project its showing an error {"success":0,"error":"Missing the action parameter."}. Please give a working C# code to get the json result.
The code I tried:
var request = (HttpWebRequest)WebRequest.Create("http://cbastest.cadvilpos.com/module/posmodule/customapi");
var postData = "{ 'action':'4', 'device_token':'3e8ea119a90ee6d2','key':'9475962085b3a1b8c475d52.95782804','shop':'1','language':'1'}";
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response2 = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response2.GetResponseStream()).ReadToEnd();
You don't need to use a raw HttpWebRequest object to make an HTTP call. HttpClient was introduced in 2012 to allow easy asynchronous HTTP calls.
You could do something as simple as :
var content=new StringContent(postData,Encoding.UTF8, "application/json");
HttpResponseMessage response=await httpClient.PostAsync(url,content);
//Now process the response
if (response.IsSuccessCode)
{
var body=await response.Content.ReadAsStringAsync();
var responseDTO=JsonConvert.DeserializeObject<MyDTO>(body);
}
Instead of building a JSON string by hand you could use a strongly typed class or an anonymous object and serialize it to JSON with JSON.NET :
var data=new {
action=4,
device_token="3e8ea119a90ee6d2",
key = "9475962085b3a1b8c475d52.95782804",
shop=1,
language=1
};
var postData=JsonConvert.SerializeObject(data);
var content=new StringContent(postData,Encoding.UTF8, "application/json");
var response=await httpClient.PostAsync(url,content);
...
You can read a response body in one go as a string, using ReadAsStringAsync or you can get the response stream with ReadAsStreamAsync. You could copy the response data directly to another stream, eg a file or memory stream with HttpContent.CopyToAsync
Check Call a Web API from a .NET Client for more examples. Despite the title, the examples work to call any HTTP/REST API.
The Microsoft.AspNet.WebApi.Client package mentioned in that article is another thing that applies to any call, not just calls to ASP.NET Web API. The extension method PostAsJsonAsync for example, combines serializing and posting a request to a url. Using it, posting the action DTO could be reduced to a single line:
var data=new {
action=4,
device_token="3e8ea119a90ee6d2",
key = "9475962085b3a1b8c475d52.95782804",
shop=1,
language=1
};
var response=await httpClient.PostAsJsonAsync(url,data);
There is a button in Postman that will generate code for the currently defined request. The link is here:
And this is what the code looks like. You'll need to pull in RestSharp from Nuget

c#: How to Post async request and get stream with httpclient?

I need to send async request to the server and get the information from the response stream.
I'm using HttpClient.GetStreamAsync(), but the server response that POST should be used. Is there a similar method like PostStreamAsync()? Thank you.
If you want to use HttpClient for streaming large data then you should not use PostAsync cause message.Content.ReadAsStreamAsync would read the entire stream into memory. Instead you can use the following code block.
var message = new HttpRequestMessage(HttpMethod.Post, "http://localhost:3100/api/test");
var response = await client.SendAsync(message, HttpCompletionOption.ResponseHeadersRead);
var stream = await response.Content.ReadAsStreamAsync();
The key thing here is the HttpCompletionOption.ResponseHeadersRead option which tells the client not to read the entire content into memory.
Use HttpClient.PostAsync and you can get the response stream via HttpResponseMessage.Content.ReadAsStreamAsync() method.
var message = await client.PostAsync(url, content);
var stream = await message.Content.ReadAsStreamAsync();
Instead of HttpClient, maybe you should use HttpWebRequest ?
They offer both async method and the possibility to switch between post and get by setting their method property.
e.g:
var request = (HttpWebRequest) WebRequest.Create(uri);
request.Method = "POST";
var postStream = await request.GetRequestStreamAsync()

c# HttpWebRequest and HttpWebResponse generic stuff

I am playing around with an app using HttpWebRequest to dialog with a web server.
I followed standard instructions I found on the web to build my request function that I tried to make as generic as possible (I try to get a unique method regardless of the method: PUT, POST, DELETE, REPORT, ...)
When I submit a "REPORT" request, I get two access logs on my server:
1) I get response 401 after following line is launched in debugger
reqStream.Write(Encoding.UTF8.GetBytes(body), 0, body.Length);
2) I get response 207 (multi-get, which is what I expect) after passing the line calling Request.GetResponse();
Actually, it seems to be the Request.GetRequestStream() line that is querying the server the first time, but the request is only committed once passing the reqStream.Write(...) line...
Same for PUT and DELETE, the Request.GetRequestStream() again generates a 401 access log on my server whereas the Request.GetResponse(); returns code 204.
I don't understand why for a unique request I have two server access logs, especially one that seems to be doing nothing as it always returns code 401... Could anybody explain what is going on? Is it a flaw in my code or a bad design due to my attempt to get a generic code for multiple methods?
Here is my full code:
public static HttpWebResponse getHttpWebRequest(string url, string usrname, string pwd, string method, string contentType,
string[] headers, string body) {
// Variables.
HttpWebRequest Request;
HttpWebResponse Response;
//
string strSrcURI = url.Trim();
string strBody = body.Trim();
try {
// Create the HttpWebRequest object.
Request = (HttpWebRequest)HttpWebRequest.Create(strSrcURI);
// Add the network credentials to the request.
Request.Credentials = new NetworkCredential(usrname.Trim(), pwd);
// Specify the method.
Request.Method = method.Trim();
// request headers
foreach (string s in headers) {
Request.Headers.Add(s);
}
// Set the content type header.
Request.ContentType = contentType.Trim();
// set the body of the request...
Request.ContentLength = body.Length;
using (Stream reqStream = Request.GetRequestStream()) {
// Write the string to the destination as a text file.
reqStream.Write(Encoding.UTF8.GetBytes(body), 0, body.Length);
reqStream.Close();
}
// Send the method request and get the response from the server.
Response = (HttpWebResponse)Request.GetResponse();
// return the response to be handled by calling method...
return Response;
}
catch (Exception e) {
throw new Exception("Web API error: " + e.Message, e);
}

How to wait for a server to successfully respond to an HTTP request

I am currently working with an internal API and visual studio (new to both of them). I am trying to submit a GET request to the server which will give me a JSON with the user info. One of the field in the expected JSON response is connect_status which shows true if its connecting and false once the connection is done meaning the response has been received. So far I have been working with the following using Sleep to wait for a bit until getting the response.
bool isConnected;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost");
request.Method = WebRequestMethods.Http.Get;
request.ContentType = "application/json";
System.Threading.Thread.Sleep(10000);
do
{
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream receiveStream = response.GetResponseStream();
StreamReader info = new StreamReader(receiveStream);
string json = info.ReadToEnd();
accountInfo user1 = JsonConvert.DeserializeObject<accountInfo>(json);
Console.WriteLine(jsonResponse);
isConnected = user1.connect_status;
}
while (isConnected == true);
The problem with this is that I have to wait for a longer time, the time it takes is variable and that's why I have to set a higher sleep time. Alsosomeimtes 10 seconds might not be enough and in that case when the do while loop loops the second time I get an exception at while(isConnected==true) saying
NUllReferenceException was unhandled. Object reference not set to an
instance of an object.
What would be a better/different way of doing this as I don't think the way I am doing is right.
One option here, if using .NET 4.5:
HttpMessageHandler handler = new HttpClientHandler { CookieContainer = yourCookieContainer };
HttpClient client = new HttpClient(handler) {
BaseAddress = new Uri("http://localhost")
};
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpContent content = new StringContent("dataForTheServerIfAny");
HttpResponseMessage response = await client.GetAsync("relativeActionUri", content);
string json = await response.Content.ReadAsStringAsync();
accountInfo user1 = JsonConvert.DeserializeObject<accountInfo>(json);
This way you let .NET take care of that waiting and such for you.

Invoke Url to check content type?

I need to check if the url content type is pdf or not? I have a working code however i was wondering what's the best way to check from what i have. I don't need to display the pdf, just need to check if the content type is pdf or not?
Note: This method will be called multiple times with different url, so i am not sure if i need to close the response or not.
here is my code.
private bool IsValid(string url)
{
bool isValid = false;
var request = (HttpWebRequest)WebRequest.Create(url);
var response = (HttpWebResponse)request.GetResponse();
if(response.StatusCode == HttpStatusCode.OK && response.ContentType == "application/pdf")
{
isValid = true;
}
response.Close();
return isValid;
}
Yes as you don't pass response anywhere you need to dispose it. You should also catch WebException and dispose stream from there too (also I would expect disposing response or even request would close all related resource, but unfortunately I never seen documentation that confirms such cascading dispose behavior for Response object).
You also need to close/dispose the request as it is one-use object. It is specified in note of GetResponse:
Multiple calls to GetResponse return the same response object; the request is not reissued.
Side note: Consider making HEAD request so you don't get any stream at all (see Method property for usage).
var request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "HEAD";

Categories