introduction to the new asynchronous api in the .net driver
TRANSCRIPT
![Page 1: Introduction to the New Asynchronous API in the .NET Driver](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/1.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/2.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/3.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/4.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/5.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/6.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/7.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/8.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/9.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/10.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/11.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/12.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/13.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/14.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/15.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/16.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/17.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/18.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/19.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/20.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/21.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/22.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/23.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/24.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/25.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/26.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/27.jpg)
Sample Web Application
• Two pages
• Search criteria form
• Search results
![Page 28: Introduction to the New Asynchronous API in the .NET Driver](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/28.jpg)
Search Criteria Form
![Page 29: Introduction to the New Asynchronous API in the .NET Driver](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/29.jpg)
Search Results Page
![Page 30: Introduction to the New Asynchronous API in the .NET Driver](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/30.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/31.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/32.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/33.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/34.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/35.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/36.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/37.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/38.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/39.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/40.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/41.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/42.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/43.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/44.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/45.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/46.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/47.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/48.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/49.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/50.jpg)
Advanced Topics
• IAsyncCursor
• Cancellation
• Timeouts using CancellationToken
• ConfigureAwait(false)
![Page 51: Introduction to the New Asynchronous API in the .NET Driver](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/51.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/52.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/53.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/54.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/55.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/56.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/57.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/58.jpg)
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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/59.jpg)
.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](https://reader034.vdocuments.net/reader034/viewer/2022042602/55c9a784bb61ebf51b8b45b6/html5/thumbnails/60.jpg)
Conclusion
Thanks for coming!
Questions?