60
Introduction to the New Asynchronous API in the .NET Driver Robert Stam MongoDB, Inc.

Introduction to the New Asynchronous API in the .NET Driver

  • Upload
    mongodb

  • View
    148

  • Download
    1

Embed Size (px)

Citation preview

Page 1: Introduction to the New Asynchronous API in the .NET Driver

Introduction to the New Asynchronous API

in the .NET Driver

Robert Stam

MongoDB, Inc.

Page 2: Introduction to the New Asynchronous API in the .NET Driver

Intended audience

• Familiar with C# and .NET

• Familiar with MongoDB in general

• Probably familiar with previous versions of the .NET driver

• Maybe haven’t used async programming before

• Interested in using the 2.0 version of the .NET driver

Page 3: Introduction to the New Asynchronous API in the .NET Driver

Topics

• Quick review of async programming in C#

• Benefits of async programming

• Sample data import application using the new async API

• Sample web application using the new async API

• A few advanced async related topics

Page 4: Introduction to the New Asynchronous API in the .NET Driver

Quick overview of async programming

T result = SomeMethod();

// vs

Task<T> task = SomeMethodAsync();

Page 5: Introduction to the New Asynchronous API in the .NET Driver

New async/await keywords

public async Task<T> SomeMethodAsync()

{

T result = await SomeOtherMethodAsync();

return result;

}

Page 6: Introduction to the New Asynchronous API in the .NET Driver

Benefits of async programming

• Threads are expensive (and often limited)

• A blocked thread is not doing any work

• A blocked thread is still consuming resources

• We can get more work done with fewer threads

• We can get higher throughput with the same hardware

Page 7: Introduction to the New Asynchronous API in the .NET Driver

Async does have some overhead

• The compiler transform for async methods is not free

• Measurable, but usually insignificant

• Takeaway is to keep the granularity of async methods coarse

Page 8: Introduction to the New Asynchronous API in the .NET Driver

2.0 .NET driver API is async-only

• There is a trend toward providing async only APIs

• (e.g. HttpClient)

• Microsoft is heavily promoting async programming

Page 9: Introduction to the New Asynchronous API in the .NET Driver

Sample applications

• Using flight delay data from the Department of Transportation• http://www.transtats.bts.gov/OT_Delay/OT_DelayCause1.asp

• Console application to import the data

• Web application to query the data

• Source code in github• https://github.com/rstam/SampleMongoDBApplication

Page 10: Introduction to the New Asynchronous API in the .NET Driver

Sample data

• Flights collection

• Date, Airline, Flight Number, From, To, Scheduled Times, Delays, etc…

• Airlines collection

• Code, Description

• Airports collection

• Code, Description

Page 11: Introduction to the New Asynchronous API in the .NET Driver

Data Importer Console Application

• Using async APIs in a console application

• Dropping collections

• Loading collections

• Creating indexes

Page 12: Introduction to the New Asynchronous API in the .NET Driver

Using the async API from a console application

public static void Main(string[] args)

{

try

{

MainAsync(args).GetAwaiter().GetResult();

}

catch (Exception ex)

{

Console.WriteLine("Exception: {0}", ex);

}

}

Page 13: Introduction to the New Asynchronous API in the .NET Driver

The top level MainAsync method

private static IMongoClient __client;

private static IMongoDatabase __database;

private static async Task MainAsync(string[] args)

{

var connectionString = "mongodb://localhost";

__client = new MongoClient(connectionString);

__database = __client.GetDatabase("flights");

await DropCollectionsAsync();

await LoadCollectionsAsync();

await CreateIndexesAsync();

}

Page 14: Introduction to the New Asynchronous API in the .NET Driver

The top level MainAsync method

private static IMongoClient __client;

private static IMongoDatabase __database;

private static async Task MainAsync(string[] args)

{

var connectionString = "mongodb://localhost";

__client = new MongoClient(connectionString);

__database = __client.GetDatabase("flights");

await DropCollectionsAsync();

await LoadCollectionsAsync();

await CreateIndexesAsync();

}

Page 15: Introduction to the New Asynchronous API in the .NET Driver

The top level MainAsync method

private static IMongoClient __client;

private static IMongoDatabase __database;

