Member 12586110 Ответов: 2

C# использование асинхронного метода для отправки сообщения обратно в другое приложение


Привет, я разработал метод POST (), который будет вызван из стороннего приложения для вызова этого api, и теперь мы немного подправляем его, чтобы скопировать поток данных и освободить вызов с сообщением об успехе из стороннего приложения и выполнить последующую обработку асинхронно. Не могли бы вы провести меня через это? Заранее спасибо.

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

public class DataController : Controller
    {
        private IList<string> errors = new List<string>();

        [HttpPost]
        [Route("data/import", Name = "DataImport")]
        public IActionResult Post()
        {
            var rawdata = ConvertToByteArray(Request.Body); 
            var rdrec = Encoding.UTF8.GetString(content).Split(new string[] { Environment.NewLine, @"\r" }, StringSplitOptions.None).ToList();
            
            Task.Run(() => importdata(rdrec)); //Trying to run asynchronously to send message back to the third party client.
			
            if (errors.Count == 0)
                return Ok("POST");
            else
                return Ok(errors);
        }

        private void importdata(IList<string> lines)
        {
            //string connectionString = @"Data Source=localhost;Initial Catalog=TEST_DB;Integrated Security=True";
			string connectionString = ConfigurationManager.ConnectionStrings["SQLDBCONN"].ConnectionString; // Added this to appsettings.json file and get null reference error in ASP.net core; works fine in ASP.net web api
            var message = "";

            var Data = from line in lines
                        let data = line.Split(',')
                        select new filedata
                        {
                            ID = data[0],
                            Type = data[1],
                            Status = data[2],
                            Description = data[3]
                        };               

            using (SqlConnection sqldbConnection = new SqlConnection(connectionString))
            {
                        sqldbConnection.Open();                       
                            foreach (var i in Data)
                            {
                                try
                                {
                                    using (SqlCommand cmd = new SqlCommand("INSERT INTO [dbo].[testImport] ([ID], [Type], [Status], [Description]) VALUES (@ID, @Type, @Status, @Description)", sqldbConnection))
                                    {
                                        cmd.Parameters.AddWithValue("@ID", i.ID);                                      
                                        cmd.Parameters.AddWithValue("@Type", i.Type);
                                        cmd.Parameters.AddWithValue("@Status", i.Status);
                                        cmd.Parameters.AddWithValue("@Description", i.Description);
                                        cmd.ExecuteNonQuery();
                                    }
                                }
                                catch (Exception ex)
                                {
                                    message = ex.StackTrace;
                                    return (message);
                                }
                            }                     

            }

        }
		
        private byte[] ConvertToByteArray(Stream stream)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                stream.CopyTo(ms);
                return ms.ToArray();
            }
        }		
    }

Afzaal Ahmad Zeeshan

Что именно Вы имеете в виду, посылая ответ асинхронно?

Member 12586110

Привет, Афзаал Ахмад Зеешан, большое спасибо за ваш ответ. Я имел в виду вместо того, чтобы ждать завершения вставки таблицы, как отправить успешный ответ, как только поток данных будет скопирован в память и вставка таблицы будет выполнена асинхронно.

С уважением

2 Ответов

Рейтинг:
1

Gerry Schmitz

В вашем случае сообщение идет от процесса "asynch" к серверу, а затем к клиенту; не от процесса непосредственно к клиенту.


Member 12586110

Привет, Джерри Шмитц, большое спасибо за ваш ответ. Не могли бы вы объяснить, как мне сделать так, чтобы сообщение шло непосредственно от процесса к клиенту, а не от асинхронного процесса.

С уважением

Рейтинг:
0

Richard Deeming

Начните с того, что сделайте свой код правильно асинхронным и оберните команды insert в транзакцию.

ASP.NET основной:

public class DataController : Controller
{
    [HttpPost]
    [Route("data/import", Name = "DataImport")]
    public async Task<IActionResult> Post()
    {
        try
        {
            using (var reader = new StreamReader(Request.Body, Encoding.UTF8))
            {
                await ImportDataAsync(reader);
                return Ok("POST");
            }
        }
        catch (Exception ex)
        {
            return BadRequest(ex.Message);
        }
    }
    
