SL 4: simple file upload, why is this not working? - c#

I am not getting any exception in the following code, however I also don't see the file which is suppose to be uploaded to the server (in this case a localhost) - could someone please point out the mistake?
As an add on, I need a simple silverlight file uploader with a progress bar, but I am having a really hard time try using the ones on the codeplex, Does anyone here has a good one for SL4?
public FileStream MyFS { get; set; }
private void UploadFile()
{
FileStream _data; // The file stream to be read
_data = MyFS;
string uploadUri;
uploadUri = #"http://localhost/MyApplication/Upload/Images/testXRay.gif";
byte[] fileContent = new byte[_data.Length]; // Read the contents of the stream into a byte array
int dataLength = int.Parse(_data.Length.ToString());
_data.Read(fileContent, 0, dataLength);
WebClient wc = new WebClient();
wc.OpenWriteCompleted += new OpenWriteCompletedEventHandler(wc_OpenWriteCompleted);
Uri u = new Uri(uploadUri);
wc.OpenWriteAsync(u, null, fileContent); // Upload the file to the server
}
void wc_OpenWriteCompleted(object sender, OpenWriteCompletedEventArgs e) // The upload completed
{
if (e.Error == null)
{
// Upload completed without error
}
}
Thanks,
Voodoo

You are trying to write to a server URL that is an image, not a service:
uploadUri = #"http://localhost/MyApplication/Upload/Images/testXRay.gif";
...
Uri u = new Uri(uploadUri);
wc.OpenWriteAsync(u, null, fileContent);
You can't just write a file (via HTTP) to a webserver like that. The receiving URL needs to be a web service designed to accept the incoming byte stream.
I am sure there are better examples about, but try this link first.

Another problem with your code is that you haven't tried to write the file at all.
This line doesn't do what you think:
wc.OpenWriteAsync(u, null,
fileContent); // Upload the file to
the server
The call signature is OpenWriteAsync(URI, HTTPMETHOD, UserToken).
Let me break that down a little. URI I think you have. The HTTPMETHOD let's you set whether you are doing a post or a get. Probably you want to do an HttpPost. Finally that last item isn't for pushing the filecontent. It is more of a state variable so you can keep track of the request (more on this in a moment).
The way the HTTP stack works in Silverlight is that everything is asynchronous. So you in your case you are setting up a request and then telling the runtime that you want to write some data to the request. That is what your call does. It goes out and sets up to let you make a request (which may all happen on a background thread not the thread where the UI gets updated). Once this is set up it will call your callback event with a stream which you can write to. One of the things it sends back to you is that state variable (the UserToken) which gives you the ability to know which request it responded back to you with (which means that you could send multiple files back to the server at the same time).
It will also exposes a few other events that you can use to see if everything worked Ok (like you can get a response from the your call and see what the status code was --which will tell you if everything was successful or not). BTW, with every callback it sends that UserToken variable so your app can keep track of which request was being responded to (if there are more than one going on right now).
The links that the last guy provided should help you out some. He is right too, you need something on the server setup to respond to the request or rather you typically want to do this. You can set up a folder to allow you to push data directly to it, but honestly you don't want to do this as you would be opening up your server for hackers to exploit.

Related

C#, clear HttpListenerContext.Response.OutputStream