private static async Task MainAsync(string[] args)

{

var connectionString = "mongodb://localhost";

__client = new MongoClient(connectionString);

__database = __client.GetDatabase("flights");

await DropCollectionsAsync();

await LoadCollectionsAsync();

await CreateIndexesAsync();

}

Page 16: Introduction to the New Asynchronous API in the .NET Driver

Dropping collections

private static async Task DropCollectionsAsync()

{

await __database.DropCollectionAsync("flights");

await __database.DropCollectionAsync("airlines");

await __database.DropCollectionAsync("airports");

}

Page 17: Introduction to the New Asynchronous API in the .NET Driver

Loading collections

private static async Task LoadCollectionsAsync()

{

await LoadFlightsAsync();

await LoadAirlinesAsync();

await LoadAirportsAsync();

}

Page 18: Introduction to the New Asynchronous API in the .NET Driver

Loading the airlines collection

private static async Task LoadAirlinesAsync(string csvFilename)

{

var airlines = new List<Airline>();

using (var csvReader = new CsvReader(new StreamReader(csvFilename)))

{

foreach (var airline in csvReader.GetRecords<Airline>())

{

if (__seenAirlineIds.Contains(airline.Code))

{

airlines.Add(airline);

}

}

}

var collection = __database.GetCollection<Airline>("airlines");

await collection.InsertManyAsync(airlines);

}

Page 19: Introduction to the New Asynchronous API in the .NET Driver

Loading the airlines collection

private static async Task LoadAirlinesAsync(string csvFilename)

{

var airlines = new List<Airline>();

using (var csvReader = new CsvReader(new StreamReader(csvFilename)))

{

foreach (var airline in csvReader.GetRecords<Airline>())

{

if (__seenAirlineIds.Contains(airline.Code))

{

airlines.Add(airline);

}

}

}

var collection = __database.GetCollection<Airline>("airlines");

await collection.InsertManyAsync(airlines);

}

Page 20: Introduction to the New Asynchronous API in the .NET Driver

Loading the airlines collection

private static async Task LoadAirlinesAsync(string csvFilename)

{

var airlines = new List<Airline>();

using (var csvReader = new CsvReader(new StreamReader(csvFilename)))

{

foreach (var airline in csvReader.GetRecords<Airline>())

{

if (__seenAirlineIds.Contains(airline.Code))

{

airlines.Add(airline);

}

}

}

var collection = __database.GetCollection<Airline>("airlines");

await collection.InsertManyAsync(airlines);

}

Page 21: Introduction to the New Asynchronous API in the .NET Driver

Loading the flights collection

private static async Task LoadFlightsAsync(string csvFilename){

var collection = __database.GetCollection<Flight>("flights");

var batchSize = 1000;using (var csvReader = new CsvReader(new StreamReader(csvFilename))){

var flights = new List<Flight>();

foreach (var flight in csvReader.GetRecords<Flight>()){

PreprocessFlight(flight);flights.Add(flight);

if (flights.Count == batchSize){

await collection.InsertManyAsync(flights);flights.Clear();

}}

if (flights.Count > 0){

await collection.InsertManyAsync(flights);}

}}

Page 22: Introduction to the New Asynchronous API in the .NET Driver

Loading the flights collection

private static async Task LoadFlightsAsync(string csvFilename){

var collection = __database.GetCollection<Flight>("flights");

var batchSize = 1000;using (var csvReader = new CsvReader(new StreamReader(csvFilename))){

var flights = new List<Flight>();

foreach (var flight in csvReader.GetRecords<Flight>()){

PreprocessFlight(flight);flights.Add(flight);

if (flights.Count == batchSize){

await collection.InsertManyAsync(flights);flights.Clear();

}}

if (flights.Count > 0){

await collection.InsertManyAsync(flights);}

}}

Page 23: Introduction to the New Asynchronous API in the .NET Driver

Preprocessing a flight document

private static void PreprocessFlight(Flight flight)

