Silverlight 4中的多个文件上传

时间:2011-03-11 15:42:22

标签: c# asp.net silverlight silverlight-4.0 httphandler

我正在尝试在silverlight 4中实现多文件上传器.silverlight控件仅包含一个按钮。单击此按钮时,将显示OpenFileDialog,它们可以选择多个文件。一旦他们关闭对话框,他们选择的所有文件的FileInfo对象就会被添加到列表中。然后,在我的网络表单中,我有一个javascript按钮,当点击它时,调用silverlight控件中的方法循环遍历列表并上传文件。此方法返回一个字符串,其中包含已上载的所有文件的虚拟路径,并以分号分隔。然后,我可以使用此字符串将所有图像的路径添加到c#代码后面的数据库中。

通过调用FileInfo对象的OpenRead()方法上传文件以获取包含文件字节的流,创建WebClient对象并调用OpenWriteAsync方法,在我的网站中传递HTTP处理程序的URI。 Web客户端的OpenWriteCompleted事件被设置为将FileInfo对象的流写入其输出流。

HTTP处理程序从请求流中读取字节,并使用FileStream将它们保存到文件中。

以下是silverlight控件的代码:

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

这里是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;
        }
    }
}

我遇到的问题是HTTP处理程序实际上只创建了一半时间的图像文件,有时它只将字节的一个子部分写入文件,因此你得到一个损坏的图像文件。没有例外似乎被抛到任何地方,似乎不可能预测何时它将起作用以及什么时候会失败。我的第一个想法是,HTTP处理程序不能同时处理这么多请求而且会崩溃。如果我可以同步上传每个图像但你不能在silverlight中做到这一点(如果可以的话,请告诉我如何:-))。

我已经坚持了2天,并且无处可去,所以任何帮助都会受到极大的赞赏

1 个答案:

答案 0 :(得分:0)

在服务器端处理程序中尝试: -

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

刷新应确保在处理流之前将完整内容写入文件。

我是否还可以指出允许查询字符串确定文件名并将其保存到包含该网站的文件夹中是一个非常糟糕的主意。如果有人向处理程序发布文件名“runthisevilstuff.ashx”并包含在上传的流恶意C#代码中,该怎么办?然后他们只是请求这个注入的页面运行他们的恶意代码。