Member 14211408 Ответов: 1

Привет друзья, кто-нибудь может мне помочь. Как прочитать файл xlsx/csv из корзины AWS S3 в C# windows forms gridview. Ниже приведен мой код


private void btnUpload_Click(object sender, EventArgs e)
        {
            try
            {
                string bucketName = string.Empty, fileName = string.Empty;//, 
                accessKey = string.Empty, SecretKey = string.Empty;
                this.Cursor = Cursors.WaitCursor;
                bucketName = "ben-s3lambdaevent"; //"ben-hrms";
                fileName = string.Format("{0}", this.SoftCopyFileName);

                //AmazonS3 s3Obj = new AmazonS3();
                string msg = UploadFile(bucketName, openFileDialog1.FileName, fileName);

                if (msg.ToUpper() == SUCCESS_MSG)
                {
                    btnBrowse.Enabled = false;
                }
                DataTable table = new DataTable();
                
                Amazon.RegionEndpoint region = Amazon.RegionEndpoint.APSouth1;
                table = GetS3SelectDetails(accessKey, SecretKey, bucketName, fileName, region);
                dgvGrid.DataSource = table;
                this.Cursor = Cursors.Default;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, TECHNO_MSG);
                //if (access == null) access = new BusinessConnector();
                //access.DBConnector.ErrorLogInsert(ex.Message, "frmServiceInvoice.cs.btnBrowse_Click()");
            }
        }

        public DataTable GetS3SelectDetails(string accessKey, string SecretKey, string bucketName, string fileName, Amazon.RegionEndpoint region)
        {
            DataTable dt = (DataTable)GetAmazonS3Select(accessKey, SecretKey, bucketName, fileName, region).Result;

            return dt;
        }

        public async Task<datatable> GetAmazonS3Select(string accessKey, string SecretKey, string bucketName, string fileName, Amazon.RegionEndpoint region)
        {
            DataTable table = new DataTable();
            using (var eventStream = await GetSelectObjectContentEventStream(accessKey, SecretKey, bucketName, fileName, region))
            {
                var recordResults = eventStream
                .Where(ev => ev is RecordsEvent)
                .Cast<recordsevent>()
                .Select(records =>
                {
                    using (var reader = new StreamReader(records.Payload, Encoding.UTF8))
                    {
                        return reader.ReadToEnd();
                    }
                }).ToArray();

                string[] fileData = recordResults[0].ToString().Split('\n');

                for (int i = 0; i < fileData.Length; i++)
                {
                    string[] rowData = fileData[i].ToString().Split(';');

                    if (i == 0)
                    {
                        for (int j = 0; j < rowData.Length; j++)
                        {
                            table.Columns.Add(rowData[j].ToString(), typeof(string));
                        }
                    }
                    else
                    {
                        DataRow row = table.NewRow();
                        for (int j = 0; j < rowData.Length; j++)
                        {
                            row[j] = rowData[j].ToString();
                        }
                        table.Rows.Add(row);
                    }
                }
            }
            return table;
        }

        public async Task<iselectobjectcontenteventstream> GetSelectObjectContentEventStream(string accessKey, string SecretKey, string bucketName, string fileName, Amazon.RegionEndpoint region)
        {
            SelectObjectContentResponse response1 = null;
            try
            {
                IAmazonS3 client1 = new AmazonS3Client(accessKey, SecretKey, region);

                SelectObjectContentRequest request = new SelectObjectContentRequest();
                request.Bucket = bucketName;
                request.Key = fileName;
                request.ExpressionType = Amazon.S3.ExpressionType.SQL;
                request.Expression = "select * from S3Object";

                request.InputSerialization = new InputSerialization()
                {
                    CSV = new CSVInput()
                    {
                        FileHeaderInfo = FileHeaderInfo.Use
                        //FieldDelimiter = ";",
                    }
                };

                request.OutputSerialization = new OutputSerialization()
                {
                    CSV = new CSVOutput()
                    {
                        //QuoteFields = QuoteFields.Always
                        FieldDelimiter = ";"
                    }
                };
   ------------  response1 = await client1.SelectObjectContentAsync(request);
            }
            catch (Exception ex)
            {

            }
            return response1.Payload;
        }


Что я уже пробовал:

после загрузки данных я не могу прочитать последний (response1 = await) курсор запущен, но дата не получает, пожалуйста, помогите мне

Gerry Schmitz

Если вы спрашиваете: "можно ли поддерживать мой код?" - нет.

1 Ответов

Рейтинг:
6

lmoelleb

Извините, это будет довольно технически. Асинхронность/ожидание, по-видимому, очень проста. Но это не так.

TL;DR ниже.