{

if (flight.FL_DATE.HasValue)

{

flight.FL_DATE = DateTime.SpecifyKind(flight.FL_DATE.Value, DateTimeKind.Utc);

}

if (flight.AIRLINE_ID.HasValue)

{

__seenAirlineIds.Add(flight.AIRLINE_ID.Value);

}

if (flight.ORIGIN_AIRPORT_ID.HasValue)

{

__seenAirportIds.Add(flight.ORIGIN_AIRPORT_ID.Value);

}

if (flight.DEST_AIRPORT_ID.HasValue)

{

__seenAirportIds.Add(flight.DEST_AIRPORT_ID.Value);

}

}

Page 24: Introduction to the New Asynchronous API in the .NET Driver

Preprocessing a flight document

private static void PreprocessFlight(Flight flight)

{

if (flight.FL_DATE.HasValue)

{

flight.FL_DATE = DateTime.SpecifyKind(flight.FL_DATE.Value, DateTimeKind.Utc);

}

if (flight.AIRLINE_ID.HasValue)

{

__seenAirlineIds.Add(flight.AIRLINE_ID.Value);

}

if (flight.ORIGIN_AIRPORT_ID.HasValue)

{

__seenAirportIds.Add(flight.ORIGIN_AIRPORT_ID.Value);

}

if (flight.DEST_AIRPORT_ID.HasValue)

{

__seenAirportIds.Add(flight.DEST_AIRPORT_ID.Value);

}

}

Page 25: Introduction to the New Asynchronous API in the .NET Driver

Creating an index

private static async Task CreateIndexesAsync()

{

var indexKeysBuilder = Builders<Flight>.IndexKeys;

var indexKeys = indexKeysBuilder

.Ascending(f => f.FL_DATE)

.Ascending(f => f.AIRLINE_ID)

.Ascending(f => f.ORIGIN_AIRPORT_ID)

.Ascending(f => f.DEST_AIRPORT_ID);

var collection = __database.GetCollection<Flight>("flights");

await collection.Indexes.CreateOneAsync(indexKeys);

}

Page 26: Introduction to the New Asynchronous API in the .NET Driver

Creating an index

private static async Task CreateIndexesAsync()

{

var indexKeysBuilder = Builders<Flight>.IndexKeys;

var indexKeys = indexKeysBuilder

.Ascending(f => f.FL_DATE)

.Ascending(f => f.AIRLINE_ID)

.Ascending(f => f.ORIGIN_AIRPORT_ID)

.Ascending(f => f.DEST_AIRPORT_ID);

var collection = __database.GetCollection<Flight>("flights");

await collection.Indexes.CreateOneAsync(indexKeys);

}

Page 27: Introduction to the New Asynchronous API in the .NET Driver

Sample Web Application

• Two pages

• Search criteria form

• Search results

Page 28: Introduction to the New Asynchronous API in the .NET Driver

Search Criteria Form

Page 29: Introduction to the New Asynchronous API in the .NET Driver

Search Results Page

Page 30: Introduction to the New Asynchronous API in the .NET Driver

MongoClient lifecycle

public class HomeController : Controller

{

private const string __connectionString = "mongodb://localhost";

private static Lazy<MongoClient> __client =

new Lazy<MongoClient>(() => new MongoClient(__connectionString));

// ... rest of HomeController class

}

Page 31: Introduction to the New Asynchronous API in the .NET Driver

Creating the Search Criteria Form

public async Task<ActionResult> Index()

{

var viewModel = await CreateIndexViewModelAsync();

return View(viewModel);

}

public class IndexViewModel

{

public IEnumerable<Airline> Airlines { get; set; }

public IEnumerable<Airport> Airports { get; set; }

}

Page 32: Introduction to the New Asynchronous API in the .NET Driver

Creating the Search Criteria Form

public async Task<ActionResult> Index()

{

var viewModel = await CreateIndexViewModelAsync();

return View(viewModel);

}

public class IndexViewModel

{

public IEnumerable<Airline> Airlines { get; set; }

public IEnumerable<Airport> Airports { get; set; }

}

Page 33: Introduction to the New Asynchronous API in the .NET Driver

Creating the IndexViewModel

private async Task<IndexViewModel> CreateIndexViewModelAsync()

{

// note: the two queries will be run in parallel

var findAirlinesTask = FindAirlinesAsync();

var findAirportsTask = FindAirportsAsync();

await Task.WhenAll(findAirlinesTask, findAirportsTask);

return new IndexViewModel

{

Airlines = findAirlinesTask.Result.OrderBy(a => a.Description),

Airports = findAirportsTask.Result.OrderBy(a => a.Description)

};

}