I have a web-service using HttpListener.
I have noticed this thing:
HttpListenerContext context = listener.GetContext();
...
context.Response.StatusCode = 200;
context.Response.OutputStream.Write(buffer, 0, bufferSize);
context.Response.StatusCode = 500;
context.Response.OutputStream.Close();
A client in this case receives a status code 200, so if i have wrote some data to the output network stream i can't change the status code, as, i suppose, it is already written to the response stream.
What i want: after i have started writing a response to the output stream, in some case i want to "abort and reset" the response, clear the output stream (so the client won't receive any data in HTTP response body), and change the status code.
I have no idea how to clear the output stream and change the status code. These two lines below won't help, they throw exceptions.
context.Response.OutputStream.SetLength(0);
context.Response.OutputStream.Position = 0;
I suppose, what the program writes buffer data into network device after i call context.Response.OutputStream.Close(), until this the data is stored in RAM and we can reset it, can't we?
EDIT: It seems what writing into the context.Response.OutputStream takes too much of time sometimes, in some case. From 100 to 1000 ms... That's why i would just interrupt writing, if it's possible.
You either could use a MemoryStream to cache the answer, and if you are sure it is complete, set the status to 200 and return it (e.g. with Stream.CopyTo).
You can't "clear" the OutputStream, since it isn't stored (for long), instead it is sent right away to the client, so you can't edit it anymore.
Apart from that, HTTP does not offer a way to gracefully say "DATADATADATA... oh forget that, this was wrong, use the Status Code 500 instead.". You only can try to kill the TCP connection (TCP RST instead of TCP FIN) and hope that the client will handle failing to continue reading on the connection in a suitable way, after it probably already started to process the data you've already sent.
Try context.Response.Abort() before closing, this won't allow you to set a status code, but will at least communicate that something went wrong.

Reactive Extensions - Flushing Subject / IObservable in a synchronous fashion

EDIT: I've edited a few lines of code, when running in the IDE it fails without an error or anything.
I'm new to Reactive Extensions and have a problem that I am trying to sort out. I'm using RX to queue events on a machine, then every so often send that data to a server. My problem appears to be that when the application is shutting down, anything that is an async call of any sort seems to just cancel and not run, thus the last batch of events never gets sent.
I have a Subject, where Event is my data class. I know now that a Subject might not be the best class to use, but here we are.
My code looks mostly like the following, added a few comments for clarity:
IObservable<IList<Event>> eventsObserver = Instance.EventBuffer.ToList<Event>();
var eventsEnumerable = eventsObserver.ToEnumerable();
List<Event> events = new List<Event>();
try
{
events = (List<Event>)eventsEnumerable.First(); // THIS LINE FAILS SILENTLY, EVEN IN DEBUGGER...
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine("Error: " + ex.Message);
}
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(someURI);
HttpResponseMessage response = client.PostAsync(somePage, new StringContent(SerializeToJSON(events))).Result;
response.EnsureSuccessStatusCode();
}
If I don't make the call to the web server synchronous (with the '.Result'), it fails there. I've tried a lot of ways to get the data from the IObservable into something I can send, but either the code fails (usually with a bad cast of some sort), or the events are not yet put into the data structure that I want to send. I know that RX is by nature async, and I'm asking to deal with it in a synchronous way, I would figure that there would be a solution. Thanks in advance!
Supposing that you control the Observable source, you could call Observable.OnComplete() like Enigmativity has pointed out. Otherwise, you could try to keep a copy of every value received before buffering it:
Observable.Do(x => localCopy = x).Buffer(..)
This local copy would be accessible to you at shutdown.
In any case, please note that .First() is marked obsolete in the latest Rx versions, possibly to avoid the problem you are experiencing.

Multithreading using AsyncCallback and GUI controls

