Несколько загрузок файлов в Silverlight 4 - PullRequest
3 голосов
/ 11 марта 2011

Я пытаюсь реализовать загрузчик нескольких файлов в Silverlight 4. Элемент управления Silverlight содержит только одну кнопку. при щелчке по нему отображается OpenFileDialog, и они могут выбрать несколько файлов. Как только они закрывают диалог, объект FileInfo для всех выбранных файлов добавляется в список. затем в моей веб-форме у меня есть кнопка javascript, которая при нажатии вызывает метод в элементе управления silverlight для циклического перемещения по списку и загрузки файлов. этот метод возвращает строку, содержащую виртуальные пути ко всем загруженным файлам, разделенные точкой с запятой. Затем я могу использовать эту строку, чтобы добавить пути ко всем изображениям в базу данных в коде c # позади.

файл загружается путем вызова метода OpenRead () объекта FileInfo, чтобы получить поток, содержащий байты файла, создания объекта WebClient и вызова метода OpenWriteAsync, передавая URI обработчика HTTP на моем веб-сайте. событие 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 (если вы можете, ПОЖАЛУЙСТА, скажите мне, как :-)).

Я работаю над этим уже 2 дня, и нигде не получаю, поэтому любая помощь будет высоко ценится

1 Ответ

0 голосов
/ 13 марта 2011

В обработчике на стороне вашего сервера попробуйте: -

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

Сброс должен обеспечить запись всего содержимого в файл перед удалением потока.

Могу ли я также указать, чтопозволить строке запроса определить имя файла и сохранить его в папке, содержащей веб-сайт, - очень плохая идея.Что делать, если кто-то отправил обработчику имя файла «runthisevilstuff.ashx» и включил в загруженный поток вредоносный код C #.Затем они просто запрашивают эту введенную страницу для запуска своего злого кода.

...