Page 34: Introduction to the New Asynchronous API in the .NET Driver

Creating the IndexViewModel

private async Task<IndexViewModel> CreateIndexViewModelAsync()

{

// note: the two queries will be run in parallel

var findAirlinesTask = FindAirlinesAsync();

var findAirportsTask = FindAirportsAsync();

await Task.WhenAll(findAirlinesTask, findAirportsTask);

return new IndexViewModel

{

Airlines = findAirlinesTask.Result.OrderBy(a => a.Description),

Airports = findAirportsTask.Result.OrderBy(a => a.Description)

};

}

Page 35: Introduction to the New Asynchronous API in the .NET Driver

Finding the airlines

private async Task<IEnumerable<Airline>> FindAirlinesAsync()

{

var client = __client.Value;

var database = client.GetDatabase("flights");

var collection = database.GetCollection<Airline>("airlines");

return await collection.Find(new BsonDocument()).ToListAsync();

}

Page 36: Introduction to the New Asynchronous API in the .NET Driver

The Index view

@model WebApplication.Models.IndexViewModel

@{Layout = null;ViewBag.Title = "Flight Delays";

}

@using (Html.BeginForm("Search", "Home")){

<div>Search flight delay data:

</div><div>

@Html.Label("From Date:")@Html.TextBox("FromDate")

</div><div>

@Html.Label("To Date:")@Html.TextBox("ToDate")

</div><div>

@Html.Label("Airline:")@Html.DropDownList("AirlineId", Model.Airlines.Select(a => new SelectListItem { Value = a.Id.ToString(), Text = a.Description }), "All")

</div><div>

@Html.Label("Origin:")@Html.DropDownList("OriginId", Model.Airports.Select(a => new SelectListItem { Value = a.Id.ToString(), Text = a.Description }), "All")

</div><div>

@Html.Label("Destination:")@Html.DropDownList("DestinationId", Model.Airports.Select(a => new SelectListItem { Value = a.Id.ToString(), Text = a.Description }), "All")

</div><div>

<input type="submit" value="Search" /></div>

}

Page 37: Introduction to the New Asynchronous API in the .NET Driver

Creating the Search Results Page

[HttpPost]

public async Task<ActionResult> Search(SearchCriteriaModel criteriaModel)

{

var viewModel = await CreateSearchResultViewModelAsync(criteriaModel);

return View("SearchResultView", viewModel);

}

public class SearchResultViewModel

{

public int TotalNumberOfFlights { get; set; }

public int TotalNumberOfDelayedFlights { get; set; }

public double AverageDelayInMinutes { get; set; }

}

Page 38: Introduction to the New Asynchronous API in the .NET Driver

Creating the Search Results Page

[HttpPost]

public async Task<ActionResult> Search(SearchCriteriaModel criteriaModel)

{

var viewModel = await CreateSearchResultViewModelAsync(criteriaModel);

return View("SearchResultView", viewModel);

}

public class SearchResultViewModel

{

public int TotalNumberOfFlights { get; set; }

public int TotalNumberOfDelayedFlights { get; set; }

public double AverageDelayInMinutes { get; set; }

}

Page 39: Introduction to the New Asynchronous API in the .NET Driver

Creating the Search Results View Model

private async Task<SearchResultViewModel> CreateSearchResultViewModelAsync(SearchCriteriaModel criteriaModel)

{var client = __client.Value;var database = client.GetDatabase("flights");var collection = database.GetCollection<Flight>("flights");

var aggregateOfFlight = collection.Aggregate();

var filter = CreateFilter(criteriaModel);if (filter != null){

aggregateOfFlight = aggregateOfFlight.Match(filter);}

var aggregateOfSearchResultViewModel = aggregateOfFlight.Group(f => 1,g => new SearchResultViewModel{

TotalNumberOfFlights = g.Count(),TotalNumberOfDelayedFlights = g.Sum(f => f.ArrivalDelay > 0.0 ? 1 : 0),AverageDelayInMinutes =

(double)g.Average(f => f.ArrivalDelay > 0.0 ? (double?)f.ArrivalDelay : null)});

return await aggregateOfSearchResultViewModel.SingleAsync();}

