Silverlight 4 中的多文件上传

3
我正在尝试在Silverlight 4中实现多文件上传器。该Silverlight控件仅包含一个按钮。当单击此按钮时,会显示OpenFileDialog并可以选择多个文件。一旦关闭对话框,所选文件的FileInfo对象将添加到列表中。然后,在我的Web表单中,我有一个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处理程序的代码:

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中无法这样做(如果可以,请告诉我如何 :-))。
我已经全力工作了两天,但还没有取得任何进展,所以非常感谢任何帮助。
1个回答

0
在您的服务器端处理程序中尝试:-
    using (FileStream fs = File.Create(context.Server.MapPath(filename)))  
    {
         SaveFile(context.Request.InputStream, fs);
         fs.Flush();
    }

flush 应该确保在流被处理之前将完整的内容写入文件。

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


感谢您的回复。添加fs.Flush()行改善了系统,但并没有完全解决问题。虽然图像上传失败的情况发生频率较低,但仍在发生。我已经在系统上添加了限制,使用户一次只能上传10张图片,这似乎可以处理。关于文件名在查询字符串中的问题,我完全同意您的观点。您有其他建议吗?我使用的代码是从网上找到的一个示例。 - lace.john

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接