开发者

Multiple file upload in silverlight 4

开发者 https://www.devze.com 2023-02-16 11:06 出处:网络
I\'m trying to implement a multiple file uploader in silverlight 4. the silverlight control contains a single button only. when this is clicked the OpenFileDialog is shown and they can select multiple

I'm trying to implement a multiple file uploader in silverlight 4. the silverlight control contains a single button only. when this is clicked the OpenFileDialog is shown and they can select multiple files. once they close the dialog the FileInfo object's for all of the files they selected get added to a list. then, in my web form i have a javascript button which, when clicked, calls a method in the silverlight control to loop through the list and upload the files. this method returns a string containing the virtual paths to all files that were uploaded, separated by a semi-colon. i can then use this string to add the paths to all images to the database in the c# code behind.

a file is uploaded by calling the OpenRead() method of the FileInfo object to get a stream containing the file's bytes, creating a WebCli开发者_运维知识库ent object and calling the OpenWriteAsync method, passing the URI of a HTTP handler in my website. the OpenWriteCompleted event of the web client is set to write the stream of the FileInfo object to it's output stream.

The HTTP Handler reads the bytes from the request stream and saves them to a file using a FileStream.

Here is the code for the silverlight control:

public partial class MainPage : UserControl
{
    private List<FileInfo> files = new List<FileInfo>();
    private String handlerUrl;
    private String imageBin;

    public MainPage(string handlerUrl, string imageBin)
    {
        InitializeComponent();

        this.handlerUrl = handlerUrl;
        this.imageBin = imageBin;

        if (!(this.imageBin.EndsWith("/")))
            this.imageBin += "/";

        //register control as scriptable object to allow methods to be called from javascript
        HtmlPage.RegisterScriptableObject("SilverlightCode", this);
    }

    private void btnBrowse_Click(object sender, RoutedEventArgs e)
    {
        files.Clear();

        OpenFileDialog ofd = new OpenFileDialog();
        ofd.Multiselect = true;

        bool? showDialog = ofd.ShowDialog();

        if ((showDialog != null) && (showDialog.Value))
        {
            try
            {
                foreach (FileInfo fi in ofd.Files)
                {
                    //check file is valid image file
                    BitmapImage source = new BitmapImage();
                    source.SetSource(fi.OpenRead());

                    files.Add(fi);
                }
            }
            catch
            {
                txtBrowse.Text = "Invalid image file selected.";
                files.Clear();
                return;
            }
        }

        if (files.Count == 1)
            txtBrowse.Text = "1 image selected.";
        else
            txtBrowse.Text = files.Count.ToString() + " images selected.";
    }

    [ScriptableMember]
    public string UploadImages()
    {
        try
        {
            String s = "";
            String now = DateTime.Now.ToString("yyyyMMddHHmmss");

            for (int i = 0; i < files.Count; i++)
            {
                String filename = imageBin + now + i.ToString("00000") + files[i].Extension;
                s += filename + "; ";

                UploadImage(files[i], filename, i);
            }

            return s.Trim();
        }
        catch
        {
            return "";
        }
    }

    private void UploadImage(FileInfo imageFile, String uploadImageVirtualPath, int index)
    {
        UriBuilder ub = new UriBuilder(handlerUrl);
        ub.Query = String.Format("filename={0}", uploadImageVirtualPath);

        Stream stream = imageFile.OpenRead();

        WebClient client = new WebClient();

        client.OpenWriteCompleted += (sender, e) =>
        {
            PushData(stream, e.Result);
            e.Result.Close();
            stream.Close();
        };

        client.OpenWriteAsync(ub.Uri);
    }

    private static void PushData(Stream input, Stream output)
    {
        byte[] buffer = new byte[input.Length];
        input.Read(buffer, 0, buffer.Length);
        output.Write(buffer, 0, buffer.Length);
    }
}

and here is code for the HTTP Handler:

public class ImagesHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        //process request
        string filename = context.Request.QueryString["filename"].ToString();

        using (FileStream fs = File.Create(context.Server.MapPath(filename)))
        {
            SaveFile(context.Request.InputStream, fs);
        }
    }

    private void SaveFile(Stream stream, FileStream fs)
    {
        byte[] buffer = new byte[stream.Length];
        stream.Read(buffer, 0, buffer.Length);
        fs.Write(buffer, 0, buffer.Length);
    }

    public bool IsReusable
    {
        get
        {
            return true;
        }
    }
}

the problem i'm having is that the HTTP handler only actually creates the image files half of the time and sometimes it only writes a subsection of the bytes to the file so you get a corrupt image file. no exceptions seem to be getting thrown anywhere and it doesn't seem to be possible to predict when it will work and when it will fail. my first thought was that the HTTP handler can't process so many requests at once and falls over. if i could i would upload each image synchronously but you can't do that in silverlight (if you can, PLEASE tell me how :-) ).

i've been working on this solidly for 2 days now and getting nowhere so any help would be hugely appreciated


In your server side handler try:-

    using (FileStream fs = File.Create(context.Server.MapPath(filename)))  
    {
         SaveFile(context.Request.InputStream, fs);
         fs.Flush();
    }

The flush should ensure the full content is written to file before the stream is disposed of.

Can I also point out that allowing the query string to determine the filename and having it saved into the folder containing the website is a really bad idea. What if someone posted to the handler the filename "runthisevilstuff.ashx" and included in the uploaded stream malicious C# code. They then simply request this injected page to run their evil code.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号