I'm working on a Silverlight app which among other things makes Http requests in which it uploads a zip file from the web server. The zip file is picked up from the web server every n:th minute, a behavior controlled by a timer.
I've tried using the WebClient and HttpWebRequest classes with the same result. The request only reaches the web server the first time. The second, third, ..., time the request is sent and a response will occur. However, the request never reaches the web server...
void _timer_Tick(object sender, EventArgs e)
{
try
{
HttpWebRequest req = WebRequest.CreateHttp(_serverUrl + "channel.zip");
req.Method = "GET";
req.BeginGetResponse(new AsyncCallback(WebComplete), req);
}
catch (Exception ex)
{
throw ex;
}
}
void WebComplete(IAsyncResult a)
{
HttpWebRequest req = (HttpWebRequest)a.AsyncState;
HttpWebResponse res = (HttpWebResponse)req.EndGetResponse(a);
Stream stream = res.GetResponseStream();
byte[] content = readFully(stream);
unzip(content);
}
Is there some kind of browser caching issue here?
I want every request I make to go all the way to the web server.
Yes, the browser may be caching the request. If you want to disable that, you can either modify the server to send a Cache-Control: no-cache header, or you can append some sort of uniquifier to the URL that will prevent the browser from caching the request:
void _timer_Tick(object sender, EventArgs e)
{
try
{
HttpWebRequest req = WebRequest.CreateHttp(_serverUrl + "channel.zip?_=" + Environment.TickCount);
req.Method = "GET";
req.BeginGetResponse(new AsyncCallback(WebComplete), req);
}
catch (Exception ex)
{
throw ex;
}
}
Chances are your timer freezes, not the web request. Put a Debug.WriteLine in your timer event, make sure it gets called more than once.
It's also a bad idea to use timers for background tasks. Instead of a timer it's a better option to create a background task that sleeps between requests. This way even too long of server request won't cause calls to overlap.
Try something in the lines of:
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork+=(s,a)=>{
try{
while (true)// or some meaningful cancellation condition is false
{
DownloadZipFile();
Sleep(FiveMinutes);
// don't update UI directly from this thread
}
} catch {
// show something to the user so they know automatic check died
}
};
worker.RunAsync();
Related
Hi all since i am new here i hope this is the right place.
i am trying out HttpWebRequest to check out the status code (in this case response) from different websites.
On ok the response is very fast and no form freeze.
On a connect failure the form freezes and take's around 5 seconds
bypassing the freezing can be done with a background worker.
But is there a way to say, there is no response in 1 second, forget this one and go to the next.
try
{
string url;
url = (LoopUrlFromListboxOrStream ) ; //example
// Creates an HttpWebRequest for the specified URL.
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
// Sends the HttpWebRequest and waits for a response.
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
if (myHttpWebResponse.StatusCode == HttpStatusCode.OK)
label1.Text = (myHttpWebResponse.StatusDescription);
// Releases the resources of the response.
myHttpWebResponse.Close();
}
catch (WebException ex)
{
label2.Text = (ex.Status.ToString());
}
catch (Exception ex)
{
label2.Text = (ex.Message.ToString());
}
Set HttpWebRequest.Timeout property to a low enough value that suits your needs.
In you case
myHttpWebRequest.Timeout = 1;
Before doing GetResponse()
I would like to write an Event Handler which triggers a method when website returns some response.
My application fetch response by posting URL's from few websites. Unfortunately at times website return response after some delay(It may take 1 to 5 seconds) and that leads my application to throw an error because next request executes without waiting for previous request to get response.
I can actually put a sleep time after every request that application posts but that doesn't seems to be right way because if I set 5 seconds as sleep time and if suppose website returns response in 1 seconds that makes process to wait for 4 more seconds unnecessarily.
To save some processing time I decide to add Event handlers which should allow application to run next request after we get response for previous request.
So I tried something like this and I can able to call trigger but it is not working the way I want.
My intention is to to create trigger which makes next request to run after getting response to the previous request and at most it can wait 5 second.
Can someone please help me in this, Thanks In advance.
public delegate void ChangedEventHandler(string response);
public class ListWithChangedEvent : EventArgs
{
public event ChangedEventHandler Changed;
protected virtual void OnChanged(string response)
{
if (Changed != null)
{
Changed(response);
}
}
public void Validate(string response)
{
OnChanged(response);
}
}
public class EventListener
{
private ListWithChangedEvent _list;
public EventListener(ListWithChangedEvent list)
{
_list = list;
_list.Changed += new ChangedEventHandler(ListChanged);
}
private void ListChanged(string response)
{
if (!response.IsEmpty())
{
return;
}
}
}
//Validating Response after request being posted
private void _postRequestAndParseResponse()
{
_performPostRequest(_returnTailPart(_urls.CommonUrl), argumentsList);
ListWithChangedEvent list = new ListWithChangedEvent();
EventListener listener = new EventListener(list);
list.Validate(_docNode.InnerHtml);
}
HTTP timeouts are a built-in function of most http clients and are the simplest way of requesting web resource with timeout specified.
If you are using WebRequest you can use its timeout property. Here's an example:
public void Test()
{
const int timeoutMs = 5000;
sw.Start();
RequestWithTimeout("https://google.com", timeoutMs);
RequestWithTimeout("http://deelay.me/7000/google.com", timeoutMs);
RequestWithTimeout("http://thisurelydoesnnotexist.com", timeoutMs);
RequestWithTimeout("http://google.com", timeoutMs);
}
private void RequestWithTimeout(string url, int timeoutMs)
{
try
{
Log("Webrequest at " + url + " starting");
WebRequest req = WebRequest.Create(url);
req.Timeout = timeoutMs;
var response = req.GetResponse();
Log("Webrequest at " + url + " finished");
}
catch (WebException webException)
{
Log("WebRequest failed: " + webException.Status);
}
catch (Exception ex)
{
Log(ex.ToString());
}
}
Output:
0ms | Webrequest at https://google.com starting
169ms | Webrequest at https://google.com finished
170ms | Webrequest at http://deelay.me/7000/google.com starting
5186ms | WebRequest failed: Timeout
5186ms | Webrequest at http://thisurelydoesnnotexist.com starting
5247ms | WebRequest failed: NameResolutionFailure
5247ms | Webrequest at http://google.com starting
5311ms | Webrequest at http://google.com finished
If you are using WebClient you can also easily configure timeouts. Check this answer out: https://stackoverflow.com/a/6994391/5056245
If you really need to implement timeout at method-calling level, check this out:
Implementing a timeout on a function returning a value
If none of those answers work for you, please tell us how are you requesting your web resources.
You have not specified how you are calling urls. If you use HttpClint (http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client) it can be done as follows:
using(var client = new HttpClient())
{
var task = client.PostAsync(url1, ..., ...);
if(!task.wait(5000))
{
//task not completed in specified interval (5 sec), take action accordingly.
}
else
{
// task completed within 5 second, take action accordingly, you can access the response using task.Result
}
// Continue with other urls as needed
}
There can be many other ways as well. Please post your code for calling urls if this doesn't answer your question.
I recently wrote an async HttpWebRequest client for our application and it works fine in .NET 3.5, but on Mono it fails to correctly write the data on to the request before sending it out.
I have confirmed the problem using wireshark to sniff the outgoing packets. The HTTP request is correctly set to POST with a JSON Content Type however the Content-Length and data are 0.
I currently get one exception:
The number of bytes to be written is greater than the specified
ContentLength.
I have tried to resolve this by manually setting the ContentLength of the WebRequest and changing the way I encode the data before giving it to the stream (I have tried both a Steam and StreamWriter).
I have also stepped through the code and debug logged the variables in the async method to ensure the data is really there. It just does not appear to be getting to the WebRequest object.
Here is the relevant code:
private void StartWebRequest(string payload) {
var httpWebRequest = (HttpWebRequest)WebRequest.Create(PortMapSleuthURL);
httpWebRequest.ContentType = "text/json";
httpWebRequest.Method = "POST";
httpWebRequest.Proxy = null; // Setting this to null will save some time.
// start an asynchronous request:
httpWebRequest.BeginGetRequestStream(GetRequestStreamCallback, new object[] {httpWebRequest, payload});
try {
// Send the request and response callback:
httpWebRequest.BeginGetResponse(FinishPortTestWebRequest, httpWebRequest);
} catch (Exception e) {
Console.WriteLine(e.Message);
PortTestException();
}
}
private void GetRequestStreamCallback(IAsyncResult asyncResult) {
try {
object[] args = (object[])asyncResult.AsyncState;
string payload = (string)args[1];
HttpWebRequest request = (HttpWebRequest)args[0];
//StreamWriter streamWriter = new StreamWriter(request.EndGetRequestStream(asyncResult), new UTF8Encoding(false));
StreamWriter streamWriter = new StreamWriter(request.EndGetRequestStream(asyncResult), Encoding.UTF8);
// Write to the request stream.
streamWriter.Write(payload);
streamWriter.Flush();
streamWriter.Close();
} catch (Exception e) {
Console.WriteLine(e.Message);
PortTestException();
}
}
I don't think you are supposed to call BeginGetResponse before EndGetRequestStream. That is, I would move that into the GetRequestStreamCallback. This is how the example on msdn works too.
I have a class that goes and grabs some data and returns it as a string. While this object is working there is a spinning icon letting the user know work is being done. The problem is the code exits before the response comes back. I stuck a
while(response == null)
In just to see whats going on and the
response = (HttpWebResponse)request.EndGetResponse(AsyncResult);
is not firing. It fires ok in a console application so I am putting this down to something I am doing that silverlight doesn't like, heres the full code:
public class HttpWorker
{
private HttpWebRequest request;
private HttpWebResponse response;
private string responseAsString;
private string url;
public HttpWorker()
{
}
public string ReadFromUrl(string Url)
{
url = Url;
request = (HttpWebRequest)WebRequest.Create(url);
request.CookieContainer = new CookieContainer();
request.AllowAutoRedirect = true;
request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6";
AsyncRequest(); // The Demon!
return responseAsString;
}
private void AsyncRequest()
{
request.BeginGetResponse(new AsyncCallback(FinaliseAsyncRequest), null);
}
private void FinaliseAsyncRequest(IAsyncResult AsyncResult)
{
response = (HttpWebResponse)request.EndGetResponse(AsyncResult);
if (response.StatusCode == HttpStatusCode.OK)
{
// Create the stream, encoder and reader.
Stream responseStream = response.GetResponseStream();
Encoding streamEncoder = Encoding.UTF8;
StreamReader responseReader = new StreamReader(responseStream, streamEncoder);
responseAsString = responseReader.ReadToEnd();
}
else
{
throw new Exception(String.Format("Response Not Valid {0}", response.StatusCode));
}
}
}
Are you going into the busy loop with (while response == null) on the UI thread? The async callback for the HttpRequest will be delivered on the UI thread, so if you're looping on that same thread, the callback can never run. You need to return to allow the main message loop to run, and then your async callback will be delivered.
Your design above suggests that what you really want is a synchronous fetch anyway. Forget the callback and just call FinaliseAsyncRequest inside ReadFromUrl yourself. The UI will hang until the request completes, but it sounds like that's what you want.
I posted a working sample here of using WebClient and HttpWebRequest.
WebClient, HttpWebRequest and the UI Thread on Windows Phone 7
Note the latter is preferred for any non trivial processing to avoid blocking the UI.
Feel free to reuse the code.
The easiest way to get a string from a web server is to use WebClient.DownloadStringAsync() (MSDN docs).
Try something like this:
private void DownloadString(string address)
{
WebClient client = new WebClient();
Uri uri = new Uri(address);
client.DownloadStringCompleted += DownloadStringCallback;
client.DownloadStringAsync(uri);
StartWaitAnimation();
}
private void DownloadStringCallback(object sender, DownloadStringCompletedEventArgs e)
{
// Do something with e.Result (which is the returned string)
StopWaitAnimation();
}
Note that the callback executes on the UI thread and so you should only use this method if your callback method is not doing very much as it will block the UI while it executes.
If you need more control over the web request then you can use HttpWebRequest.
If you really must imitate synchronous behaviour have a look at Faking synchronous calls in Silverlight WP7
I am writing a program. my program receive data from a server through HTTP protocol. the data will be pushed by server to my program.
I tried to use WebRequest, but only received one session of data.
How can i keep the connection alive, to receive the data from server continuosly,
Any help is appreciated.
the following is the SDK document:
Under the authorization of GUEST or ADMIN, it is possible to get the series of live images
(Server push). To get the images, send the request to “/liveimg.cgi?serverpush=1” as shown
in the Figure. 2-1-1.
When the camera receives the above request from the client, it sends the return as shown
in the Figure. 2-2.
Each JPEG data is separated by “--myboundary”, and “image/jpeg” is returned as
“Content-Type” header, after “--myboundary”. For “Content-Length” header, it returns the
number of bytes in the --myboundary data (excluding “--myboundary”, each header, and
\r\n as delimiter). After the “Content-Length” header and “\r\n” (delimiter), the actual
data will be sent.
This data transmission will continue until the client stop the connection (disconnect), or
some network error occurs.
int len;
string uri = #"http://192.168.0.2/liveimg.cgi?serverpush=1";
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
req.Credentials = new NetworkCredential("admin", "admin");
req.KeepAlive = true;
string line = "";
HttpWebResponse reply = (HttpWebResponse)req.GetResponse();
Stream stream = reply.GetResponseStream();
System.Diagnostics.Debug.WriteLine(reply.ContentType);
StreamReader reader = new StreamReader(stream);
do
{
line = reader.ReadLine();
System.Diagnostics.Debug.WriteLine(line);
System.Threading.Thread.Sleep(300);
} while (line.Length>0);
You can keep an HTTP connection open for an extended period of time, if the server supports doing so. (As already mentioned, this will significantly limit the number of simultaneous users you can support.)
The server will need to be set Response.Buffer=false, and have an extended ScriptTimeout (I'm assuming your using ASP.NET on the server side). Once you do that, your page can keep sending Response.Write data as needed until whatever it is doing is done.
Your client will need to process the incoming Response before the connection is complete rather than blocking for the complete response.
You may want to take a look at StreamHub Push Server - its a popular Comet server and has an .NET Client SDK which allows you to receive real-time push updates in C# (or VB / C++).
If I'm understanding you correctly, your server is going to respond to some event by sending data to your client outside of the client making a request/response. Is this correct? If so, I wouldn't recommend trying to keep the connection open unless you have a very small number of clients -- there are a limited number of connections available, so keeping them open may rapidly result in an exception.
Probably the easiest solution would be to have the clients poll periodically for new data. This would allow you to use a simple server and you'd only have to code a thread on the client to request any changes or new work once every minute or thirty seconds or whatever your optimal time period is.
If you truly want to have the server notify the clients proactively, without them polling, then you'll have to do something other than a simple web server -- and you'll also have to code and configure the client to accept incoming requests. This may be difficult if your clients are running behind firewalls and such. If you go this route, WCF is probably your best choice, as it will allow you to configure server and client appropriately.
You need to get a cookie from IP cam and include that cookie in header of your next HttpWebRequest. Otherways it will always try to redirect you to "index.html".
Here is how you can do it...
BitmapObject is a class that serves as a container for Jpeg image, current date and eventual error text. Once a connection is established it will pool an image every 200 ms. Same should be applicable for continuous image stream obtained through "serverpush".
public void Connect()
{
try
{
request = (HttpWebRequest)WebRequest.Create("Http://192.168.0.2/index.html");
request.Credentials = new NetworkCredential(UserName,Password);
request.Method = "GET";
response = (HttpWebResponse)request.GetResponse();
WebHeaderCollection headers = response.Headers;
Cookie = headers["Set-Cookie"];//get cookie
GetImage(null);
}
catch (Exception ex)
{
BitmapObject bitmap = new BitmapObject(Properties.Resources.Off,DateTime.Now);
bitmap.Error = ex.Message;
onImageReady(bitmap);
}
}
private Stream GetStream()
{
Stream s = null;
try
{
request = (HttpWebRequest)WebRequest.Create("http://192.168.0.2/liveimg.cgi");
if (!Anonimous)
request.Credentials = new NetworkCredential(UserName, Password);
request.Method = "GET";
request.KeepAlive = KeepAlive;
request.Headers.Add(HttpRequestHeader.Cookie, Cookie);
response = (HttpWebResponse)request.GetResponse();
s = response.GetResponseStream();
}
catch (Exception ex)
{
BitmapObject bitmap = new BitmapObject(Properties.Resources.Off,DateTime.Now);
bitmap.Error = ex.Message;
onImageReady(bitmap);
}
return s;
}
public void GetImage(Object o)
{
BitmapObject bitmap = null;
stream = GetStream();
DateTime CurrTime = DateTime.Now;
try
{
bitmap = new BitmapObject(new Bitmap(stream),CurrTime);
if (timer == null)//System.Threading.Timer
timer = new Timer(new TimerCallback(GetImage), null, 200, 200);
}
catch (Exception ex)
{
bitmap = new BitmapObject(Properties.Resources.Off, CurrTime);
bitmap.Error = ex.Message;
}
finally
{
stream.Flush();
stream.Close();
}
onImageReady(bitmap);
}
If you are using a standard web server, it will never push anything to you - your client will have to periodically pull from it instead.
To really get server push data you have to build such server yourself.