Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
vermeir_nico_introducing_net_6_getting_started_with_blazor_m.pdf
Скачиваний:
19
Добавлен:
26.06.2023
Размер:
11.64 Mб
Скачать

Chapter 11 Advanced .NET 6

public class ResourcesService

{

public async Task<string> FetchAllResources()

{

var client = RestClient.GetClientInstance(); var result = await client.GetAsync(“/api/data”). ConfigureAwait(false);

string json = await result.Content.ReadAsStringAsync(). ConfigureAwait(false);

return json;

}

}

The FetchAllResources method has two calls that are awaited and uses ConfigureAwait(false) because we do not need to switch back to the caller context. By not returning to caller context in that method, we prevent two context switches to occur.

The FetchData method doesn’t use ConfigureAwait(false) because it needs to return to the caller context. The caller context here is the UI thread. The property that the returned value is being set to will trigger a change notification, so we need to be on the UI thread.

Cancellations

In Async operations, we often make use of CancellationTokens to cancel long running tasks. These tokens are used quite a lot across the base class library as well. However, cancelling tasks does not happen that often so it would be interesting to be able to reuse

CancellationTokenSource, the object that generates CancellationTokens. Up until now, we couldn’t do this safely because we couldn’t be certain that some tasks were still referencing this token. In .NET 6, CancellationTokenSource was extended with a TryReset method. Listing 11-10 shows the use of the TryReset method.

308

Chapter 11 Advanced .NET 6

Listing 11-10.  Try to reset a cancellation token

CancellationTokenSource _cancellationTokenSource = new

CancellationTokenSource();

private void CancelButton_OnClick(object sender, EventArgs args)

{

_cancellationTokenSource.Cancel();

}

public async Task DoWork()

{

if (!_cancellationTokenSource.TryReset())

{

_cancellationTokenSource = new CancellationTokenSource();

}

Task<string> data = FetchData(_cancellationTokenSource.Token);

}

public async Task<string> FetchData(CancellationToken token)

{

token.ThrowIfCancellationRequested();

var client = new HttpClient();

HttpResponseMessage response = await client.GetAsync("https://www. apress.com", token).ConfigureAwait(false);

string html = await response.Content.ReadAsStringAsync(token). ConfigureAwait(false);

return html;

}Once a token was actually cancelled it cannot be recycled and the TryReset method will return false.

The example shown here comes from a WinForms application where we can load data and cancel it using a cancel button. When calling the DoWork method, we try to reset the CancellationTokenSource; if we don’t succeed, we instantiate a new one.

309

Chapter 11 Advanced .NET 6

The CancellationTokenSource's CancellationToken is passed to the LoadData method. LoadData checks if the token is not cancelled and uses it for loading and deserializing the data. As long as the token was not cancelled, we can keep resetting the

CancellationTokenSource for reuse.

WaitAsync

In .NET 6, Microsoft is giving us more control over when to cancel or timeout asynchronous operations by adding WaitAsync methods to Task. With WaitAsync, we can specify a cancellation token or a timeout to a task.

Listing 11-11.  WaitAsync with a cancellation token

CancellationToken token = _cancellationTokenSource.Token;

var client = new HttpClient();

Task<HttpResponseMessage> response = client.GetAsync("https://www.apress.com", token)

.WaitAsync(token);

await response;

Listing 11-12 shows the three different options.

Listing 11-12.  All WaitAsync overloads

Task<HttpResponseMessage> taskWithToken = client

.GetAsync("https://www.apress.com", token)

.WaitAsync(token);

Task<HttpResponseMessage> taskWithTimeout = client

.GetAsync("https://www.apress.com", token)

.WaitAsync(new TimeSpan(0, 0, 10));

Task<HttpResponseMessage> taskWithBoth = client

.GetAsync("https://www.apress.com", token)

.WaitAsync(new TimeSpan(0, 0, 10), token);

310