How to call an async method synchronously in C#

Markus Freitag 3,786 Reputation points
2023-05-25T18:25:42.11+00:00

Hello, How can I call an asynchronous function from a synchronous function?

Thanks for tips and your help!



private async void btnTest_Click(object sender, EventArgs e)
//private void btnTest_Click(object sender, EventArgs e)
{
	Panel testPanel = new Panel() { BoardId = "25052023", Mode = Panel.ModePanel.NotDefine, No = 1 };

	if (!m_running)
	{
		try
		{
			// Update display to indicate we are running
			m_running = true;
			statusLabel.Text = "Working";
			btnTest.Text = "Cancel";

			m_cancelTokenSource = new CancellationTokenSource();

			Trace.WriteLine($"Before Task TestSecondTask       MainThread Panel No= '{testPanel.No}'");

			await TestSecondTask(m_cancelTokenSource.Token, testPanel);
			//var task = TestSecondTask(m_cancelTokenSource.Token, testPanel);
			//var result = task.Result;
  //##### I don't have here a *Resultvalue

			Trace.WriteLine($"After Task TestSecondTask       MainThread Panel No= '{testPanel.No}'");
		}
		catch (Exception ex)
		{
			if (ex is OperationCanceledException)
			{
				Trace.WriteLine($"Message exception= '{ex.Message}'");

				Trace.WriteLine($"CANCEL Task TestSecondTask       MainThread Panel No= '{testPanel.No}'");
			}
		}
		finally
		{
			// Reset the UI
			btnTest.Text = "Start";
			m_running = false;
			m_cancelTokenSource = null;
		}
	}
	else
	{
		// User hit the Cancel button, so signal the cancel token and put a temporary message in the UI
		statusLabel.Text = "Waiting to cancel...";
		m_cancelTokenSource.Cancel();
	}
}


Task TestSecondTask(CancellationToken ct, Panel testPanel)
{
	return Task.Run(() =>
	{
		for (int i = 0; i < 100; i++)
		{
			ct.ThrowIfCancellationRequested();
			if (ct.IsCancellationRequested)
				break;

			++testPanel.No;

			// Make work
			Thread.Sleep(1000);
		}
	}, ct);
}

public class Panel
{
	public enum ModePanel
	{
		NotDefine = -1,
		Passthrough = 0,
		Mark = 1
	}

	[XmlAttribute("no")]
	public int No { get; set; }

	[XmlAttribute("mode")]
	public ModePanel Mode { get; set; }

	[XmlAttribute("BoardId")]
	public string BoardId { get; set; }
}

public class Order
{
   [XmlAttribute("no")]
	public int No { get; set; }


	[XmlAttribute("Name")]
	public string OrderName { get; set; }
}






//Not work, I didn't have it.  Need I here a return value? Result value?

// Synchronous method
void Method() 
{
    var task = MethodAsync();
    var result = task.Result;
}
// Asynchronous method
public async Task<int> MethodAsync() 
{
    return await Task.Run(() => { return 1; });
//** or 
return Task.Run(() =>
	{
		for (int i = 0; i < 100; i++)
		{
			ct.ThrowIfCancellationRequested();
			if (ct.IsCancellationRequested)
				break;

			++testPanel.No;

			// Make work
			Thread.Sleep(1000);
		}
return 0; // Return value?
	}, ct);
}
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,640 questions
{count} votes

Accepted answer
  1. Konstantinos Passadis 17,456 Reputation points MVP
    2023-05-25T18:47:23.7766667+00:00

    Hello @Markus Freitag !

    In C#, you can call an asynchronous function from a synchronous function by using the Result property or the Wait method of the Task object. However, it's important to note that blocking the synchronous function to wait for the asynchronous operation to complete can lead to potential deadlocks in certain scenarios, such as UI applications.
    Here's an example of how you can call an asynchronous function from a synchronous function using the Result property:
    csharp
    void Method()
    {
        var task = MethodAsync();
        var result = task.Result;
    }
    
    public async Task<int> MethodAsync()
    {
        // Asynchronous operation
        await Task.Delay(1000);
    
        return 1;
    }
    In the above example, the Method function is synchronous, and it calls the MethodAsync function, which is asynchronous. By accessing the Result property of the Task object returned by MethodAsync, we can block the execution of the Method function until the asynchronous operation completes and get the result.
    However, it's generally recommended to keep the asynchronous flow throughout your codebase to fully leverage the benefits of asynchronous programming and avoid potential issues like deadlocks. If possible, consider making the calling function asynchronous as well. For UI applications, it's particularly important to keep the main thread responsive by using asynchronous patterns like async/await instead of blocking calls.
    In your provided code, since the btnTest_Click event handler is an asynchronous void method, you can directly use the await keyword to call the TestSecondTask method asynchronously. You don't need to block and retrieve the result using Result. The current approach you have with await TestSecondTask(...) is the correct way to call the asynchronous method in an asynchronous context.
    csharp
    private async void btnTest_Click(object sender, EventArgs e)
    {
        // ...
    
        await TestSecondTask(m_cancelTokenSource.Token, testPanel);
    
        // ...
    }
    It's important to handle exceptions properly in asynchronous code, and in your case, you're handling the OperationCanceledException to catch cancellation requests.
    
    
    
    

    I hope this helps!

    The answer or portions of it may have been assisted by AI Source: ChatGPT Subscription

    Kindly mark the answer as Accepted and Upvote in case it helped or post your feedback to help !

    Regards


1 additional answer

Sort by: Most helpful
  1. SurferOnWww 2,491 Reputation points
    2023-05-26T00:45:24.8066667+00:00

    Please refer to the following Microsoft document:

    Avoid blocking calls

    https://learn.microsoft.com/en-us/aspnet/core/fundamentals/best-practices?view=aspnetcore-6.0#avoid-blocking-calls

    It says "Do not use Task.Run to make a synchronous API asynchronous."

    0 comments No comments