Multithread programming is a new concept for me. I’ve done a bunch of reading and even with many examples, I just can’t seem to figure it out. I'm new to C# and programming.
I have a winform project with lots of custom controls I’ve imported and will utilize many tcpclients. I’m trying to get each control to be hosted on it’s own separate thread. Right now, I’m trying to get 1 control to behave appropriately with it’s own thread.
I'll show you what I have and then follow up with some questions regarding guidance.
string asyncServerHolder; // gets the server name from a text_changed event
int asyncPortHolder; // gets the port # from a text_changed event
TcpClient wifiClient = new TcpClient();
private void btnStart_Click(object sender, EventArgs e)
{
... // variable initialization, etc.
... // XML setup, http POST setup.
send(postString + XMLString); // Content to send.
}
private void send(string msg)
{
AsyncCallback callBack = new AsyncCallback(ContentDownload);
wifiClient.BeginConnect(asyncServerHolder, asyncPortHolder, callBack, wifiClient);
wifiClient.Client.Send(System.Text.Encoding.ASCII.GetBytes(msg));
}
private void ContentDownload(IAsyncResult result)
{
if (wifiClient.Connected)
{
string response4 = "Connected!!"; //debug msg
byte[] buff = new byte[1024];
int i = wifiClient.Client.Receive(buff);
do
{
response1 = System.Text.Encoding.UTF8.GetString(buff, 0, i);
} while (response1.Length == 0);
response2 = response1.Substring(9, 3); // pick out status code to be displayed after
wifiClient.Client.Dispose();
wifiClient.Close();
}
}
If you're knowledgeable about this, I bet you see lots of problems above. As it stands right now, I always get an exception one my first iteration of running this sequence:
"A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied"
Why is this? I have confirmed that my asyncServerHolder and my asyncPortHolder are correct. My second iteration of attempting allowed me to see response4 = "Connected!!" but I get a null response on response1.
Eventually I'd like to substitute in my user controls which I have in a List. I'd just like to gracefully connect, send my msg, receive my response and then allow my form to notify me from that particular control which plays host to that tcp client. My next step would be link up many controls.
Some questions:
1) Do I need more TCP clients? Should they be in a list and be the # of controls I have enabled at that time of btnStart_Click?
2) My controls are on my GUI, does that mean I need to invoke if I'm interacting with them?
3) I see many examples using static methods with this context. Why is this?
Thanks in advance. All criticism is welcome, feel free to be harsh!
BeginConnect returns immediately. Probably, no connection has been established yet when Send runs. Make sure that you use the connection only after having connected.
if (wifiClient.Connected) and what if !Connected? You just do nothing. That's not a valid error recovery strategy. Remove this if entirely.
In your read loop you destroy the previously read contents on each iteration. In fact, you can't split up an UTF8 encoded string at all and decode the parts separately. Read all bytes into some buffer and only when you have received everything, decode the bytes to a string.
wifiClient.Client.Dispose();
wifiClient.Close();
Superstitious dispose pattern. wifiClient.Dispose(); is the canonical way to release everything.
I didn't quite understand what "controls" you are talking about. A socket is not a control. UI controls are single-threaded. Only access them on the UI thread.
Do I need more TCP clients?
You need one for each connection.
Probably, you should use await for all blocking operations. There are wrapper libraries that make the socket APIs usable with await.

ASMX webservices with Silverlight Async confusion

I have a silverlight 4 web app that needs to communicate with a server by accessing the ASMX web service on the server.
I have a list(yes, the array), of objects that I need to send(one by one) as a parameter to the service. However looping through the list and running the method(objecttosend); will not work because I need to send then one after another and Silverlight seems to only support Async(presumably to not lockup interface - makes sense).
So I tried this:
public void SendNextPart()
{
if (partsToSend.Count > 0)
{
Part thisPart = partsToSend.Dequeue();
fuWS.createPartCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(fuWS_createPartCompleted);
fuWS.createPartAsync(thisPart);
}
}
Queue<Part> partsToSend = new Queue<Part>();
void fuWS_createPartCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
SendNextPart();
}
Which, as far as I can understand it, will check to see if the List has parts to send, then run the webservice(called fuWS) method and delete that part from the partsToSend List. Once it gets the completed event it should then run the SendNextPart method again and send the next part.
However what is happening(picked this up by watching HTTPwatch) is that it sends the first part, then after that is sends 2 parts at once and then after that more and more, all at once. Almost as if it is receiving the completed event before it has actually sent to the server and run the method successfully.
Please help, this is bugging the hell out of me, and it completely breaks what I need to do :'(
I don't see the SendNextBuffer method that you're calling in the web service callback event handler. But in any case, at best your code has a race condition. If the web service completes and returns before the partsToSend.RemoveAt line is executed (theoretically possible) then you could be making the next request before you've removed the one you just sent.
So first, you should check to make sure you've included all the code in your example unless you meant for SendNextBuffer to say SendNextPart.
Secondly, you should move the partsToSend.RemoveAt line before the web service call.
Finally, you should probably change the partsToSend list into a Queue<Part> (first in, first out) or Stack<Part> (last in, first out) instead since that is what you're using it as.
Ok, so after using Debug.WriteLine, I realized that I was being an idiot.
Check out this line:
fuWS.createPartCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(fuWS_createPartCompleted);
What this was doing was adding a new event handler every time it had to send a new part. So the second part sending now had two callback then the third would have more and so on increasing exponentially.

