I am writing an MVC Web API the make async HttpWebRequest calls. I am getting 2 different exceptions. Below is the method I am using.
The 1st exception is: "This stream does not support seek operations." and it is happening on the responseStream.
The 2nd exception is: "timeouts are not supported on this stream" and that is happening on the MemoryStream content.
What am I doing wrong? I have been Googling but not really finding any solution.
Thanks,
Rhonda
private async Task GetHtmlContentAsync(string requestUri, string userAgent, string referrer, bool keepAlive, TimeSpan timeout, bool forceTimeoutWhileReading, string proxy, string requestMethod, string type)
{
//string to hold Response
string output = null;
//create request object
var request = (HttpWebRequest)WebRequest.Create(requestUri);
var content = new MemoryStream();
request.Method = requestMethod;
request.KeepAlive = keepAlive;
request.Headers.Set("Pragma", "no-cache");
request.Timeout = (Int32)timeout.TotalMilliseconds;
request.ReadWriteTimeout = (Int32)timeout.TotalMilliseconds;
request.Referer = referrer;
request.Proxy = new WebProxy(proxy);
request.UserAgent = userAgent;
try
{
using (WebResponse response = await request.GetResponseAsync().ConfigureAwait(false))
{
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
{
await responseStream.CopyToAsync(content);
}
}
var sr = new StreamReader(content);
output = sr.ReadToEnd();
sr.Close();
}
}
catch (Exception ex)
{
output = string.Empty;
var message = ("The API caused an exception in the " + type + ".\r\n " + requestUri + "\r\n" + ex);
Logger.Write(message);
}
return output;
}
I fixed the issue by adding
content.Position = 0
before new StreamReader line. Now I just need to get it work with GZip compression.
Rhonda
Related
I am provided a webservice url similar to:
http://ericdev35:7280/persons/persons/
and a username and password.
I want to make a post call on this web service from WPF application.
The data to be sent to the service is the first name and last name of a person in the format:
"fname=Abc&lname=Xyz"
How can I make a call for this in C#?
Here is the code that I have tried:
HttpWebRequest httpWebRequest = (HttpWebRequest) WebRequest.Create("http://ericdev35:7280/persons/persons/");
httpWebRequest.Method = "POST";
httpWebRequest.ContentType = "application/json";
httpWebRequest.Credentials = new NetworkCredential(username, password);
string data = "fname=Abc&lname=Xyz";
StreamWriter writer = new StreamWriter(httpWebRequest.GetRequestStream());
writer.Write(data);
writer.Close();
This does not give me any error but I cannot see the data that I have posted. Is there anything that needs to be corrected?
Is the Content Type correct?
This Method posts json.
After that it gets the response and deserialize the Json Object.
private static string PostJson<T1>(string p_url, string p_json, string p_method, out T1 p_target)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(p_url);
httpWebRequest.UseDefaultCredentials = true;
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = p_method;
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(p_json);
streamWriter.Flush();
streamWriter.Close();
}
HttpWebResponse httpResponse;
try
{
httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
}
catch (WebException ex)
{
httpResponse = ex.Response as HttpWebResponse;
}
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var a_result = streamReader.ReadToEnd();
//If you dont need a Json object delete anything behind here
try
{
p_target = JsonConvert.DeserializeObject<T1>(a_result);
}
catch { p_target = default(T1); }
return a_result;
}
}
I have application that sends requests to same REST server constantly and after some time HttpWebRequest.GetResponse() starts timing out i've noticed that whenever i increase System.Net.ServicePointManager.DefaultConnectionLimit it takes it longer to start timing out again, which should mean that those requests are staying active, but as far as i know i'm closing all of them.
Here is method i'm using for my requests.
Current DefaultConnectionLimit is set to 10.
Also there is 1 request that is going on throughout most of applications lifetime.
I'm using .NET Compact framework and REST server is written using WCF (.NET 4.5)
public static string HttpRequest(string request, string method, string contentType, int timeout)
{
string result = "";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(PodesavanjaManager.TrenutnaPodesavanja.PutanjaServisa + "/" + request);
req.Method = method;
req.ContentType = contentType;
req.Timeout = timeout;
req.KeepAlive = false;
if(method == "POST")
req.ContentLength = 0;
using(Stream stream = req.GetResponse().GetResponseStream())
{
using(StreamReader reader = new StreamReader(stream))
{
result = reader.ReadToEnd();
reader.Close();
}
stream.Close();
stream.Flush();
}
return result;
}
EDIT new version of method:
public static string HttpRequest(string request, string method, string contentType, int timeout)
{
string result = "";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(PodesavanjaManager.TrenutnaPodesavanja.PutanjaServisa + "/" + request);
req.Method = method;
req.ContentType = contentType;
req.Timeout = timeout;
req.KeepAlive = false;
if(method == "POST")
req.ContentLength = 0;
using (HttpWebResponse resp =(HttpWebResponse) req.GetResponse())
{
using (Stream stream = resp.GetResponseStream())
{
using (StreamReader reader = new StreamReader(stream))
{
result = reader.ReadToEnd();
reader.Close();
}
}
}
GC.Collect();
return result;
}
I agree it does behave like the connection is still in use by a resource that has not been closed. The documentation for HttpWebResponse mentions:
You must call either the Stream.Close or the HttpWebResponse.Close method to close the response and release the connection for reuse. It is not necessary to call both Stream.Close and HttpWebResponse.Close, but doing so does not cause an error.
I was hoping for a more straightforward description like "you must either close the stream returned by GetResponseStream or call the HttpWebResponse.Close method - but if my interpretation of the documentation is correct, your code is fine.
We use HttpWebRequest in our CE applications as well, and always put the response in a using block as well - you could try this:
using(HttpWebResponse response = (HttpWebResponse)req.GetResponse())
using(Stream stream = response.GetResponseStream())
{
// ...
}
Also have you checked your code for other HttpWebRequest usages, just to be sure?
I have an application that creates Survey Monkey collectors for a survey using the 'create_collector' API method. That works perfectly. The problem is that it always creates collectors with the 'Multiple Responses' set to false. I need collectors created through the API to have 'Multiple Responses' set to true. There doesn't seem to be any option in the API call to specify that.
How can I set 'Multiple Responses' to true using the 'create_collector' API?
Here is my code in c#:
class CollectorJSON
{
public string type { get; set; }
public string name { get; set; }
}
private string CreateCollectorURL = "https://api.surveymonkey.net/v2/collectors/create_collector?api_key={API_KEY_VALUE}";
public CollectorResponseJSONWrapper CreateCollector(string APIKey, string AccessToken, long SurveyId, string CollectorName)
{
_LastException = null;
CollectorResponseJSONWrapper collectorRv = new CollectorResponseJSONWrapper();
collectorRv.status = -1;
try
{
string url = CreateCollectorURL.Replace("{API_KEY_VALUE}", APIKey);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.Headers.Add("Authorization", "bearer " + AccessToken);
CollectorJSON collector = new CollectorJSON()
{
type = "weblink",
name = CollectorName
};
CollectorJSONWrapper wrapper = new CollectorJSONWrapper()
{
survey_id = SurveyId.ToString(),
collector = collector
};
string JSONData = JsonConvert.SerializeObject(wrapper);
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] bytes = encoding.GetBytes(JSONData);
request.ContentType = "application/json";
request.ContentLength = bytes.Length;
Stream rstream = request.GetRequestStream();
rstream.Write(bytes, 0, bytes.Length);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string responseBody = string.Empty;
using (var reader = new StreamReader(response.GetResponseStream(), ASCIIEncoding.ASCII))
{
responseBody = reader.ReadToEnd();
}
collectorRv = JsonConvert.DeserializeObject<CollectorResponseJSONWrapper>(responseBody);
}
catch( Exception ex )
{
_LastException = ex;
}
return collectorRv;
}
Thanks,
This was not supported in API v2 but can now be done using API v3, https://developer.surveymonkey.com/api/v3/#surveys-id-collectors
By setting the field allow_multiple_responses when doing a POST to /surveys/{id}/collectors to create a new collector.
Saving data in windows phone received from WCF/web service .
The response may be received after sometime so how to handle this situation.
Saving data is no problem but How to handel if data is received late
You can use this code (show the code from my project):
public void sendPost(string postData, Action<MyResponse, Exception> callback, CreateResponse creater)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(UrlRequest);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Accept = "application/json";
webRequest.AllowAutoRedirect = true;
webRequest.BeginGetRequestStream(new AsyncCallback(getRequestStreamCallback), new Request()
{
HttpRequest = webRequest,
PostData = postData,
Url = UrlRequest,
CallBack = callback,
Creater = creater
});
}
private void getRequestStreamCallback(IAsyncResult asynchronousResult)
{
var request = (Request)asynchronousResult.AsyncState;
// End the stream request operation
Stream postStream = request.HttpRequest.EndGetRequestStream(asynchronousResult);
byte[] byteArray = Encoding.UTF8.GetBytes(request.PostData);
// Add the post data to the web request
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
// Start the web request
request.HttpRequest.BeginGetResponse(new AsyncCallback(getResponseCallback), request);
}
private void getResponseCallback(IAsyncResult asynchronousResult)
{
var request = (Request)asynchronousResult.AsyncState;
try
{
HttpWebResponse response;
// End the get response operation
response = (HttpWebResponse)request.HttpRequest.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamReader = new StreamReader(streamResponse);
var myResponse = streamReader.ReadToEnd();
streamResponse.Close();
streamReader.Close();
response.Close();
MyResponse response_obj = request.Creater.CreateResponseObj();
using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(myResponse)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(response_obj.GetType());
response_obj = (GYResponse)serializer.ReadObject(stream);
if (request.CallBack != null)
{
request.CallBack.Invoke(response_obj, null);
}
}
}
catch (WebException e)
{
if (request.CallBack != null)
{
request.CallBack.Invoke(null, e);
}
}
}
public void getInfo(string uid, Action<MyResponse, Exception> callback)
{
CreateResponse creater = new CreateResponseGetInfo();
string model = "User";
string method = "getInfo";
Params parametrs = new Params();
parametrs.Uid = uid;
//create yor request
string request = getRequestString(model, method, parametrs, Atoken);
sendPost(request, callback, creater);
}
So, you call method, which send request to web service postRequester.getInfo(uid, ResponseHandler) and use delegate for processing result.
private void ResponseHandler(MyResponse result, Exception error)
{
if (error != null)
{
string err = error.Message;
return;
}
else
{
var infoResponse = result as ResponseGetInfo;
if (infoResponse != null)
{
//result processing..
}
}
}
All the web requests you make in a Windows Phone app are Asynchronous. That means, you make a web request from your app and attach a handler to handle the response when it comes. In the response handler, you will have to take care of the response and do whatever you want with it.
Check this link Using WebClient and HttpWebRequest
I have a script sending a multi part mime ie a a soap with attachments. I am using C# httpWebRequest class. I am getting an error that says the content length is required yet I am setting the content length dynamically in my code using webrequest's contentLength property. any ideas why this could be? thanx!
this is the code:
public void sendSOAPoverHttpVoda()
{
try
{
string xmlDoc = this.soapXml;
byte[] bytes;
bytes = Encoding.UTF8.GetBytes(xmlDoc);
long contentSize = bytes.Length;
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(conectionUrl);
req.SendChunked = true;
CredentialCache credentialCacheObj = new CredentialCache();
credentialCacheObj.Add(
new Uri(conectionUrl),
"Basic", new NetworkCredential("dddfff", "dddddd"));
credentialCacheObj.Add(new Uri(conectionUrl), "Digest", new NetworkCredential("dddfff", "dddddd"));
req.Credentials = credentialCacheObj;
req.Method = "POST";
req.ProtocolVersion = HttpVersion.Version11;
req.ContentLength = xmlDoc.Length;
req.ContentType = "multipart/related; boundary=\"----=cellsmart_mm7_SOAP\";type=\"text/xml\";Start=\"</cellsmart_mm7_submit>\"";
req.AllowWriteStreamBuffering = true;
req.Timeout = 20000;
req.Headers.Add("SOAPAction", "");
//req.Connection = "";
if (bytes != null)
{
using (Stream outputStream = req.GetRequestStream())
{
outputStream.Write(bytes, 0, xmlDoc.Length);
}
}
using (HttpWebResponse response = (HttpWebResponse)req.GetResponse())
{
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
string responseText = reader.ReadToEnd();
Console.WriteLine("Response received from URI : " + responseText);
Console.ReadLine();
}
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("Error : " + ex.Message + "\n" + ex.StackTrace);
Console.ReadLine();
}
}
The error/exception i get is COntent length required (411)
You can't use both SendChunked=true and ContentLength. The easiest thing to do would be to use a chunked response and omit the ContentLength. You could also retain the ContentLength and omit the SendChunked if you want though.
In case you're not familiar with it, wikipedia has a nice description of chunking.
You declare contentLength as the length of the byte[] that you send ('bytes') and then you use the length of xmlDoc as the content length - which will give a different length than actual. Then you use the same xmlDoc.Length in outputStream.Write.
Why are you not using bytes.Length in both cases? Or contentLength which you've declared but never used, I believe that is your problem, you are sending xmlDoc.Length (Length of a string) for bytes.Length (length of a byte array converted from a string), so when the file is longer than expected by the sent length, the error returns.
Try this:
public void sendSOAPoverHttpVoda()
{
try
{
string xmlDoc = this.soapXml;
byte[] bytes;
bytes = Encoding.UTF8.GetBytes(xmlDoc);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(conectionUrl);
req.SendChunked = true;
CredentialCache credentialCacheObj = new CredentialCache();
credentialCacheObj.Add(
new Uri(conectionUrl),
"Basic", new NetworkCredential("dddfff", "dddddd"));
credentialCacheObj.Add(new Uri(conectionUrl), "Digest", new NetworkCredential("dddfff", "dddddd"));
req.Credentials = credentialCacheObj;
req.Method = "POST";
req.ProtocolVersion = HttpVersion.Version11;
req.ContentLength = bytes.Length;
req.ContentType = "multipart/related; boundary=\"----=cellsmart_mm7_SOAP\";type=\"text/xml\";Start=\"</cellsmart_mm7_submit>\"";
req.AllowWriteStreamBuffering = true;
req.Timeout = 20000;
req.Headers.Add("SOAPAction", "");
//req.Connection = "";
if (bytes != null)
{
using (Stream outputStream = req.GetRequestStream())
{
outputStream.Write(bytes, 0, bytes.Length);
}
}
using (HttpWebResponse response = (HttpWebResponse)req.GetResponse())
{
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
string responseText = reader.ReadToEnd();
Console.WriteLine("Response received from URI : " + responseText);
Console.ReadLine();
}
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("Error : " + ex.Message + "\n" + ex.StackTrace);
Console.ReadLine();
}
}