Page 40: Introduction to the New Asynchronous API in the .NET Driver

Creating the Search Results View Model

private async Task<SearchResultViewModel> CreateSearchResultViewModelAsync(SearchCriteriaModel criteriaModel)

{var client = __client.Value;var database = client.GetDatabase("flights");var collection = database.GetCollection<Flight>("flights");

var aggregateOfFlight = collection.Aggregate();

var filter = CreateFilter(criteriaModel);if (filter != null){

aggregateOfFlight = aggregateOfFlight.Match(filter);}

var aggregateOfSearchResultViewModel = aggregateOfFlight.Group(f => 1,g => new SearchResultViewModel{

TotalNumberOfFlights = g.Count(),TotalNumberOfDelayedFlights = g.Sum(f => f.ArrivalDelay > 0.0 ? 1 : 0),AverageDelayInMinutes =

(double)g.Average(f => f.ArrivalDelay > 0.0 ? (double?)f.ArrivalDelay : null)});

return await aggregateOfSearchResultViewModel.SingleAsync();}

Page 41: Introduction to the New Asynchronous API in the .NET Driver

Creating the Search Results View Model

private async Task<SearchResultViewModel> CreateSearchResultViewModelAsync(SearchCriteriaModel criteriaModel)

{var client = __client.Value;var database = client.GetDatabase("flights");var collection = database.GetCollection<Flight>("flights");

var aggregateOfFlight = collection.Aggregate();

var filter = CreateFilter(criteriaModel);if (filter != null){

aggregateOfFlight = aggregateOfFlight.Match(filter);}

var aggregateOfSearchResultViewModel = aggregateOfFlight.Group(f => 1,g => new SearchResultViewModel{

TotalNumberOfFlights = g.Count(),TotalNumberOfDelayedFlights = g.Sum(f => f.ArrivalDelay > 0.0 ? 1 : 0),AverageDelayInMinutes =

(double)g.Average(f => f.ArrivalDelay > 0.0 ? (double?)f.ArrivalDelay : null)});

return await aggregateOfSearchResultViewModel.SingleAsync();}

Page 42: Introduction to the New Asynchronous API in the .NET Driver

Creating the Search Results View Model

private async Task<SearchResultViewModel> CreateSearchResultViewModelAsync(SearchCriteriaModel criteriaModel)

{var client = __client.Value;var database = client.GetDatabase("flights");var collection = database.GetCollection<Flight>("flights");

var aggregateOfFlight = collection.Aggregate();

var filter = CreateFilter(criteriaModel);if (filter != null){

aggregateOfFlight = aggregateOfFlight.Match(filter);}

var aggregateOfSearchResultViewModel = aggregateOfFlight.Group(f => 1,g => new SearchResultViewModel{

TotalNumberOfFlights = g.Count(),TotalNumberOfDelayedFlights = g.Sum(f => f.ArrivalDelay > 0.0 ? 1 : 0),AverageDelayInMinutes =

(double)g.Average(f => f.ArrivalDelay > 0.0 ? (double?)f.ArrivalDelay : null)});

return await aggregateOfSearchResultViewModel.SingleAsync();}

Page 43: Introduction to the New Asynchronous API in the .NET Driver

A sample resulting aggregation pipeline

[

{ $match : {

FL_DATE : {

$gte : ISODate("2014-12-01T00:00:00Z"),

$lte : ISODate("2014-12-31T00:00:00Z") },

AIRLINE_ID : 19790, /* Delta Airlines */

ORIGIN_AIRPORT_ID : 10397, /* Atlanta Hartsfield International */

DEST_AIRPORT_ID : 12953 } /* New York La Guardia */

},

{ $group : {

_id : 1,

TotalNumberOfFlights : { $sum : 1 },

TotalNumberOfDelayedFlights :

{ $sum : { $cond : [{ $gt : ["$ARR_DELAY", 0.0] }, 1, 0] } },

AverageDelayInMinutes :

{ $avg : { $cond : [{ $gt : ["$ARR_DELAY", 0.0] }, "$ARR_DELAY", null] } } }

}

]

