Click here to Skip to main content
15,887,683 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi, I developed a POST() method to be called from a third-party application to call this api and now we are tweaking this a bit to copy the datastream and release the call with success message from third-party application and do the downstream processing asynchronously. Could you please guide me through this. Thank you in advance.

What I have tried:

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();
            }
        }		
    }
Posted
Updated 27-Aug-19 9:14am
Comments
Afzaal Ahmad Zeeshan 25-Aug-19 12:32pm    
What exactly do you mean send the response asynchronously?
Member 12586110 25-Aug-19 13:51pm    
Hi Afzaal Ahmad Zeeshan, Thanks very much for your response. I meant instead of waiting for the table insertion to complete, how to send a success response as soon as data stream is copied into memory and table insertion is done asynchronously.

Regards

Start by making your code properly asynchronous, and wrapping the insert commands in a transaction.

ASP.NET Core:
C#
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 Web API 2:
C#
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();
            }
        }
    }
}

How you update the calling code to make that asynchronous will depend on which language you're using.
 
Share this answer
 
v3
Comments
Member 12586110 28-Aug-19 23:43pm    
Hi Richard Deeming, Thanks very much for your response. I am running into errors at Request.Body HttpRequestMessage does not contain a definition for body. input.ReadLineAsync() The name input does not exist in the current context. Also how to use SqlBulkCopy with async.

Regards
Richard Deeming 29-Aug-19 7:13am    
The fact that you're returning IActionResult[^] rather than IHttpActionResult would suggest that you're using ASP.NET Core.

In ASP.NET Core, the Request property returns an HttpRequest[^] object, not an HttpRequestMessage object. The HttpRequest has a Body property.

If Request is returning an HttpRequestMessage object, that would suggest you're not using ASP.NET core. In which case, your code won't compile.

I'll update my answer to add the code for working with HttpRequestMessage as well.
Member 12586110 30-Aug-19 12:38pm    
Thanks Richard Deeming, I will work on it and keep you posted.
In your case, the message goes from the "asynch" process to the server, and then to the client; not from the process directly to the client.
 
Share this answer
 
Comments
Member 12586110 25-Aug-19 14:01pm    
Hi Gerry Schmitz, Thanks very much for your response. Could you please guide how do I make the message go directly from process to the client instead of async process.

Regards

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900