Диалоговое окно файла Silverlight 3

#silverlight-3.0

#silverlight-3.0

Вопрос:

Хорошо — у меня есть служба WCF, которая считывает файл Excel из определенного местоположения и преобразует данные в объект. Что мне нужно, так это возможность разрешить пользователям моей программы загружать таблицу Excel в расположение файла, которое использует мой сервис.

Альтернативно, я мог бы передать загруженный лист Excel в службу напрямую.

Кто-нибудь может помочь с этим. Мой сервисный код:

     public List<ImportFile> ImportExcelData(string FileName)
    {
        //string dataSource = Location   FileName;
        string dataSource = Location;
        string conStr = "Provider=Microsoft.Jet.OLEDB.4.0;"   "Data Source="   dataSource.ToString()   ";Extended Properties=Excel 8.0;";
        var con = new OleDbConnection(conStr);
        con.Open();

        var data = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
        var sheetName = data.Rows[0]["TABLE_NAME"].ToString();

        OleDbCommand cmd = new OleDbCommand("SELECT * FROM ["   sheetName   "] WHERE Status = '4'", con);
        OleDbDataAdapter oleda = new OleDbDataAdapter();
        oleda.SelectCommand = cmd;

        DataSet ds = new DataSet();
        oleda.Fill(ds, "Employees");
        DataTable dt = ds.Tables[0];

        var _impFiles = new List<ImportFile>();
        foreach (DataRow row in dt.Rows)
        {
            var _import = new ImportFile();

            _import.PurchaseOrder = row[4].ToString();

            try
            {
                var ord = row[8].ToString();
                DateTime dati = Convert.ToDateTime(ord);
                _import.ShipDate = dati;
            }
            catch (Exception)
            {
                _import.ShipDate = null;
            }


            ImportFile additionalData = new ImportFile();
            additionalData = GetAdditionalData(_import.PurchaseOrder);


            _import.NavOrderNo = additionalData.NavOrderNo;
            _import.IsInstall = additionalData.IsInstall;
            _import.SalesOrderId = additionalData.SalesOrderId;
            _import.ActivityID =  additionalData.ActivityID;
            _import.Subject =  additionalData.Subject ;

            _import.IsMatched = (_import.ShipDate != null amp; _import.NavOrderNo != "" amp; _import.NavOrderNo != null amp; _import.ShipDate > DateTime.Parse("01/01/1999") ? true : false);

            _import.UpdatedShipToField = false;
            _import.UpdatedShipToFieldFailed = false;
            _import.CreateNote = false;
            _import.CreateNoteFailed = false;
            _import.CompleteTask = false;
            _import.CompleteTaskFailed = false;
            _import.FullyCompleted = 0;
            _import.NotCompleted = false;
            _impFiles.Add(_import);

        }


        oleda.Dispose();
        con.Close();
        //File.Delete(dataSource);

        return _impFiles;

        } 
  

Ответ №1:

Вы захотите изменить свой сервис, чтобы он принимал Stream вместо имени файла, затем вы можете сохранить значение if off в файл (или проанализировать его непосредственно из Stream , хотя я не знаю, как это сделать).

Затем в вашем приложении Silverlight вы могли бы сделать что-то вроде этого:

 private void Button_Click(object sender, RoutedEventArgs ev)
{
    var dialog = new OpenFileDialog();
    dialog.Filter = "Excel Files (*.xls;*.xlsx;*.xlsm)|*.xls;*.xlsx;*.xlsm|All Files (*.*)|*.*";
    if (dialog.ShowDialog() == true)
    {
        var fileStream = dialog.File.OpenRead();
        var proxy = new WcfService();
        proxy.ImportExcelDataCompleted  = (s, e) =>
        {
             MessageBox.Show("Import Data is at e.Result");
             // don't forget to close the stream
             fileStream.Close();
        };
        proxy.ImportExcelDataAsync(fileStream);
    }
}
  

Вы также могли бы заставить свою службу WCF принять byte[] и сделать что-то вроде этого.

 private void Button_Click(object sender, RoutedEventArgs ev)
{
    var dialog = new OpenFileDialog();
    dialog.Filter = "Excel Files (*.xls;*.xlsx;*.xlsm)|*.xls;*.xlsx;*.xlsm|All Files (*.*)|*.*";
    if (dialog.ShowDialog() == true)
    {
        var length = dialog.File.Length;
        var fileContents = new byte[length];
        using (var fileStream = dialog.File.OpenRead())
        {
            if (length > Int32.MaxValue)
            {
                throw new Exception("Are you sure you want to load > 2GB into memory.  There may be better options");
            }
            fileStream.Read(fileContents, 0, (int)length);
        }
        var proxy = new WcfService();
        proxy.ImportExcelDataCompleted  = (s, e) =>
                                                {
                                                    MessageBox.Show("Import Data is at e.Result");
                                                    // no need to close any streams this way
                                                };
        proxy.ImportExcelDataAsync(fileContents);
    }
}
  

Обновить

Ваш сервис может выглядеть следующим образом:

 public List<ImportFile> ImportExcelData(Stream uploadedFile)
{
    var tempFile = HttpContext.Current.Server.MapPath("~/uploadedFiles/"   Path.GetRandomFileName());
    try
    {
        using (var tempStream = File.OpenWrite(tempFile))
        {
            uploadedFile.CopyTo(tempStream);
        }

        //string dataSource = Location   FileName;
        string dataSource = tempFile;
        string conStr = "Provider=Microsoft.Jet.OLEDB.4.0;"   "Data Source="   dataSource.ToString()  
                        ";Extended Properties=Excel 8.0;";
        var con = new OleDbConnection(conStr);
        con.Open();
    }
    finally
    {
        if (File.Exists(tempFile))
            File.Delete(tempFile);
    }
}
  

Комментарии:

1. Не уверен, как это сделать в виде потока — Можно заставить его работать только с помощью описанного выше метода

2. Вам пришлось бы сохранить содержимое потока в локальном каталоге на сервере. Где-то у учетной записи службы WCF есть разрешение, возможно, в подпапке в корне веб-сайта или во временном каталоге.

3. Добавлено обновление, которое показывает, как перенести поток во временный файл и запустить его оттуда.

Ответ №2:

Спасибо, Бендевей, это было здорово. Пришлось немного изменить его — Мой сервис:

         var tempFile = @"c:temp"   Path.GetRandomFileName();

        try  
        {        

            int length = 256;
            int bytesRead = 0;
            Byte[] buffer = new Byte[length];

            // write the required bytes
            using (FileStream fs = new FileStream(tempFile, FileMode.Create))
            {
                do
                {
                    bytesRead = uploadedFile.Read(buffer, 0, length);
                    fs.Write(buffer, 0, bytesRead);
                }
                while (bytesRead == length);
            }

            uploadedFile.Dispose();             



            string conStr = "Provider=Microsoft.Jet.OLEDB.4.0;"   "Data Source="   dataSource.ToString()   ";Extended Properties=Excel 8.0;";
            var con = new OleDbConnection(conStr);
  

Еще раз спасибо за вашу помощь

Комментарии:

1. к вашему сведению, 256 — это действительно маленькая длина буфера, есть на то причины? Я бы рекомендовал не менее 1024.