Page 44: Introduction to the New Asynchronous API in the .NET Driver

Creating the Search Results Filter

private FilterDefinition<Flight> CreateFilter(

SearchCriteriaModel criteriaModel)

{

var filterBuilder = Builders<Flight>.Filter;

var clauses = CreateClauses(criteriaModel, filterBuilder);

if (clauses.Count > 0)

{

return filterBuilder.And(clauses);

}

else

{

return null;

}

}

Page 45: Introduction to the New Asynchronous API in the .NET Driver

Creating the clauses

private List<FilterDefinition<Flight>> CreateClauses(SearchCriteriaModel criteriaModel,FilterDefinitionBuilder<Flight> filterBuilder)

{var clauses = new List<FilterDefinition<Flight>>();if (criteriaModel.FromDate != null){

var fromDate = DateTime.SpecifyKind(DateTime.Parse(criteriaModel.FromDate), DateTimeKind.Utc);

var clause = filterBuilder.Gte(f => f.FlightDate, fromDate);clauses.Add(clause);

}if (criteriaModel.ToDate != null){

var toDate = DateTime.SpecifyKind(DateTime.Parse(criteriaModel.ToDate), DateTimeKind.Utc);

var clause = filterBuilder.Lte(f => f.FlightDate, toDate);clauses.Add(clause);

}// code for 3 more clauses (see next slide)return clauses;

}

Page 46: Introduction to the New Asynchronous API in the .NET Driver

Creating the clauses

private List<FilterDefinition<Flight>> CreateClauses(SearchCriteriaModel criteriaModel,FilterDefinitionBuilder<Flight> filterBuilder)

{var clauses = new List<FilterDefinition<Flight>>();if (criteriaModel.FromDate != null){

var fromDate = DateTime.SpecifyKind(DateTime.Parse(criteriaModel.FromDate), DateTimeKind.Utc);

var clause = filterBuilder.Gte(f => f.FlightDate, fromDate);clauses.Add(clause);

}if (criteriaModel.ToDate != null){

var toDate = DateTime.SpecifyKind(DateTime.Parse(criteriaModel.ToDate), DateTimeKind.Utc);

var clause = filterBuilder.Lte(f => f.FlightDate, toDate);clauses.Add(clause);

}// code for 3 more clauses (see next slide)return clauses;

}

Page 47: Introduction to the New Asynchronous API in the .NET Driver

Creating the clauses

private List<FilterDefinition<Flight>> CreateClauses(SearchCriteriaModel criteriaModel,FilterDefinitionBuilder<Flight> filterBuilder)

{var clauses = new List<FilterDefinition<Flight>>();if (criteriaModel.FromDate != null){

var fromDate = DateTime.SpecifyKind(DateTime.Parse(criteriaModel.FromDate), DateTimeKind.Utc);

var clause = filterBuilder.Gte(f => f.FlightDate, fromDate);clauses.Add(clause);

}if (criteriaModel.ToDate != null){

var toDate = DateTime.SpecifyKind(DateTime.Parse(criteriaModel.ToDate), DateTimeKind.Utc);

var clause = filterBuilder.Lte(f => f.FlightDate, toDate);clauses.Add(clause);

}// code for 3 more clauses (see next slide)return clauses;

}

Page 48: Introduction to the New Asynchronous API in the .NET Driver

Creating the clauses (continued)

private List<FilterDefinition<Flight>> CreateClauses(SearchCriteriaModel criteriaModel,FilterDefinitionBuilder<Flight> filterBuilder)

{// ... (continued from previous slide)

if (criteriaModel.AirlineId != null){

var clause = filterBuilder.Eq(f => f.AirlineId, criteriaModel.AirlineId.Value);clauses.Add(clause);

}if (criteriaModel.OriginId != null){

var clause = filterBuilder.Eq(f => f.OriginAirportId, criteriaModel.OriginId.Value);clauses.Add(clause);

}if (criteriaModel.DestinationId != null){

var clause = filterBuilder.Eq(f => f.DestinationAirportId, criteriaModel.DestinationId.Value);

clauses.Add(clause);}return clauses;

}

Page 49: Introduction to the New Asynchronous API in the .NET Driver

The SearchResult view

@model WebApplication.Models.SearchResultViewModel

