Reputation: 824
I have some doubt related to some best practices regarding the asynchronous events. More exactly related to assigning the async
modifier to a void method (that triggers an EventHandler
)
My app's supposed to work to do some tests on the background and when I finish up the execution to upload my results to my Db.
Before asking the question I've taken a look over here but I still feel that I am doing something wrong.
From what I've tested there is no apparent reason (for my specific case) to apply the async
modifier when I am calling the event handler because specifying the async
modifier to subscriber's
underlying methods it'll 'dial-back' when meeting the first await
resuming the program execution until the awaited action finishes up, working perfectly as I wanted.
My doubt came when I started applying (1'st approach) the async
modifier to a void method (the WorkerClass
) even though it's the event handler, am I doing it wrongly ?
I've done the following test : Made a stored procedure which delays it's execution for about a minute
alter procedure TestStoredProcedure
@WhileValue int
as
begin
set nocount on;
begin transaction
begin try
waitfor delay '00:01';
insert into WhileResults(Value)
values
(@WhileValue)
commit tran;
end try
begin catch
raisError('Error',16,1);
rollback tran;
end catch;
return;
end
go
This is my 1'st approach :
class Program
{
static void Main(string[] args)
{
var workerClass = new WorkerClass();
var engine = new PlaybackEngine();
engine.TestFinishedEventHandler += workerClass.WorkSomething;
engine.TestRun();
}
}
class PlaybackEngine
{
public EventHandler TestFinishedEventHandler;
public void TestRun()
{
var i = 0;
while (i < 10000)
{
Console.WriteLine(i);
i++;
OnTestFinishedEventHandler(i,new EventArgs());
}
}
protected virtual void OnTestFinishedEventHandler(object sender, EventArgs args)
{
TestFinishedEventHandler?.Invoke(sender,args);
}
}
class WorkerClass
{
public async void WorkSomething(object sender, EventArgs args)
{
await UploadToDbAsync((int)sender);
}
private async Task UploadToDbAsync(int i)
{
using (var sqlConn = new SqlConnection("Data Source=EDWARD;Initial Catalog=TestDb;Integrated Security=True"))
using (var sqlCommand = new SqlCommand())
{
sqlConn.Open();
sqlCommand.Connection = sqlConn;
sqlCommand.CommandTimeout = 1000000;
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.CommandText = "dbo.TestStoredProcedure";
sqlCommand.Parameters.AddWithValue("@WhileValue", i);
await sqlCommand.ExecuteNonQueryAsync();
sqlConn.Close();
}
}
}
My second approach is :
class Program
{
static void Main(string[] args)
{
var workerClass = new WorkerClass();
var engine = new PlaybackEngine();
// engine.TestFinishedEventHandler += workerClass.WorkSomething;
engine.TestFinished += workerClass.WorkSomething;
engine.TestRun();
}
}
class PlaybackEngine
{
public delegate Task TestRunEventHandler(object source, EventArgs args);
public event TestRunEventHandler TestFinished;
public void TestRun()
{
var i = 0;
while (i < 10000)
{
/* Doing some work here */
i++;
OnTestRan(i,new EventArgs());
Console.WriteLine(i);
}
}
protected virtual async void OnTestRan(object source, EventArgs args)
{
//await TestFinished?.Invoke(source, EventArgs.Empty);
if (TestFinished != null)
await TestFinished(source, new EventArgs());
}
}
class WorkerClass
{
public async Task WorkSomething(object sender, EventArgs args)
{
await UploadToDbAsync((int)sender);
}
private async Task UploadToDbAsync(int i)
{
using (var sqlConn = new SqlConnection("Data Source=EDWARD;Initial Catalog=TestDb;Integrated Security=True"))
using (var sqlCommand = new SqlCommand())
{
sqlConn.Open();
sqlCommand.Connection = sqlConn;
sqlCommand.CommandTimeout = 1000000;
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.CommandText = "dbo.TestStoredProcedure";
sqlCommand.Parameters.AddWithValue("@WhileValue", i);
await sqlCommand.ExecuteNonQueryAsync();
sqlConn.Close();
}
}
Upvotes: 1
Views: 262
Reputation: 1151
My doubt came when I started applying (1'st approach) the async modifier to a void method (the WorkerClass) even though it's the event handler, am I doing it wrongly ?
No, you're doing it correctly and you should not have any doubts. You should avoid using async void, unless it's an event handler. That's the only acceptable place to use async void.
Async/Await - Best Practices in Asynchronous Programming - You should read this article if you are interested in more best practices about asynchronous programming.
Upvotes: 3