    private async Task ImportData(TextReader input)
    {
        string connectionString = ConfigurationManager.ConnectionStrings["SQLDBCONN"].ConnectionString;
        const string query = "INSERT INTO [dbo].[testImport] ([ID], [Type], [Status], [Description]) VALUES (@ID, @Type, @Status, @Description)";
        
        using (SqlConnection sqldbConnection = new SqlConnection(connectionString))
        {
            await sqldbConnection.OpenAsync();
            
            using (SqlTransaction transaction = sqldbConnection.BeginTransaction())
            using (SqlCommand cmd = new SqlCommand(query, sqldbConnection, transaction))
            {
                // TODO: Set the correct data types and sizes here:
                var pID = cmd.Parameters.Add("@ID", SqlDbType.Int);
                var pType = cmd.Parameters.Add("@Type", SqlDbType.VarChar);
                var pStatus = cmd.Parameters.Add("@Status", SqlDbType.VarChar);
                var pDescription = cmd.Parameters.Add("@Description", SqlDbType.VarChar);
                
                string line = await input.ReadLineAsync();
                while (line != null)
                {
                    string[] parts = line.Split(',');
                    if (parts.Length < 4) throw new InvalidOperationException($"Invalid line: '{line}'");
                    
                    pID.Value = parts[0];
                    pType.Value = parts[1];
                    pStatus.Value = parts[2];
                    pDescription.Value = parts[3];
                    
                    await cmd.ExecuteNonQueryAsync();
                    
                    line = await input.ReadLineAsync();
                }
                
                transaction.Commit();
            }
        }
    }
}
ASP.NET веб-API 2:
public class DataController : ApiController
{
    [HttpPost]
    [Route("data/import", Name = "DataImport")]
    public async Task<IHttpActionResult> Post()
    {
        try
        {
            string content = await Request.Content.ReadAsStringAsync();
            string[] lines = content.Split(Environment.NewLine);
            await ImportDataAsync(lines);
            return Ok("POST");
        }
        catch (Exception ex)
        {
            return BadRequest(ex.Message);
        }
    }
    
    private async Task ImportData(IEnumerable<string> lines)
    {
        string connectionString = ConfigurationManager.ConnectionStrings["SQLDBCONN"].ConnectionString;
        const string query = "INSERT INTO [dbo].[testImport] ([ID], [Type], [Status], [Description]) VALUES (@ID, @Type, @Status, @Description)";
        
        using (SqlConnection sqldbConnection = new SqlConnection(connectionString))
        {
            await sqldbConnection.OpenAsync();
            
            using (SqlTransaction transaction = sqldbConnection.BeginTransaction())
            using (SqlCommand cmd = new SqlCommand(query, sqldbConnection, transaction))
            {
                // TODO: Set the correct data types and sizes here:
                var pID = cmd.Parameters.Add("@ID", SqlDbType.Int);
                var pType = cmd.Parameters.Add("@Type", SqlDbType.VarChar);
                var pStatus = cmd.Parameters.Add("@Status", SqlDbType.VarChar);
                var pDescription = cmd.Parameters.Add("@Description", SqlDbType.VarChar);
                
                foreach (string line in lines)
                {
                    string[] parts = line.Split(',');
                    if (parts.Length < 4) throw new InvalidOperationException($"Invalid line: '{line}'");
                    
                    pID.Value = parts[0];
                    pType.Value = parts[1];
                    pStatus.Value = parts[2];
                    pDescription.Value = parts[3];
                    
                    await cmd.ExecuteNonQueryAsync();
                }
                
                transaction.Commit();
            }
        }
    }
}

То, как вы обновите вызывающий код, чтобы сделать его асинхронным, будет зависеть от того, какой язык вы используете.


Member 12586110

Привет, Ричард Диминг, большое спасибо за ваш ответ. Я сталкиваюсь с ошибками по запросу.Body HttpRequestMessage не содержит определения для body. вход.ReadLineAsync() Входное имя не существует в текущем контексте. Также как использовать SqlBulkCopy с асинхронностью.

С уважением

Richard Deeming

Тот факт, что ты возвращаешься IActionResult[^] вместо того чтобы IHttpActionResult предположил бы, что вы используете ASP.NET ядро.

В ASP.NET ядро, то Request возвращает свойство HttpRequest[^] объект, а не ан HttpRequestMessage объект. То HttpRequest имеет Body собственность.

Если Request возвращается Ан HttpRequestMessage объект, который наводит на мысль, что вы нет использование ASP.NET ядро. В этом случае ваш код не будет компилироваться.

Я обновлю свой ответ, чтобы добавить код для работы с ним HttpRequestMessage также.

Member 12586110

Спасибо Ричарду Димингу, я буду работать над этим и держать вас в курсе.