@{

Layout = null;

}

<!DOCTYPE html>

<html>

<head>

<meta name="viewport" content="width=device-width" />

<title>SearchView</title>

</head>

<body>

<div>

Search Results:

</div>

<div>

@Model.TotalNumberOfFlights total number of flights

</div>

<div>

@Model.TotalNumberOfDelayedFlights total number of delayed flights

</div>

<div>

@Model.AverageDelayInMinutes average delay (in minutes)

</div>

<div>

@Html.ActionLink("New search", "Index")

</div>

</body>

</html>

Page 50: Introduction to the New Asynchronous API in the .NET Driver

Advanced Topics

• IAsyncCursor

• Cancellation

• Timeouts using CancellationToken

• ConfigureAwait(false)

Page 51: Introduction to the New Asynchronous API in the .NET Driver

IAsyncCursor

public interface IAsyncCursor<out TDocument> : IDisposable

{

IEnumerable<TDocument> Current { get; }

Task<bool> MoveNextAsync();

}

using (var cursor = await collection.FindAsync(filter))

{

while (await cursor.MoveNextAsync())

{

var batch = cursor.Current;

foreach (var document in batch)

{

// process document

}

}

}

Page 52: Introduction to the New Asynchronous API in the .NET Driver

IAsyncCursor

public interface IAsyncCursor<out TDocument> : IDisposable

{

IEnumerable<TDocument> Current { get; }

Task<bool> MoveNextAsync();

}

using (var cursor = await collection.FindAsync(filter))

{

while (await cursor.MoveNextAsync())

{

var batch = cursor.Current;

foreach (var document in batch)

{

// process document

}

}

}

Page 53: Introduction to the New Asynchronous API in the .NET Driver

Cancellation

using (var cancellationTokenSource = new CancellationTokenSource())

{

var cancellationToken = cancellationTokenSource.Token;

var task = SomeMethodAsync(cancellationToken);

// ...

cancellationTokenSource.Cancel(); // request cancellation

var result = await task;

}

Page 54: Introduction to the New Asynchronous API in the .NET Driver

Cancellation

using (var cancellationTokenSource = new CancellationTokenSource())

{

var cancellationToken = cancellationTokenSource.Token;

var task = SomeMethodAsync(cancellationToken);

// ...

cancellationTokenSource.Cancel(); // request cancellation

var result = await task;

}

Page 55: Introduction to the New Asynchronous API in the .NET Driver

Cancellation

using (var cancellationTokenSource = new CancellationTokenSource())

{

var cancellationToken = cancellationTokenSource.Token;

var task = SomeMethodAsync(cancellationToken);

// ...

cancellationTokenSource.Cancel(); // request cancellation

var result = await task;

}

Page 56: Introduction to the New Asynchronous API in the .NET Driver

Timeouts using CancellationToken

using (var timeoutSource = new CancellationTokenSource(timeout))

{

var cancellationToken = timeoutSource.Token;

var filter = ...;

var cursor = await collection.FindAsync(filter, cancellationToken);

}

// or: search the Web for “WithTimeout” helper method

var cursor = await collection.FindAsync(filter).WithTimeout(timeout);

Page 57: Introduction to the New Asynchronous API in the .NET Driver

Timeouts using CancellationToken

using (var timeoutSource = new CancellationTokenSource(timeout))

{

var cancellationToken = timeoutSource.Token;

var filter = ...;

var cursor = await collection.FindAsync(filter, cancellationToken);

}

// or: search the Web for “WithTimeout” helper method

var cursor = await collection.FindAsync(filter).WithTimeout(timeout);

Page 58: Introduction to the New Asynchronous API in the .NET Driver

ConfigureAwait(false)

Which thread runs the code after an await?

Depends on the captured SynchronizationContext.

We use ConfigureAwait(false) 100% of the time inside the

driver.

Improves performance. Helps prevent deadlocks.

Page 59: Introduction to the New Asynchronous API in the .NET Driver

.NET Users Birds of a Feather

Tuesday 12:20 pm to 1:50 pm

Metropolitan East Ballroom

Page 60: Introduction to the New Asynchronous API in the .NET Driver

Conclusion

Thanks for coming!

Questions?