Call a webpage from c# in code

I need a way of calling a web page from inside my .net appliction.
But i just want to send a request to the page and not worry about the response.
As there are times when the response can take a while so i dont want it to hang the appliction.
I have been trying in side the page_load event
WebClient webC = new WebClient();
Uri newUri = new Uri("http://localhost:49268/dosomething.aspx");
webC.UploadStringAsync(newUri, string.Empty);
Even though its set to Async, it still seams to hang as the page wont finish rendering until the threads have finsished
This should work for you:
System.Net.WebClient client = new System.Net.WebClient();
client.DownloadDataAsync(new Uri("http://some.url.com/some/resource.html"));
The WebClient class has events for notifying the caller when the request is completed, but since you don't care there shouldn't be anything else to it.
Doak, Was almost there, but each time I put any of the request in a sepreate thread the page still wouldn't render until all the thread had finished running.
The best way I found was adjusting Doak's method, and just sticking a timeout in there and swallowing the error.
I know its a hack but it does work :P
WebRequest wr = WebRequest.Create("http://localhost:49268/dostuff.aspx");
wr.Timeout = 3500;
try
{
HttpWebResponse response = (HttpWebResponse)wr.GetResponse();
}
catch (Exception ex)
{
//We know its going to fail but that dosent matter!!
}
For not having you application to hang you will need to call the method from a Thread.
For the HTTP request without an answer, something like that should do the job:
Thread myThread = new Thread(new ThreadStart(myMethodThatDoHttp));
myThread.Start();
public void myMethodThatDoHttp()
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www..com");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
}
Look at System.Net.WebClient, specifically use the DownloadDataAsync() method to send the request without blocking the rest of the app.
To have this process without interrupting the page flow of your current page I would recommend creating a WCF service that will execute the code for you. Have the service set to use 1 way calls and on the page initiate an Ajax call to the service.
As far as I can see the 'BeginGetResponse'-method and the 'EndGetResponse'-method of the HttpWebRequest-object (gained through the call of WebRequest.Create), resp. the BeginGetRequestStream-/EndGetRequestStream methods, HERE aren't reflected yet, - although they are EXLPLICITLY marked for an "async request" in the docs:
For .Net 2.0
For .Net 4.0
No clue, how that works.
If the page to call is on the same IIS/App. as the calling, you could write an Filter, that ends all service for this request to client (Your 'calling' aspx-page), if the map-string contains the spec for the page to call (in ISAPI-cpp: "return SF_STATUS_REQ_FINISHED;") But perhaps Your asp/x/-script-execution in the called page is killed too. Question of check.
Consider using server-side include directives (less conditionable) or dynamically call an .asp file by using Server.Execute.
Not really async, but maybe worthy: State explicitly by an EARLY Response.End() (or similar) IN THE CALLED PAGE to the system, that NO FURTHER RESPONSE is to be expected, mainly NOT to the caller. Then do Your stuff ongoing in the CALLED page's scripts. At least the time-slip to await the sync-call's ending could be minimized by fac of 10, 100 or so.
Use System.Net.WebClient.DownloadDataAsync/DownloadFileAsync in conjunction with DownloadDataCompleted/DownloadFileCompleted.

Categories