Introduction to the New Asynchronous API in the .NET Driver

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

Transcript of Introduction to the New Asynchronous API in the .NET Driver

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?