Build an ASP.NET app with the Mongo C# Driver

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
-Hello and welcome to this talk on Building an ASP.NET Application with MongoDB. My name is Caleb Thompson and then I'm a Developer Educator here at MongoDB. In this talk today, I'm going to show you how we can access data in a MongoDB store with an ASP.NET application using the C# driver. The first thing we'll do is we'll set up an Atlas account and install some sample data. Atlas is MongoDB in the cloud and it’s a free and very convenient way to get up and running quickly without having to install MongoDB locally. We'll do that first and then we will switch over to Visual Studio. We'll create a new ASP.NET app. We'll look at the default code that's in there. Then we'll switch back to the slides and spend a little bit time looking at how you can use the driver to access the data that's sitting in Atlas. We have a bunch of choices now, we do that. We'll look at building what they called mapping classes to access the data easily and then we'll do some reading and updating of the data from the application. The first thing we want to do is set up an account in Atlas. We'll create a new shared cluster which is free. In that cluster, we will then import some sample data that we will use with our application. What is Atlas? Well, Atlas is MongoDB running in the cloud. It allows us to easily have a MongoDB instance running without having to worry about any server maintenance and that can save us a lot of time. You can choose to run Atlas as we'll see in just a moment in one of the three cloud providers AWS, Azure, or Google Cloud. It is self-serving, elastic, scalable, global. We have enterprise-grade security, monitoring, managed backups. There's also a serverless platform which we won’t to look at in this talk. For a lot of reasons, Atlas is a great way to just get up and running with MongoDB very quickly. Of course, you can use a local installation of MongoDB if you already have one running for this talk, but I'm going to show you how to do it with Atlas. Let's go ahead and take a look at Atlas. I'm going to switch to my browser here. If you don't yet have an Atlas account, go to cloud.mongodb.com and create a new account. It's free. Once you're in, you’ll have the option to build a new cluster. We're going to do that. I'm going to choose this left-hand column. You'll notice the word free here. For our purposes, a free shared cluster is just fine. Create a cluster. As you'll see, you can choose what cloud you want your data to be stored in, AWS, Google Cloud Platform or Azure. I'll just stay with AWS for now. I'm on the West Coast so I'm going to pick Oregon, not that it really matters. You can see I haven't changed anything that would charge, so it's still free. If you want, you can change your cluster name here. I'm just going to keep it at Cluster0 for now. I'm going to click create cluster. Now, this process takes one to three minutes so I'm going to pause while that catches up. There we go. We now have a new cluster named Cluster0 that's been created for us. We have three buttons, connect, metrics, collections. Under the fourth one, we have some other options that we're going to take a look at in just a minute. Let's click on the connect button first. You'll notice when we open this dialog, it says, "You can't connect yet. Set up your firewall access and user security permissions below." By default, our Atlas service is turned off or rather it's turned on, but nobody can actually get to the data. The first thing we need to do is whitelist the IP address or addresses for the machines that are going to access the data. You can easily do this just by clicking the add your current IP address. In secure way to do this also is add a different IP address and you can enter the site or address 0.0.0.0/0 which means every computer can access the data or at least theoretically can. I'm just going to add my current IP address and click on add address. Now, the second thing we need to do is create a MongoDB user. Let's do live2020 is the user and live2020pass as the password. I'll make sure I typed that correctly. Yes. Then click on create MongoDB user. Of course, if you're following along, you can create a username and password or whatever you want. Your IP address obviously is going to be different from mine. Click on create MongoDB user, I don’t want to save it. That's it for now. We're going to come back to this choose a connection method in a few minutes. Let's go ahead and close that. You'll notice now that Atlas is updating with our IP restriction and our new user it should be just a second. When that's done, we will import some sample data that we'll use for the rest of this talk. Okay, we have added our IP address to the whitelist. We've created a MongoDB user and with a password. Now, let's go into this ellipsis and we're going to choose load sample dataset. Now, obviously, if you're using your own data, you don't need to do this. This is really handy though if you're giving a talk or demo. It just says, "Are you sure you want to install this sample dataset?" We'll go ahead and load that. Now, we'll give another minute or so to import all of that data and then we'll explore it for just a minute. Okay, it is now loaded. Let's take a quick moment to explore what that might look like. Let's go to collections. We can see that a bunch of data has been installed for us. It looks like about one, two, three, four, five, six, seven collections, sample airbnb, sample analytics, et cetera. You can use any of this data for your projects. There's a good diversity here. In particular for this talk, I'm going to use under the sample geospatial collection. There is a database called shipwrecks. If we take a look at that, we can see that there are 11,095 shipwrecks in this collection with some fields like feature type, chart, latitude, longitude, water level. Might be some interesting stuff here. We're going to go ahead and use this for the rest of our talk. Now that we have a data store we can play with, let's go ahead and switch to Visual Studio and get to work on building an app. We're going to create a new ASP.NET Core Web App. We're going to use NuGet to import the MongoDB driver. We'll initialize the MongoDB client. We'll instantiate a database and collection object and then we'll read some data. Let's go ahead and switch over to Visual Studio, and we will choose to create a new project. We want to choose an ASP.NET Core Web App. Next. We'll keep the default name. Create. Let's choose, let's see here, a React.js app. We don't have to do any frontend work in this. I like React. It's handy so let's just go ahead and choose that for now. We'll keep it simple. We will create. It has now created a new app for us. Without doing anything else, let's go ahead and run it and just see what it looks like. Now, the first time you run it, you'll notice in the output console window there that it is restoring dependencies using npm. That's all necessary for the React frontend. Again, it's something we don't need to worry about in this talk. It takes a minute the first time you run the app and then after that, we shouldn't even notice it. I'll also note while we're waiting that I'm running this in Visual Studio 2019 Community Edition on a Windows box. Everything I'm doing though works just the same on a Mac in the MacOS with Community Edition 2019. Here is our default application. Nice. Hello, World page rendered in React. You'll notice that there is a link over in the upper-right corner called fetch data. What this does is it loads a React page that behind the scenes is calling our controller and fetching data. If we look at the developer console on this, make that a little bigger and we fresh the page, you'll see that it is calling a get call here to our localhost/weather forecast, which is the name of our controller. I'm going to go ahead and copy and paste that. What I’m doing here is I’m just bypassing the front-end the stuff that makes it look pretty and you can see that the controller is currently returning an array of JSON objects or a collection rather that have a day, the temperature, and a summary. If we go back and look at our code, let's go ahead and stop this. We go to our weather forecast controller right here. You can see that when we call the GET method which is what's happening behind the scenes, we are returning a random selection of these summaries up here as well as generating some random temperature ranges. Interesting but not all that useful because it's all fake data. Obviously, what we want to do here is use our sample data in MongoDB. Let's look at how we do that. I'm going to clean up a little bit here. I'm going to get rid of this static summary array of strings. I will leave the logger for now. In the get, I'm just going to get rid of all of the code for a moment. None of that is useful to us other than showing us that it works. I'm just going to add a return null for the moment. What we need to do now is add the MongoDB Driver to our project so we can actually access some data. There are several ways you can get to this. We're going to use NuGet. I like to right-click on the dependencies and choose manage NuGet packages. If you're using Visual Studio on the Mac your UI will look a little different but the idea is the same, you want to find manage NuGet packages. Look over there and you need to switch to the browse tab and we're going to type in MongoDB. A surprising number of results come back. The one we're interested in is in my case, the second one, MongoDB.driver. I'm going to choose that. Make sure it says, “Latest stable version,” and install. It'll ask us to accept the license and of course, we will. That's it, we can switch back to the installed tab and see that it has indeed been installed. We can also see it here under dependencies in case you really want to believe it. Under packages, there it is. Let's switch back to our controller and what we need to do now is create a Mongo client which will define how we connect to our datastore whether it's local or in Atlas or wherever. If our client equals new Mongo client and it's not going to recognize Mongo client until we use the namespace MongoDB.driver and there it is. Now, when you set up a client, you have to pass in the connection string, the URI to where wherever your datastore is, whether it's local or an Atlas. It's not something I have in the top of my head but fortunately, we can go back to our Atlas page and go to our clusters right here. You'll remember this connect button from a few minutes ago where we set up the IP whitelist and our database user. This time when I connect on it, I'm going to choose the second option down, connect your application. Make sure you select under the driver the C# .NET driver and the latest version. Then you'll notice right here the connection string has already been generated for us. I'm just going to click copy, switch back to Visual Studio and paste it right in there. Now, you'll notice that in the connection string, our username has been added but not the password for security reasons. Let's type that in live2020pass. Now, we have a Mongo client. This is pointing to our Atlas store. What we now need to do is tell our application which database and collection we actually want to use, what data do we want to get. I'm going to switch back to Atlas again for a moment. I'm going to close that screen and go to collections again. We decided we're going to use the sample geospatial database with the shipwrecks collection. sample_geospatial. Here I can do var database=client.GetDatabase. In there again we put in a string, sample_geospatial, like so. Then from that database object we can create a collection. var collection=database.getCollection and it is called shipwrecks. Now, you'll notice that we've got an error here in the IEE. getCollection expects us to tell it what type of data we're going to be getting and we don't know yet. If we look at our shipwrecks data here in Atlas as we did a few minutes ago, it's just data. It's a bunch of JSON documents we're going to get back. We're going to need to do something here to translate this JSON to something in C# that makes sense to us. If we don't want to, if you don't know what's going on you just want to have a quick and down and dirty way to get the data, you can always pass in BSON document object type. This is generic, it always fills in automatically. This is a generic class that defines any JSON object. You have to import the MongoDB.BSON namespace. That will work, but it might not be very useful for us. We now have a client, object it is pointing to our Atlas cluster. Within that cluster we're telling the driver that we want to use the sample geospatial database. Within that database, we're specifically looking at the shipwrecks collection. With that information, we can then do something like collection.find and get out the data we want. We can specify what we want. Before we go any further though, I'm going to switch back to the slides so we can look at several different ways we can access the actual data using the driver. There are four ways we'll look at and then we'll switch back to our code and make it happen. Let's spend a minute talking about how we actually access data in MongoDB from the driver. There are four main approaches we can take and here they are. You can use the MongoDB query language MQL. You can use the BSON document object. The driver provides these things called builders and we'll take a look at those. Then finally the most robust way to do it is to build mapping classes and use the link. Hopefully, you'll see why a little bit of time spent upfront using mapping classes will save you a lot of time later on. Well, let's go ahead and take a look at the four ways because these are all valid approaches you can use depending on your needs. We're going to assume for a minute here that we have a collection somewhere in MongoDB of guitars. Each guitar has four properties, an ID, make, model, and price. We're going to use this, we're going to pretend we're going to query for all guitars over $400 and we'll look at those four different approaches to doing just that. This is what the collection would look like in MongoDB. We've got in this example four JSON documents, each one has the same four properties _ID, make which is a string, model is a string, price is a double. Simple data here. If you're familiar with the Mongo query language, you can continue to use that by simply passing a string that contains valid MQL into your find or any of the other CRUD methods we've got. In this case, we're creating a string property called filter. It contains a valid MQL statement which is saying, “I want all of the documents where the price is greater than 400,” and we're passing that in and we will indeed get back what we expect. Now, if you've got something you want to do very quickly and you're familiar with MQL and you're good at typing, this is a perfectly valid way to do it. It is not however at all type-safe. If you typed price wrong or if price were capitalized in the database or something like that, it's not going to work. You won't know it won't work, you just won't get the data you expect. Your users won't get the data they expect. Works, but not great. Now, you can also use a BSON document object with the driver. What this does is it provides a little more structure around your MQL, but not a whole lot. As you can see in the bolded line here we're creating a new BSON document. We're saying the field we want to query on is price and the value is another BSON document, which is greater than $400. It does exactly the same thing as this previous slide right here, but it's wrapping it in a BSON document. It provides a little bit of type safety, but again, not very much. Now, if we had a slightly more complex query, very slightly, like we want to get all the guitars between $400 and $600 in MQL, you can see the line up here, you create an and, $and and specify a price greater than $400 and a price less than $600. Converted to the BSON document. Now we have to create a BSON array for those various properties. It gets a little bit longer and you can see that if you had a complex query using the BSON document approach really can lead to some pretty long wordy code verbose which is one of the reasons why the driver provides this builders class. Now, a builders class, you specify the type of document you want to build. You say you want to build in this example a find filter called filter and you can see that the builder now has some properties like GT for greater than. You can pass in an ampersand for and. It also has an LT for less than, so that same query of all guitars, more than $400 but less than $600 can be handled in a more graceful way. You don't have to remember to do $GT or any of the other MQL specifics to get this to work. It's also a lot shorter than using a BSON document. This is definitely better. Still not my preferred approach. My preferred approach is much more .NET friendly and that is using mapping classes. A mapping class is just a C# class that defines the properties that we expect in the data and that we care about and that we want to use. We can name them whatever we want and then we can tell the driver how to map those to the actual data in the data store. As you can see here, we have a class called a guitar. It has four properties in ID, MAKE, MODEL, and PRICE. They're all capitalized in this case because that's how we generally define properties in C#. Here's a side-by-side comparison of the mapping class on the right and the actual guitar object as it's stored in MongoDB. Now, by convention a public property named with a lowercase id, or _id is always used as the identifier. You can specify a different field if you want by using the BSON _id attribute. We'll look at attributes in the next slide, but you can see that otherwise this will work. We haven't told the driver anything about how to map these, but because they have the same names other than the initial capitalization, the driver is smart enough to say, “You're looking for something called Make with a capital M. Here's a make in the data store with a lower M. I'm going to assume they're the same.” Now, assumptions can be dangerous. So the driver also provides attributes that we can use to make things very explicit. The BSON _id attribute says even though I've named this property guitar _id, it is the _id for the document and so it's going to be mapped to the _id in the data store. Likewise, I don't really like the names MAKE, MODEL, and PRICE. I want them to be more user friendly. I'm going to call the manufacturer, model name, and price in dollars. For each of these I'm going to use the BSON element attribute, passing in the name of the element as it exists in the data store. Now, we have a C# class called guitar, it has property names that we like and we want to use and we're telling the driver explicitly how to deserialize and serialize between this and MongoDB and the fields that are there. Now, that we have a mapping class, we can use a link. Now, a link is the query language within .NET framework that allows us to do structured querying against any number of different kinds of data stores. Of course, the driver implemented it to work with MongoDB. In this case, we have expensive guitars variable reassigning, which is the guitars collection where the guitar.price is greater than 400 and we're going to return that as a list. Very straightforward link statement right here and you'll notice that we have 100% type-safety. We can't do G.Price with a lowercase P or misspell it, P-R-C-E, something like that. The compiler will yell at us. Actually the _id will yell out us before we even compile. Using a mapping class and then using a link provides us with a great type of security. Makes it really easy to write complex statements using a link which most of us are probably familiar with at this point. If you're not, it's time to be. Here's a more complete example where we have the collection you saw a minute ago in Visual Studio, we Nu-ed up a collection and we can now call on that collection the find method passing in the link statement, specifying how we want to filter, what we actually want to find, and then we're returning it as a list. Now that we have all of that, let's go back to our app and do some refinement and see if we can actually display data from MongoDB in our what is currently a weather data app, but we're going to use the shipwrecks. Here we are back in Visual Studio, back in our controller and we've got our client, our database, our collection. Right now the collection is saying it's of type BSON document, but that's not very helpful to us. We now know we want to create a mapping class. Let's go ahead and do that. I’m going to right-click and choose add class and we'll call it shipwreck. You can call it whatever you like, but obviously a name that is sensible is always good. Now, I'm going to go look at our data in shipwreck again for just a moment here. I’m going to clean that up and shipwrecks. It looks like we have an _id and a whole bunch of fields, some of them strings, some of them doubles that may or may not be useful. Let's start with _id feature type chart. We have public object _id and it's called _id and we'll put a getter setter on that. It doesn't seem to recognize this object _id. We need to import MongoDB.Bson. Then we have a public string feature type, getter setter. We have a public stream chart. What else? Now, this latdec and longdec are doubles or decimal values of the latitude and longitude. Now, it seems really important if you're doing some app that's showing where shipwrecks are. Let's go ahead and include those too. Public double latitude. You'll notice that I'm not using the names that are in MongoDB because latdec and longdec mean nothing to me. I'm using something that makes a lot more sense. If you don't know about latitude and longitude, don't worry, that's just a way describing where something is on a map or on the planet actually. Now, notice that I didn't use the same names so we need to go back and we need to do some BsonElement, attribute element and we pass in the name of the element as it appears in MongoDB, so that was called FeatureType. I'm going to go back and double-check these and again we need to add a reference here to BSON serialization. Okay, let's make sure we get the names feature _type chart, latdec, longdec. Let's go ahead and copy and paste a little bit. We don't need to add one for chart interestingly, I'm doing it anyway for the sake of being thorough, but again, the driver is smart enough to recognize that the only difference is the capitalization. Now, this was latdec and longdec. I'm going to just double-check those, latdec, longdec. We can specify here that this is the BSON _id. Now, there are also a whole bunch of fields in the database that for the time being, at least we don't care about, okay, I don't know what this GP quality is. Depth might be interesting, but for now we want to ignore a bunch of stuff and there are two ways we can do that. We can create a public property of type object, an array of objects called whatever you want. The bucket I call it, once you get them set. If we put-- It would help if I could type. If we put on this bucket a BSON or an attribute called BsonExtraElements. Anything that the driver finds when it's serializing or de-serializing that it doesn't recognize as one of the properties we have already specified, it will throw it into this object array as a key-value pair. That's one way to do it. The problem with that is you end up with an array of key-value pairs that you still don't really care about so you're getting back more data than you need and somewhere on the front end, you're going to have to deal with that. Another option is to get rid of that and on the class itself add a BSON ignore extra elements tag. That just tells the driver to throw away anything you don't recognize. We don't care about it, for now, very handy and that's it. Now, we have a shipwreck mapping class with names that we like, that means something a little more useful than what's in Mongo. Let's go back to our controller and here we're going to change our get collection from a type of BSON document to a type of shipwreck because we now can do that. Then let's do a find and see what happens here. Let’s do--We want to return the collection.find we'll add some link here. Let's see, let's find shipwrecks where the feature type is wrecks visible. The first one that in that I see here. S.feature type equals wrecks visible. It's yelling at us because we're supposed to be returning an innumerable, so let's do a Tolist. Now, we're asking it to return an innumerable of a type called weather forecast, and that's no longer valid, so we'll change that to shipwreck and we'll get rid of this return null line it's no longer needed and that should do it. Let's see if we did it right. Build the app. We'll open up our console again, we'll go to fetch data. Again, I'm going to go ahead and bypass the front end altogether and just go straight to the API call and call it the controller. Look at that, we have a page now returning a whole bunch of JSON objects. They have an _id, feature type, which again, we specified wrecks visible. If we go through this entire list of hundreds of them, they should all have wrecks visible. Indeed they do. I guess two, isn't proof, but there it is and we got our latitude and longitude back. That's how we connect our driver to the MongoDB store. Now, this is great. We've got it working just like we want it to, but there's a little bit of a problem here. That problem is that within the method of the controller, within the GET method, we're creating a new Mongo client every time, a new database object, a new collection every time and if you're following MVC patterns, this probably smells a little to you and that's because we don't need to do this every time. This controller, which is still named our weather forecast controller, but our shipwreck controller probably is always going to be using the same collection shipwrecks. There's no point in having all of this code in every method of the controller. In fact, we may have multiple controllers in our project that are looking at different collections within the sample geospatial database, or maybe they're even still using the same collection. There's gotta be a way we can clean this up a little bit more and I want to take a quick look at that because this is not a best practice the way I've got it right now. In ASP.NET applications, there is a Startup.cs file right here. This is where we do all of our initialization code. It seems logical that we would initialize our Mongo client here and then have the ASP.NET framework, inject that client into our controller where we can then use it. Let's go back to our controller for a minute. What I'm saying is we want to inject this client. We don't want it here anymore. I'm going to get rid of this on this constructor right now, it's expecting an ILogger object. I'm going to get rid of that and what I really want to have come in here is a Mongo client. We'll just name a client for now, and I'm going to get rid of this property, this private locker. Instead, I'm going to do a private IMongo. Now, let's assume and I think this is a safe assumption that every method we want to do in this controller is always going to be using these shipwrecks collection. It is after all the shipwreck controller. Let's do an IMongo collection and we'll name it, shipwreck collection. You can name it, whatever you'd like Shipwreckcollection and it's better if you spell things correctly. What we're going to want to do is set here the code that when we get the client in, we create the collections. Let's take this code out of our method. These two lines, I'm going to cut those, put them in our constructor, change this now to shipwreckcollection as such. Now, when this controller is initialized by the framework, we need it to pass in an IMongo client object. We will use that client to get the database. We will use the database to Nu-up the collection, and then down here, we get rid of the client line down here, and in the method we just change collection to shipwreckcollection. Now, it's yelling at something here. We haven't specified the type. It is of type shipwreck. In our startup.cs in the configure services method, we want to create a new Mongo client that will get injected. Let's do services.addsingleton, specify the type of Mongo client. We want a Mongo client out of this deal, and let's see here, we'll use a little bit of link. What do we want to do? We want to return a new Mongo client like so. Here we would pass in that same URI that we had in our controller to go back to our controller. Do we still have it? No, I deleted it. That's okay. That's one way to do it. A slightly better way to do it is ASP.NET projects come with an appsettings.Json file. This is a convenient place to store configuration information, for example, a MongoURI. You can create a new property and you can set it to whatever you want. Let's go back to our Atlas and we'll go to our cluster. Go to connect. Connect your application. Now, if I hadn't have deleted it already out of my project, I would just copy it from there. We'll copy that string one more time. Paste it in here. Again, we need to put in the password live2020pass. Make sure that's all saved correctly. Now, that we have that, go back to our start up again and what we want to pass in here is some URI and that URI. We want to do s.GetRequiredService. Is of Type IConfiguration and we want to specifically ask for the MongoURI property we just created. We got the variable there. That should do it. I'm going to double-check that I got MongoURI that matches the property name here, MongoURI. Now, we're saying, “Within the configuration service, get the MongoURI property, set it to this string variable. Then Nu-up a Mongo client passing in that connection string. At this point now, we should have automatic injection of this client into our controller. We'll then create the database. We will assign the shipwrecks collection to the shipwreck collection global. In our get method now, we should see exactly the same data. Let's fire it up and see if did it right. There is our page. We'll go to fetch data and we'll go directly to the backend and sure enough we're still getting the data we expected. Except now, we're not doing it within the controller method itself and we can reuse this shipwreck collection throughout the controller for all of our different methods. Much cleaner, much better practice. With that, let's switch back to the slides. In this talk, I showed you how to set up a new Atlas account and a new cluster within that. We imported some sample data that we used for our app. We then switched to Visual Studio, created a new ASP.NET app. From there, I showed you how to import the MongoDB driver using NuGet. Once we had the driver installed, we initialized a new Mongo client passing in the URI to our Atlas data store. We created then a database and collection object off of that client. We then switched and talked about how to access the data and all of the different choices. While all of them are valid choices, it's generally a very good idea to create mapping classes for the objects that are stored within MongoDB. We did that. We created a shipwreck mapping class. Then finally, we did a find specifying a particular subset of the data that we wanted to get. We then did a little bit more refinement of the app moving the creation of the Mongo client out to the startup file and adding the URI to the appsettings.json file. With that, I would like to thank you very much for joining me today in this talk. I'd also like to give a quick shoutout to a new course we released just this spring called M220N. It's the .NET version of 220. It's a five-week course where we dive into using the .NET Driver in much greater detail. You get the opportunity to work on a website called MFlix which is a movie database. We walk you through a lot more things that you can do with the driver including some fairly complex work with the aggregation pipeline. I encourage you to check that out. It's university.mongodb.com and just search for M220N. Thank you very much for attending this talk. I hope you enjoyed it. I hope you learned a lot and I look forward to your questions.
Info
Channel: MongoDB
Views: 31,576
Rating: undefined out of 5
Keywords: free cloud database, mongodb on aws, engineer, software, serverless, virtual event, mongodb, technology, conference, software engineer, data, cloud database, engineering, stem, dbaas, mongodb on azure, MDB, mongodb atlas, mongodb.live, developer, nosql, code, tech, database, database as a service, coding, MongoDB cloud, cloud, mongodb on google cloud
Id: gM4m5LizxL8
Channel Id: undefined
Length: 44min 9sec (2649 seconds)
Published: Wed Jun 10 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.