Metro XAML Rating Control www.perpetuumsoft.com
Star Tech Corner Star Tech Corner
TUESDAY, MARCH 03, 2009
Silverlight Multi-part File Upload Form Post
Silverlight not actually very web friendly. It lacks of built-in support for the current HTML form post protocol. So, we have to write it our own. I have written an extension class and two serializer classes, one for normal form post (DataContractQueryStringSerializer) while the other for multipart upload form post (DataContractMultiPartSerializer).
If you only want to have the working code, just copy the code below. Detail explanation is available at Multi-Part Form Post in Shane's Shelf
public static class Extensions
public static void PostFormAsync(this HttpWebRequest request, object parameters, AsyncCallback callback) { request.Method = "POST"; request.ContentType = "applicatio n/x-www-form-urlencoded"; request.BeginGetRequestStream(new AsyncCallback(asyncResult => { Stream stream = request.EndGe tRequestStream(asyncResult); DataContractQueryStringSerial izer ser = new DataContractQueryStringSeria lizer(); ser.WriteObject(stream, param eters); stream.Close(); request.BeginGetResponse(call back, request); }), request); }
public static void PostMultiPartAsync (this HttpWebRequest request, object parame ters, AsyncCallback callback) { request.Method = "POST"; string boundary = "---------------" + DateTime.Now.Ticks.ToString(); request.ContentType = "multipart/form-data; boundary=" + boundary; request.BeginGetRequestStream(new AsyncCallback(asyncResult => { Stream stream = request.EndGe tRequestStream(asyncResult);
DataContractMultiPartSerializ er ser = new DataContractMultiPartSerialize r(boundary); ser.WriteObject(stream, param eters); stream.Close(); request.BeginGetResponse(call back, request); }), request); }
public class DataContractQueryStringSeria lizer
public void WriteObject(Stream stream , object data) { StreamWriter writer = new StreamW riter(stream); if (data != null) { if (data is Dictionary<string , string>) { foreach (var entry in dat a as Dictionary<string, string>) { writer.Write("{0}={1} &", entry.Key, entry.Value); } } else { foreach (var prop in data .GetType().GetFields()) { foreach (var attribut e in prop.GetCustomAttributes(true)) { if (attribute is DataMemberAttribute) {
ribute member = attribute as DataMemberAttr ibute;
"{0}={1}&", member.Name ?? prop.Name, prop. GetValue(data)); } } } foreach (var prop in data .GetType().GetProperties()) { if (prop.CanRead) { foreach (var attr ibute in prop.GetCustomAttributes(true)) {
is DataMemberAttribute)
rAttribute member = attribute as DataMember Attribute;
ite("{0}={1}&", member.Name ?? prop.Name, p rop.GetValue(data, null));
} } } } writer.Flush(); } }
public class DataContractMultiPartSeriali
private string boundary; public DataContractMultiPartSerialize r(string boundary) { this.boundary = boundary; }
private void WriteEntry(StreamWriter writer, string key, object value) { if (value != null) { writer.Write("--"); writer.WriteLine(boundary); if (value is FileInfo) {
FileInfo f = value as Fil eInfo; writer.WriteLine(@"Conten t-Disposition: form-data; name=""{0}""; fil ename=""{1}""", key, f.Name); writer.WriteLine("Content -Type: application/octet-stream"); writer.WriteLine("Content -Length: " + f.Length); writer.WriteLine(); writer.Flush(); Stream output = writer.Ba seStream; Stream input = f.OpenRead
byte[] buffer = new byte[ 4096]; for (int size = input.Rea d(buffer, 0, buffer.Length); size > 0; size = input.Read(buffer, 0, buffer.Length)) { output.Write(buffer, 0, size); } output.Flush(); writer.WriteLine(); } else { writer.WriteLine(@"Conten t-Disposition: form-data; name=""{0}""", ke
writer.WriteLine(); writer.WriteLine(value.To String()); } } }
public void WriteObject(Stream stream , object data) { StreamWriter writer = new StreamW riter(stream); if (data != null) { if (data is Dictionary<string , object>) { foreach (var entry in dat a as Dictionary<string, object>) { WriteEntry(writer, en try.Key, entry.Value); } } else { foreach (var prop in data .GetType().GetFields()) { foreach (var attribut e in prop.GetCustomAttributes(true)) { if (attribute is DataMemberAttribute) {
ribute member = attribute as DataMemberAttr ibute;
iter, member.Name ?? prop.Name, prop.GetVal ue(data)); } } } foreach (var prop in data .GetType().GetProperties()) { if (prop.CanRead) { foreach (var attr ibute in prop.GetCustomAttributes(true)) {
is DataMemberAttribute)
rAttribute member = attribute as DataMember Attribute;
y(writer, member.Name ?? prop.Name, prop.Ge tValue(data, null));
} } } } } writer.Write("--"); writer.Write(boundary); writer.WriteLine("--"); writer.Flush(); }
The usage is as follows: First a PHP file
<?php print_r($_REQUEST); $src = $_FILES['y']['tmp_name']; $dest = "C:\\Windows\\Temp\\".$_FILES['y'][ 'name']; echo $src; echo "\r\n"; echo $dest; echo @copy($src, $dest);
Then the Page control
public partial class Page : UserControl
public Page() { InitializeComponent(); // Create a request object HttpWebRequest request = (HttpWeb Request)WebRequest.Create(new Uri("http://l ocalhost/rms/test.php")); OpenFileDialog dlg = new OpenFile Dialog(); if (dlg.ShowDialog().Value) { request.PostMultiPartAsync(ne w Dictionary<string, object> { { "x", "1" } , { "y", dlg.File } }, new AsyncCallback(as yncResult => { HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(a syncResult);
Stream responseStream = r esponse.GetResponseStream(); StreamReader reader = new StreamReader(responseStream); this.Dispatcher.BeginInvo ke(delegate { // output is a TextBl
output.Text = reader. ReadToEnd(); response.Close(); }); })); } }
Since it is able to serialize data contract, you could actually replace
new Dictionary<string, object> { { "x", "1" }, { "y", dlg.File } }
new Point(){X=1, Y=2}
given the point class is like this:
[DataContract] public class Point
[DataMember] public int X { get; set; } [DataMember(Name="y")] public int Y { get; set; }
Shane Ng at 2:21 AM
Share 0
4 comments:
Dai Lo 3:28 AM
Cool! The multipart handling was exactly what I needed. Nice work!
Reply
Anonymous 4:53 PM
Hi, I failed in EndGetResponse(), and got security exception. What will the encoding data would like? Could you give me an example?
Thanks a lot~
Reply
Naveen 7:10 PM
Could you post the receiving part? Meaning, how to take the multipart request in the server (Jersey) and process the multipart request?
Reply
Shane Ng 1:13 AM
It's just a multi-part form
standard Java Web Container (e.g. Tomcat) will be able to process it natively.
Reply
Enter your comment...
Comment as: Select profile...
Preview
Publish
› Home
View web version
ABOUT ME
Shane Ng
Enjoy your life, enjoy programming. View my complete profile
Powered by Blogger
YAGI Hiroto (piroto@a-net.email.ne.jp)
twitter http://twitter.com/pppiroto
Copyright© 矢木 浩人 All Rights Reserved.