In today's article, we will see how to implement multithreading with real-time updates shown in ASP.NET Core 2.0 web application.
Why do we need this?
In real-world applications, once in a while, we are faced with the issue of having to process too much data. Real life examples are
- Processing hundreds of records at once, the user has a checkbox and can check as many he/she wants.
- There might be a procedure that takes a few minutes to execute for a single record and you have to process multiple records at once.
In all of these situations, you have to think about the processing time and database timeout. So, for these issues, we can use multithreading. We can execute our time-consuming methods in a separate thread so that the processing of the main thread is not blocked and all the records are processed.
Let’s get started.
Here is the DB structure and Stored Procedures (Microsoft SQL Server).
Table structure of MultiProcessStatus

GetMultiprocessStatus Stored procedure
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
ALTER PROCEDURE [dbo].[GetMultiprocessStatus]
(
@UserId NVARCHAR(200),
@Module NVARCHAR(200)
)
AS
BEGIN
SELECT TOP 1 * FROM MultiProcessStatus WHERE UserId = @UserId AND Module = @Module ORDER BY Id DESC
END
InsertMultiprocessStatus Stored procedure
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
ALTER PROCEDURE [dbo].[InsertMultiprocessStatus]
(
@UserId NVARCHAR(200),
@Module NVARCHAR(200),
@TotalRecords INT,
@ReturnId INT OUTPUT
)
AS
BEGIN
SET @ReturnId = 0
INSERT INTO MultiProcessStatus (UserId,Module,TotalRecords,FailedRecords,SuccessRecords,Percentage,IsCompleted,CreatedDate)
VALUES (@UserId,@Module,@TotalRecords,0,0,0,0,GETDATE())
SET @ReturnId = @@IDENTITY
END
UpdateMultiprocessStatus Stored procedure
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
ALTER PROCEDURE [dbo].[UpdateMultiprocessStatus]
(
@Id INT,
@Percentage DECIMAL(18,2),
@IsCompleted BIT,
@FailedRecords INT,
@SuccessRecords INT
)
AS
BEGIN
IF(@Percentage > 99)
BEGIN
SET @IsCompleted = 1
END
UPDATE MultiProcessStatus SET Percentage = @Percentage,IsCompleted = @IsCompleted,
FailedRecords = @FailedRecords,SuccessRecords = @SuccessRecords
WHERE Id = @Id
END
Now, we will create our ASP.NET Core 2.0 Web Application. We will select ASP.NET Core Web Application which will be under .NET Core.

Then, we will select the Web Application(Model-View-Controller) as our template.

Once our project is created, we will create a new controller (UserController in this case) and work on that.
Now, first of all, we will make some HTML, CSS, and jQuery changes to show our progress bar which will show the status of multithreading process.
Add this piece of HTML in _layout.cshtml just below where <nav> tag ends.
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12 col-lg-12">
<div id="myProgress" class="progress nodisplay">
<div id="myProgressBar" class="progress-bar-striped progress-bar-animated"></div>
<div id="emptyProgress">
<div class="fast-loader"></div>
</div>
</div>
</div>
</div>
Once you have done that, place this HTML just below the <div class=”container”> ends.
<div id="snackbar"></div>
When you are done with that, place this piece of the script just above @RenderSection(“Scripts”,required:false).
<script>
var multiProcessStatusGetUrl = "@Url.Action("GetMultiProcessStatus","User")";
var userId = "Ravi";
var moduleName = "User";
</script>
This script section just defines a URL and two variables that we will use in the AJAX call to get the status of multithreading process. (Will be explained later)
Now we have to define some CSS but I will not post the CSS here because it's not so much relevant. However, I will leave a link for the entire code for you guys to download.
Now, we will create a view in our user controller and will add a button. On the click event of this button, we will start our heavy processes.
For database operations, I have used the factory pattern with lazy loading, I will not get into the details of the architecture, I have already written an article explaining this architecture. Click here to read that article.
Now, we will add a Test method in our UserController which will be called to perform heavy operations.
public JsonResult Test()
{
var isDone = true;
var msg = "Process submitted";
Task.Factory.StartNew(() =>
{
var conStr = appSettings.Value.DbConn;
var client = DbClientFactory<MultiprocessDbClient>.Instance;
var totalRecords = 50;
var id = client.InsertMultiprocessStatus(conStr, "Ravi", "User", totalRecords);
int success = 0, fail = 0;
var isComplete = false;
for (int i = 0; i < totalRecords; i++)
{
isComplete = false;
Thread.Sleep(500);
decimal percentage = Convert.ToDecimal((Convert.ToDecimal(i + 1) / Convert.ToDecimal(totalRecords))) * Convert.ToDecimal(100);
success++;
if ((success + fail) == totalRecords)
isComplete = true;
client.UpdateMultiprocessStatus(conStr, id, percentage, isComplete, fail, success);
}
});
var obj = new { isSuccess = isDone, returnMessage = msg };
return Json(obj);
}
In the above method, I have created a new thread with Task.Factory.StartNew.
Inside the body of new thread I have declared a client, and then inserted a multiprocess request in our database with parameters as connectionString, username i.e Ravi (hardcoded for testing purpose, you will pass it as the user id of the logged in user).
Next is moduleName i.e User (again hardcoded for testing purpose, you will pass the module on which user is going to perform the action such as User, Employee, Leave etc.).
Next is total records (these will be the total number of records that you need to processed, generally a list will be posted so this will be the list.Count)
Now. I have written a simple for loop to iterate up to my total records (in real case scenario you will be iterating through each item of the list posted by the user). Then, I have written Thread.Sleep(500).
This is just to replicate a database operation where you will take values from an item of the list and post them to your database. Now once the operation is completed, then you will get the result whether its failure or success.





Aniket NarvankarPosted Sep 29, 2021, 3:06 PM
Nice Application
ankit pandeyPosted Nov 23, 2020, 1:24 AM
Great Demo application, Shall we implement same in Entity Framework. for Real Time update.
Monika DayalPosted Jan 29, 2020, 12:30 PM
Hi Ravi, does this solution will work fine on Azure app service ?
Hellan AdamPosted Aug 11, 2018, 12:54 AM
Interesting blog, helped to clarify many things, definitely this will be a useful article. Good work, excepting these kinds of more useful blogs and articles. Thanks and Regards, Hellan, smarther.co