WebRequest problems

  • Thread starter Michael Kremser
  • Start date
M

Michael Kremser

Hi NG!

I use the following code to get something from a webserver:

Uri uri = new Uri("http://www.mkcs.at/test/somedata.4s");
System.Net.WebRequest wr = System.Net.HttpWebRequest.Create(uri);
System.IO.Stream stream = wr.GetResponse().GetResponseStream();
int b;
string strResult = string.Empty;
while ((b=stream.ReadByte())!=-1)
{
strResult += System.Text.UTF7Encoding.UTF7.GetString(new byte[] {
(byte)b },0,1);
}
stream.Close();
return strResult;

However, these lines are not working correctly. It works two times, then
it hangs in line 3. If I comment out "stream.Close();", each even call
(2nd, 4th, 6th, and so on) fails with an error:

The protocol version is not supported

I do not have any idea what I could have done wrong.

Can anyone help me, please? Or is there any other possibility in getting
some data from a webserver (except a Web Service)?

Best regards,

Michael

--
How to contact me
~~~~~~~~~~~~~~~~~
directly via mail: remove the "NOTUSEABLE" and the point after it and
reverse the characters
via my portal: go to
http://great.dynu.com/tools/contact.4s?lang=de&ref=usenet
 
J

Jon Skeet [C# MVP]

Michael Kremser said:
I use the following code to get something from a webserver:

Uri uri = new Uri("http://www.mkcs.at/test/somedata.4s");
System.Net.WebRequest wr = System.Net.HttpWebRequest.Create(uri);
System.IO.Stream stream = wr.GetResponse().GetResponseStream();
int b;
string strResult = string.Empty;
while ((b=stream.ReadByte())!=-1)
{
strResult += System.Text.UTF7Encoding.UTF7.GetString(new byte[] {
(byte)b },0,1);
}
stream.Close();
return strResult;

Well that's a pretty nasty way to convert a stream to text to start
with - use a StreamReader and just call ReadToEnd.

I suggest you also use a using statement to make sure the stream is
disposed whether or not an exception occurs.

You should *also* use a using statement to dispose of the WebResponse -
I suspect that's the problem.

Here's some sample "better" code:

string url = "http://www.mkcs.at/test/somedata.4s";
WebRequest req = WebRequest.Create(url);

using (WebResponse resp = req.GetResponse())
{
using (StreamReader reader = new StreamReader
(resp.GetResponseStream(), Encoding.UTF7))
{
return reader.ReadToEnd();
}
}
 
M

Michael Kremser

Jon Skeet [C# MVP] wrote:

Hi Jon,

Thank you for your answer!
You should *also* use a using statement to dispose of the WebResponse -
I suspect that's the problem.

Hm, that seems to be a problem, at least for the compiler:

HttpServiceAdapter.cs(50): Cannot implicitly convert type
'System.Net.WebResponse' to 'System.IDisposable'

If I change the code to

WebRequest req = WebRequest.Create(strURL);
WebResponse resp = req.GetResponse();
using (StreamReader reader = new StreamReader
(resp.GetResponseStream(), System.Text.Encoding.UTF7))
{
strResult = reader.ReadToEnd();
}

the problem occurs again that only each 2nd call is successful.

Isn't there a chance to call the WinInet-functions of Windows CE? I
found them under "Mobile and Embedded Development/Embedded Operating
System Development/Windows CE/Windows CE .NET/Product
Documentation/Application Development/Windows Internet Services
(WinInet)" but it's all C++... :-(

Best regards,

Michael

--
How to contact me
~~~~~~~~~~~~~~~~~
directly via mail: remove the "NOTUSEABLE" and the point after it and
reverse the characters
via my portal: go to
http://great.dynu.com/tools/contact.4s?lang=de&ref=usenet
 
J

Jon Skeet [C# MVP]

Michael Kremser said:
Hm, that seems to be a problem, at least for the compiler:

HttpServiceAdapter.cs(50): Cannot implicitly convert type
'System.Net.WebResponse' to 'System.IDisposable'

Ah yes - for some reason it doesn't seem to implement IDisposable in
the Compact Framework. You need to call Close() on it, in a finally
block.

That *should* fix the problem, I believe. (I had a very similar bug a
while ago.)
 
M

Michael Kremser

Jon Skeet [C# MVP] wrote:

Hi Jon,

Thank you for your answer!
Ah yes - for some reason it doesn't seem to implement IDisposable in
the Compact Framework. You need to call Close() on it, in a finally
block.

I can't see it's implementing IDisposable at all, at least there's no
method "Dispose" also in the "big" fx.
That *should* fix the problem, I believe. (I had a very similar bug a
while ago.)

I now close the stream as well as the response, as shown below:

WebRequest req = WebRequest.Create(strURL);
WebResponse resp = req.GetResponse();
using (StreamReader reader = new StreamReader
(resp.GetResponseStream(), System.Text.Encoding.UTF7))
{
strResult = reader.ReadToEnd();
reader.Close();
}
resp.Close();

....but there's still the same error. :-( I begin to wonder whether we
work with a beta release of CF... :-/

However, in another thread on this NG I found a link where a download of
a file is being described:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetcomp/html/AutoUpdater.asp

I try this out and hope it helps. If not, I thought to just catch but
ignore this exception (currently the user would get annoyed by a dialog
box saying that the transfer failed - I will make a routine around the
call that tries it maximum three times automatically if the problem
persists).

Best regards,

Michael

--
How to contact me
~~~~~~~~~~~~~~~~~
directly via mail: remove the "NOTUSEABLE" and the point after it and
reverse the characters
via my portal: go to
http://great.dynu.com/tools/contact.4s?lang=de&ref=usenet
 
J

Jon Skeet [C# MVP]

Michael Kremser said:
I can't see it's implementing IDisposable at all, at least there's no
method "Dispose" also in the "big" fx.

There's WebResponse.IDisposable.Dispose - it's done by explicit
interface implementation. If you look at "about WebResponse class"
you'll see it implements IDisposable.
I now close the stream as well as the response, as shown below:

WebRequest req = WebRequest.Create(strURL);
WebResponse resp = req.GetResponse();
using (StreamReader reader = new StreamReader
(resp.GetResponseStream(), System.Text.Encoding.UTF7))
{
strResult = reader.ReadToEnd();
reader.Close();
}
resp.Close();

...but there's still the same error. :-( I begin to wonder whether we
work with a beta release of CF... :-/

And are you always executing that Close()? Don't forget that the reader
could be throwing an exception. You don't need to call reader.Close(),
by the way - the using statement will call Dispose for you.
However, in another thread on this NG I found a link where a download of
a file is being described:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnne
tcomp/html/AutoUpdater.asp

I try this out and hope it helps. If not, I thought to just catch but
ignore this exception (currently the user would get annoyed by a dialog
box saying that the transfer failed - I will make a routine around the
call that tries it maximum three times automatically if the problem
persists).

I don't know whether doing things asynchronously will help - I believe
the problem is that there's a connection pool and if the responses
aren't being closed properly, those connections are all in use. Then
again, if resp.Close() *is* being executed in your code, that doesn't
account for the problem...
 
M

Michael Kremser

Jon Skeet [C# MVP] wrote:

Hi Jon,

Thank you for your answer!
There's WebResponse.IDisposable.Dispose - it's done by explicit
interface implementation. If you look at "about WebResponse class"
you'll see it implements IDisposable.

Oh yes... I must have overseen this before. ;-)
And are you always executing that Close()? Don't forget that the reader
could be throwing an exception.

Well, it hasn't thrown an exception yet, but you're true... it would be
quite better to close it in a finally-statement, but first of all I want
to see it working basically, then I do these tasks. ;-)
You don't need to call reader.Close(),
by the way - the using statement will call Dispose for you.

Ah I see. I just wanted to be sure. ;-)
I don't know whether doing things asynchronously will help - I believe
the problem is that there's a connection pool and if the responses
aren't being closed properly, those connections are all in use.

Yes, it seems like that, it must be an error either in the CF or in the
operating system which is not in our (programmers) area of
responsibility. Now, I tried it this way and made a little class
WebDownloader (attached as file [1]), I call it this way:

WebDownloader wd = new WebDownloader(strURL);
wd.Download();
strResult = wd.Response;
GC.Collect(); <-- I thought as it works after restarting the app, it's
may be a programm with handles or something of that type

This works two times serially... then always throws an time out
exception (I have the feeling I already had something that way).

So, it seems to be impossible to make a download three times while the
application is running. Too bad, IMO. IE on the PDA can call a URL as
many times as it likes, so why can't the CF too?

Best regards,

Michael *confused*

[1] Download: http://www.mkcs.at/test/webdownloader.cs

--
How to contact me
~~~~~~~~~~~~~~~~~
directly via mail: remove the "NOTUSEABLE" and the point after it and
reverse the characters
via my portal: go to
http://great.dynu.com/tools/contact.4s?lang=de&ref=usenet

public class WebDownloader
{
public WebDownloader(string URL)
{
req = (HttpWebRequest)HttpWebRequest.Create(URL);
}

public void Download()
{
bFinished = false;
req.BeginGetResponse(new AsyncCallback(ResponseReceived),null);
while (!bFinished)
System.Threading.Thread.Sleep(500);
}

private void ResponseReceived(IAsyncResult res)
{
try
{
m_resp = (HttpWebResponse)req.EndGetResponse(res);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(),"ResponseReceived: Error");
bFinished = true;
return;
}
databuffer = new byte[DataBlockSize];
m_resp.GetResponseStream().BeginRead(databuffer,0,DataBlockSize,new AsyncCallback(OnDataRead),this);
}

private void OnDataRead(IAsyncResult res)
{
int nBytes = m_resp.GetResponseStream().EndRead(res);
Response += System.Text.Encoding.UTF7.GetString(databuffer,0,nBytes);
if (nBytes>0)
{
m_resp.GetResponseStream().BeginRead(databuffer,0,DataBlockSize,new AsyncCallback(OnDataRead),this);
}
else
{
// finished
bFinished = true;
}
}

private HttpWebResponse m_resp;
private HttpWebRequest req;
private byte[] databuffer;
public string Response = string.Empty;
private int DataBlockSize = 256;
private bool bFinished;
}
 
J

Joerg Jooss

Michael said:
Hi NG!

I use the following code to get something from a webserver:

Uri uri = new Uri("http://www.mkcs.at/test/somedata.4s");
System.Net.WebRequest wr = System.Net.HttpWebRequest.Create(uri);
System.IO.Stream stream = wr.GetResponse().GetResponseStream();
int b;
string strResult = string.Empty;
while ((b=stream.ReadByte())!=-1)
{
strResult += System.Text.UTF7Encoding.UTF7.GetString(new byte[] {
(byte)b },0,1);
}
stream.Close();
return strResult;


Besides the points Jon mentioned, why do use UTF-7? That's only used in
E-mail, if at all. http://www.mkcs.at/test/somedata.4s returns plain ASCII.

Cheers,
 
M

Michael Kremser

Joerg said:
Besides the points Jon mentioned, why do use UTF-7? That's only used in
E-mail, if at all. http://www.mkcs.at/test/somedata.4s returns plain ASCII.

Hi Joerg,

yes, that's right, but the real data service (the one posted is only an
basic example) may return german umlauts and sharp s, and ASCII encoding
would replace those characters with question marks.

Best regads,

Michael

--
How to contact me
~~~~~~~~~~~~~~~~~
directly via mail: remove the "NOTUSEABLE" and the point after it and
reverse the characters
via my portal: go to
http://great.dynu.com/tools/contact.4s?lang=de&ref=usenet
 
J

Joerg Jooss

Michael said:
Hi Joerg,

yes, that's right, but the real data service (the one posted is only
an basic example) may return german umlauts and sharp s, and ASCII
encoding would replace those characters with question marks.

Absolutely. But UTF-7 is most likely the wrong encoding. UTF-8 is used for
web sites.

Cheers,
 
Top