Showing posts with label silverlight. Show all posts
Showing posts with label silverlight. Show all posts

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 = "application/x-www-form-urlencoded";
          request.BeginGetRequestStream(new AsyncCallback(asyncResult =>
          {
              Stream stream = request.EndGetRequestStream(asyncResult);
              DataContractQueryStringSerializer ser = new DataContractQueryStringSerializer();
              ser.WriteObject(stream, parameters);
              stream.Close();
              request.BeginGetResponse(callback, request);
          }), request);
      }

      public static void PostMultiPartAsync(this HttpWebRequest request, object parameters, 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.EndGetRequestStream(asyncResult);

              DataContractMultiPartSerializer ser = new DataContractMultiPartSerializer(boundary);
              ser.WriteObject(stream, parameters);
              stream.Close();
              request.BeginGetResponse(callback, request);
          }), request);
      }
  }

  public class DataContractQueryStringSerializer
  {
      public void WriteObject(Stream stream, object data)
      {
          StreamWriter writer = new StreamWriter(stream);
          if (data != null)
          {
              if (data is Dictionary<string, string>)
              {
                  foreach (var entry in data as Dictionary<string, string>)
                  {
                      writer.Write("{0}={1}&", entry.Key, entry.Value);
                  }
              }
              else
              {
                  foreach (var prop in data.GetType().GetFields())
                  {
                      foreach (var attribute in prop.GetCustomAttributes(true))
                      {
                          if (attribute is DataMemberAttribute)
                          {
                              DataMemberAttribute member = attribute as DataMemberAttribute;
                              writer.Write("{0}={1}&", member.Name ?? prop.Name, prop.GetValue(data));
                          }
                      }
                  }
                  foreach (var prop in data.GetType().GetProperties())
                  {
                      if (prop.CanRead)
                      {
                          foreach (var attribute in prop.GetCustomAttributes(true))
                          {
                              if (attribute is DataMemberAttribute)
                              {
                                  DataMemberAttribute member = attribute as DataMemberAttribute;
                                  writer.Write("{0}={1}&", member.Name ?? prop.Name, prop.GetValue(data, null));
                              }
                          }
                      }
                  }
              }
              writer.Flush();
          }
      }
  }

  public class DataContractMultiPartSerializer
  {
      private string boundary;
      public DataContractMultiPartSerializer(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 FileInfo;
                  writer.WriteLine(@"Content-Disposition: form-data; name=""{0}""; filename=""{1}""", key, f.Name);
                  writer.WriteLine("Content-Type: application/octet-stream");
                  writer.WriteLine("Content-Length: " + f.Length);
                  writer.WriteLine();
                  writer.Flush();
                  Stream output = writer.BaseStream;
                  Stream input = f.OpenRead();
                  byte[] buffer = new byte[4096];
                  for (int size = input.Read(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(@"Content-Disposition: form-data; name=""{0}""", key);
                  writer.WriteLine();
                  writer.WriteLine(value.ToString());
              }
          }
      }

      public void WriteObject(Stream stream, object data)
      {
          StreamWriter writer = new StreamWriter(stream);
          if (data != null)
          {
              if (data is Dictionary<string, object>)
              {
                  foreach (var entry in data as Dictionary<string, object>)
                  {
                      WriteEntry(writer, entry.Key, entry.Value);
                  }
              }
              else
              {
                  foreach (var prop in data.GetType().GetFields())
                  {
                      foreach (var attribute in prop.GetCustomAttributes(true))
                      {
                          if (attribute is DataMemberAttribute)
                          {
                              DataMemberAttribute member = attribute as DataMemberAttribute;
                              WriteEntry(writer, member.Name ?? prop.Name, prop.GetValue(data));
                          }
                      }
                  }
                  foreach (var prop in data.GetType().GetProperties())
                  {
                      if (prop.CanRead)
                      {
                          foreach (var attribute in prop.GetCustomAttributes(true))
                          {
                              if (attribute is DataMemberAttribute)
                              {
                                  DataMemberAttribute member = attribute as DataMemberAttribute;
                                  WriteEntry(writer, member.Name ?? prop.Name, prop.GetValue(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 = (HttpWebRequest)WebRequest.Create(new Uri("http://localhost/rms/test.php"));
          OpenFileDialog dlg = new OpenFileDialog();
          if (dlg.ShowDialog().Value)
          {
              request.PostMultiPartAsync(new Dictionary<string, object> { { "x", "1" }, { "y", dlg.File } }, new AsyncCallback(asyncResult =>
              {
                  HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult);

                  Stream responseStream = response.GetResponseStream();
                  StreamReader reader = new StreamReader(responseStream);
                  this.Dispatcher.BeginInvoke(delegate
                  {
                      // output is a TextBlock
                      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 } }

with
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; }
  }

Monday, December 08, 2008

Flash vs. Silverlight vs. JavaFX

In RIA, Flash is the dominant player while Silverlight and JavaFX are new. However, Silverlight is in a better position than JavaFX.

.Net is a huge platform like Java. However, Microsoft trimmed .Net into a 5MB version to become a Silverlight runtime. On the other hand, Sun only added scripting syntax to Java and reuse the whole Java runtime as well as the branding. In fact, Java applet and Java web start has become the burden of the Java family. Users perceive Java is slow, insecure, and has compatibility issues whether or not any of them are true. So, it is no longer a technology issue. It is a marketing issue.

In fact, when it comes to marketing, Microsoft does it far much better than everyone one else in the technology industry.

Sunday, June 17, 2007

Thoughts on Silverlight

Microsoft is pushing Silverlight so hard these days. As the official release is approaching, the adoption rate will be low if it use the same installation method of beta. A better off will be Flash like installation. Everything can be installed automatically and no restart of browser. The real frictionless environment.

I could provision it could be a big success when Microsoft solves this particular problem.