Для начинающих я рекомендую убедиться, что все ваше приложение асинхронно, или ничего не асинхронно. Как только вы начнете смешивать его, вы получите тупики, если у вас нет очень точных знаний о том, как выполняется асинхронный код. В этом контексте смешивание его конкретно означает вызов Wait или Result для объекта задачи, возвращаемого асинхронным методом.

Один из уроков в основном усвоенных на горьком опыте заключается в том что ждать придется нет начать новую тему. Метод, который вы называете асинхронным вероятно выберите использовать новый поток, но никогда не гарантируйте этого. Когда он решит это сделать, он доставит результат обратно в поток, для которого он был вызван, если только вы специально не скажете ему этого не делать (и если вы это сделаете, вам нужно убедиться, что код после await может работать в новом потоке - чего он не может в вашем случае, поскольку он обновляет пользовательский интерфейс.

Для вашего конкретного примера вы вызываете await из основного потока пользовательского интерфейса. Это означает, что весь код выполняется в основном потоке пользовательского интерфейса - что обычно хорошо, если только нет каких - то тяжелых вычислений (в вашем случае их нет, поэтому не пытайтесь переместить его в другой поток-это просто сделает его медленнее и труднее поддерживать... и он все равно будет заблокирован).

От

btnUpload_Click
вы называете
GetS3SelectDetails
Этот вызов не использует await. Это означает, что как только поток пользовательского интерфейса возвращается из GetS3SelectDetails, он должен получить таблицу из S3. Если бы было использовано ключевое слово await, оно в основном указывало бы потоку пользовательского интерфейса ждать с оставшейся частью кода до тех пор, пока таблица не станет доступной.

Из GetS3SelectDetails вы звоните
GetAmazonS3Select
Это заставляет GetAmazonS3Select начать выполнение до тех пор, пока он не достигнет
response1 = await client1.SelectObjectContentAsync(request);
Поскольку результат этого вызова недоступен сразу (ему нужно сделать сетевой вызов), метод возвращает задачу, в которой он установит результат, как только он будет доступен. Но самое главное, что он сразу же возвращается в GetS3SelectDetails, где вы затем вызываете свойство Result для возвращаемой задачи.

Когда вы вызываете Result, у вас есть то, что известно как блокирующий вызов. Это означает, что основной поток пользовательского интерфейса теперь сидит и ждет, когда кто-то другой установит результат. Он не может сделать ничего другого. Он не может обрабатывать другие нажатия кнопок, позволяет перемещать окно и т. д. Он ничего не будет делать, кроме как ждать этого результата.

Следующее, что происходит, - это результат возвращается из сетевого вызова. Обычно это обрабатывается другим потоком, так что никаких проблем... пока он не захочет установить результат на Задачу. Как я уже писал ранее, это будет по умолчанию (и не меняйте значение по умолчанию, вы еще недостаточно понимаете, чтобы сделать это), чтобы запустить код в том же потоке, в котором он был вызван.

Так что теперь у вас есть:
1) основной поток пользовательского интерфейса, сидящий в свойстве .Result и ожидающий результата
2) Еще одна угроза, ожидающая появления потока пользовательского интерфейса, чтобы он мог установить результат.

Таким образом, оба потока перестанут обрабатывать что-либо и просто будут сидеть там.

Как это исправить:

Сначала измените методы btnUpload_Click и GetS3SelectDetails, чтобы они были асинхронными и возвращали задачи.

Что-то вроде:
private async Task btnUpload_Click(object sender, EventArgs e)...
public Task<DataTable> GetS3SelectDetails(string accessKey, string SecretKey, string bucketName, string fileName, Amazon.RegionEndpoint region)...


Теперь измените GetS3SelectDetails так, чтобы он вызывал GetAmazonS3Select async (чтобы он не блокировал ожидание результата):
DataTable dt = await (DataTable)GetAmazonS3Select(accessKey, SecretKey, bucketName, fileName, region);


Наконец Вам также нужно убедиться что вызов GetS3SelectDetails также ожидает вас:
table = await GetS3SelectDetails(accessKey, SecretKey, bucketName, fileName, region);


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

TL;DR

Если это слишком сложно для вас, чтобы полностью понять (вы доберетесь туда, не волнуйтесь), просто внесите предложенные изменения и возьмите этот ключевой урок из этого: если вы звоните .Результат или .подождите, ваш пользовательский интерфейс будет висеть. Поэтому любой метод, вызывающий асинхронный метод, должен быть асинхронным сам по себе.

- О да.. другая вещь... Не делайте catch с пустым блоком кода, если только вы действительно не ненавидите следующих двух человек (которые могут быть одним и тем же парнем, а может быть, даже вами):
1) пользователь вашего приложения
2) разработчик, который должен выяснить, почему он не работает.

Если вы уверены, что эти двое-самые отвратительные люди, которые когда-либо жили, и они заслуживают всего зла, которое может быть брошено в их общее направление, тогда непременно используйте catch {}.