Watch videos with subtitles in your language, upload your videos, create your own subtitles! Click here to learn more on "how to Dotsub"

What is ASP.NET MVC? 80 minute technical video for developers, building NerdDinner

0 (0 Likes / 0 Dislikes)
  • Embed Video

  • Embed normal player Copy to Clipboard
  • Embed a smaller player Copy to Clipboard
  • Advanced Embedding Options
  • Embed Video With Transcription

  • Embed with transcription beside video Copy to Clipboard
  • Embed with transcription below video Copy to Clipboard
  • Embed transcript

  • Embed transcript in:
    Copy to Clipboard
  • Invite a user to Dotsub
[Microsoft ASP.NET] [www.ASP.NET] [ASP.NET MVC: What] [Deep Dive: Building Nerddinner.com] Hi, this is Rob Connor. In this screen cast I will be building Nerddinner.com using ASP.NET MVC. The screen cast will be a little bit over an hour, so there's a lot to show. Let's jump right into it. [What's a Nerd Dinner?] This is the Nerddinner.com website, and it is going to be the site that I will build today, and if you take a look at it, it's pretty basic. There's not that much information that is required to go in here. We have the concept of a dinner. Each dinner can have an RSVP, 1 or more. This main page right here is also pretty simplistic. We just have a map, some nice JavaScript interactions and so on. If I click on a dinner, you can see that the information that goes into a dinner is, again, fairly basic. The organizer, description, where, when, so on like that. We also have a list of who is coming, which is pretty groovy, and then finally, some flare, the add this to your calendar, and again, this nice map. That's pretty much it. The focus of the site is really just getting geeks together to eat. It's more or less an event management system, and if you're hungry, and you're a geek, and you want to meet other geeks, well, this site is for you, and it's what we'll be building today. [Getting Set Up] First let's start with the tools that we're going to need here today, and the first one is Visual Studio. If you already have it, well, then you're good to go. If you don't and you want to try this out for a little while, I would recommend heading over to Microsoft.com/express/vwd and grab yourself a free copy of Visual Web Developer 2008. This is free. It's not a trial edition. It's always good, and you can always use it, and it works great with ASP.NET MVC. The next thing we're going to need to do is we're going to need to download ASP.NET MVC, and if you come over here to ASP.NET/MVC you can hit the Download page, and you can download it from here. If you want to shortcut all of this and not have to worry about it, what I'd recommend is you use the Web Platform Installer. If you click on this link, it will head you over to Microsoft.com/web. You'll install this really cool installer, and when it comes up, it will give you a choice of all the things that you'll need. I've opened it up here, and it is querying the Microsoft.com/webservers to find out what's cool and what's interesting to install. Now, I already have ASP.NET MVC installed on my machine, but if you didn't, you would see some cool stuff here on the front page of things that you might be interested in. Where you want to go to do this all in one fell swoop, you can get MVC and Visual Studio all set up for you, is you want to click on the Web Platform tab, and then you want to click over here to Frameworks and Runtimes. Make sure you check "ASP.NET MVC 1.0." Now, you don't need to check this off, because that will be installed with Visual Studio. Next up, if we head back to Web Platform, come down to Tools, and you can click right here, Visual Web Developer with SP1. And you're good to go, and this will run for about 20 minutes or so as it installs everything. While it's doing that, you can come through here, and you can check out all the cool things you can add in the Web PI, Platform Installer. And there's lots of websites and cool things you can have it install for you. It downloads them, configures them, good to go. Well, let's get moving here. We've got all our tools, and we're off and running. [File|New] I've got everything installed that I'm going to need now to start working with ASP.NET MVC. I've installed Visual Studio, SQL Server Express, and the ASP.NET MVC project templates. Now I'm ready to create the Nerddinner site. I can go to File, New, and select the project using my mouse and the menu, or I could be a good ninja and hit Control, Shift, N, which brings up the new project dialog. And here I've selected web, ASP.NET MVC Web Application. And so what I'm going to do is type in Nerddinner here, and that's going to name my project Nerddinner, and when I hit OK, up pops another dialog here. You can see "Do you want to create a unit test project?" Testing is sort of a first-class citizen with ASP.NET MVC, so that is why this dialog is here. It's expected that you'll probably want to test what you're doing, and so you have a choice. You can use the Visual Studio Unit Test framework here, or if you have another framework installed, like xUnit, NUnit, MbUnit, whatnot, and you've hooked an individual studio, those might show up right there as well. For right now we're going to choose Visual Studio Unit Test. Hit OK. For those of you using Visual Web Developer out there this will work as well, which is exciting. We hit OK, and down pops our new projects. I'm going to talk about the test project later, but what I want to do right now is quickly go through the new Nerddinner project and what it is and what you get, so first and foremost, let's run this thing and see how it looks. Yes, I'll modify the web config, and up pops the website here. It pops up in the browser. There we go. You get a nice application that comes and runs straight out of the box, and this is the home page, and we have an About page as well that you can talk about the site. And we even have membership ready to go. We can even register if we want, and this all works, which is exciting. And so how does this all hang together? Well, this is a web application project, so at its core, it is an ASP.NET site, and it's one of the things that we talk about all the time. ASP.NET is greater than MVC or Web Forms. It is an underlying framework that MVC is based on, so a lot of the stuff that you are familiar with already if you're an ASP.NET programmer is still here. We have these things called controllers inside the Controllers directory right here. We have these things called Views. These are sort of immoveable. You don't want to change these. This is convention based, and the underpinnings of MVC expect these to be here, and so inside the Controllers directory are the default controllers that you get with ASP.NET MVC, the Home Controller, which we were just looking at, as well as the Account Controller. So what is a controller? A controller is essentially the thing that directs the application flow. When a user requests a page, that request comes through the controller. When a user responds and enters data into a form, for instance, that post is posted to a controller. The controller handles the flow. Views down here are solely responsible for displaying information to the user. The controller will hand some data to the view. The view will then display it, and I'm going to go into this in detail in just a bit. I want to show you the rest of what you get here, and you get some nice JavaScript that we ship out of the box. You notice it's jQuery, which is pretty groovy, and also Microsoft Ajax that we use for the Ajax requests that are built into the HTML helpers, and I'll talk about that in a little bit. We have a directory up here for static content, like CSS and images and so forth. This is for convenience, and the Models folder here is also for convenience. You don't necessarily need to use this directory for putting your models into. It's there by convention. That's about it. Let's get started with building out our site. [Creating the Model] The next step here is to build out my model, and what I'm going to do today is I'm using LINQ to SQL for the data access, and I'd like to flex LINQ to SQL's code generation. I know that a lot of people have a different approach to the way they build out their model. This is a data-centric approach, and it is somewhat simplistic, and since the site is simplistic, I'm going to go ahead and flex that. Well, to get started what I'm going to do is right click on my App Data folder, and I'm going to go and add a database, and you say "Add new item." And it notes it's talking to the App Data folder, which is exciting, so I'm going to choose a SQL Server database, and I'm going to call this "Nerddinner." And it gets added in, and when the database gets added in, this is an actual SQL Server database, which is groovy, but it's file based, so if you're used to using something like SQLite, then this is sort of the same thing. It's located right here inside your project. It's not off on a server. Now, should you decide not to do something like this and you want to have it up on a server, it's pretty easy. You just have to change your connection string to your database and point it to a server. It's easy to do. That's inside the web config. I'll talk more about that later. When I add this in to the App Data folder if I choose the Server Explorer you'll notice now that I can work with that database right away in my Server Explorer right here, so if I right click, open this thing up, down pops all the different ways I can work with this thing. In fact, I can create tables right here if I like, or I can do it visually by working with the Database Diagrams. Then I can add a diagram, and right inside here I can add a table and when I do—we'll call it Table 1 for right now— you can see it pop up right here, and now what I can do is I can start adding tables. I can add relationships and so on. I'm going to do that right now. Here's my database. As I mentioned, the Nerddinner site is pretty simplistic. We have the notion of a dinner, we have the notion of RSVPs, and that's about it. And we also have the notion of users, as you know. RSVPs need to correspond to user names. We're going to let membership handle all the user stuff. We don't need to add any other information in that, so ASP.NET comes with a membership system that is sort of built in, so it's a framework that we don't necessarily need to expand on. Not right now, because we don't have a notion of a user that requires any more complexity. All right, we're good to go, and I'll pin this thing back open, and I'll head over to our solution frame, and now what I'm going to do is I'm going to add some code so we can access these tables, so what I'm going to do next is add a new item, and inside here I'm going to head down to Data, and I'm going to add LINQ to SQL. This is one of Microsoft's object relational mapper, or ORM, tool sets, and I'm going to simply call this Nerddinner, again, keeping my naming constant. And you can see some things are added to our project for us, which is great. And inside here we now have a new design surface to work on, and the way this works, it gives you a little hint down here, but it's pretty basic. You head over to the Server Explorer, drop open your tables, and I'm going to Shift, click on these things and drag them in. And there we are, so what this actually is right here, what happened here, is these are now classes that are generated now. Notice my table name was Dinners, but this is called Dinner. Same with RSVP. I'm going to go over to Properties here, and one thing I want to do is I want to rename this context. I want to call it something a little bit simpler than NerddinnerDataContext. It's a mouthful. I'll call it DB. And in the context name space, well, I'll call it Nerddinner. And then for the entities, these things right here, these guys, I'm going to call that name space Nerddinner.Model. Now the full name space of this object here is Nerddinner.Model.Dinner. Good stuff. Save it, and we have some code generated for us. That's groovy, and we are ready to go building controllers. My database is set up, and the core of my model is ready to go here, and I'm ready to start adding controllers and views. But before I do, I want to talk about an architectural approach that we're going to be using today building out Nerddinner, and that is a RESTful approach. Let's talk about that for a little bit. [A look at REST] As I'm building out the site here, I am keeping an eye on using a RESTful architecture, and I'm sure you've heard that term before. You probably heard it with respect to web services and maybe a debate about REST versus SOAP. REST is actually an architectural style. It's more of an approach to building a website, and believe it or not, you've used RESTful websites a lot. In fact, the entire Web can be thought of as being RESTful. We're not really going to get into that deep of a definition right now. If you'd like to know more, head over to Wikipedia or maybe hit a search engine. For right now in this high-level summary, I would say you could think of a URL as pointing to a resource. Now, in Web Forms, you can think of those resources as pages, and those pages process data. MVC can be a little bit broader than that. Those resources can sense the caller and what kind of data format they want, like JSON or XML. If it's a human, they probably want HTML. In addition, the resources act on HTTP verbs, like get, put, post and delete. Those are treated differently, and finally, you have a standard set of actions. In ASP.NET MVC, which you'll see in a little bit as I start working with ASP.NET MVC in my views and controllers, you'll see that the standard set of actions are index, details, edit and create. You can think of it this way. In an IS we don't have the verbs put and delete, so I'm only going to show get and post here. You can think of it like an interface. Every URL you have, say Dinners/Index, it has to implement both get and post. If you pass get to it, you'll get back a list of all dinners. Say you pass in post. Well, it might search Dinners. The same with Dinners/Details/1. A get would get a single dinner, read only. Post, that would customize the view in some way. You don't have to implement these things, but this is one way you could to have a RESTful interface. Again, Dinners/Edit/1, a get would get an editable dinner form. Post would update the dinner, and /Create, well, you get the idea. I can hear what a lot of people are thinking. "I want my own URL scheme. I don't want to have to have the default controller action ID." And that's okay. You can. Because remember, routing is the key to building out your URL scheme. It's always nice to leave a simplified default controller action index style of route in there, but you can definitely build out and customize on top of it. If you want to have something like mysite.com/Dinner/2009/Monkey, you certainly can. You can still go to the DinnerController index method, and you can still keep the default action in there. That's how I'm going to proceed today. [The Dinner Controller] What I'm going to do right now is I want to add my first controller, and since I'm working with Dinner so far, I'm going to add a Dinner Controller. I mentioned previously those methods, those standard methods, well, here they are: Create, Update, Details scenarios. Index is going to be in there because Index is the default action for any controller, so I'm going to say OK. Add this thing in, and let's take a look at what we got to our brand-new Dinner Controller. And you can see in here we have a bunch of methods. These are called actions, and they return this thing called an ActionResult. We'll talk more about why we return this, but for right now, just know that the engine that catches these calls right here expects this result, and you can think of it as your HTML holder. We have an index method. This is the default one. We have Details. This shows an individual one. You can see here by the URL. Same thing with the Creates, and you'll notice that we have an overload for Create. This is what I was mentioning previously. This one works with get. This one works with post. We delineate between these 2 methods by this attribute, and we do the same thing with Edit down here. Okay, this might look incredibly foreign to people, and that's okay. What I'd like to do now is to show you how this all hangs together. We have our controller, so let's go ahead and grab some data and throw it out onto a view. And to do this, I am going to pick up a new LINQ to SQL context. What I'm going to do is double click that, and all you have to do is pass it down that way. Just pass it as a parameter into the return statement, and you're good to go. Well, now how do I create a set of views for this? What I could do is come down here to my Views folder. Notice how these directories correspond to the names up here. One of the things you've got to know is that, again, MVC is based on convention here, and the names of the controllers are considered this prefix here, Account, Dinner, Home. It is expected that they end with Controller. But notice also down here that each of these things has a corresponding directory down below. Inside Account we have a bunch of different views for the account controller to use, and each one of these things corresponds to these actions. So with our Dinner Controller what we're going to need to do is we're going to need to have an index view created for us. Now, I could come in here, right click, create a directory called Dinner inside of it, put an index view, or I can rely on a tooling, and since I'm lazy, that's what I'm going to do. I'm going to hit Add View, and it knows since we're inside the index action that we are going to be using the index view name. The next thing that I want to do—and this is really cool— I want to create a strongly typed view. Now, my view data class, if I drop this open— oh, it didn't find it for me because I need to come up here and compile the application. I'll hit Build. There we go. I make that mistake all the time. And so we're going to come back down here again, view data class. There we are, Nerddinner.Model.Dinner. And we hit OK. Next up, the view content. This is important stuff, remember, we were talking about in terms of REST. Here we go again, Create, Details, Edit, Empty, List. The index view, we can have it be anything, the index action, the index view. We can have it show anything we want, but ideally, we should keep with convention. So let's just show a list of data, and the rest of it we can keep as it is. We hit Add, and the tooling adds in a directory for us. It adds in the index view for us. It adds in a page with a nice table that's going to show a list of all data, which is great. One of the cool things is since we're using LINQ to SQL the tooling is able to go in and figure out what our primary key is, DinnerID. It's able to work with the HTML helpers, this guy— I'll talk more about those in a bit— to build links for us and all that good stuff. This is good to go right here. In fact, if I hit Run, which I can hit F5, and the application comes up, and I'll come in here and type in Dinner, and here we go. This is our page. Now, we don't have any data in here. And what we can easily do is create that, and if I hit Create New, I will get the yellow screen of death, but that's okay. It's because I don't have a create view yet. Come back in here. I only have a single view. That's easy to do, and you probably have guessed already that I am going to use the tooling to create this for me. Add View. Yes, it's going to be called Create. Yes, I'm going to use Nerddinner.Model.Dinner, and this is going to use the Create content. That's pretty cool, huh? And so before I show you this page, there's 2 things I want to do. I want to remove the DinnerID, because this is the primary key. I certainly do not want to be adding that manually, because the database controls that for me. What I do want to do is I want to set up some data access code inside the postback to add the dinner into the database. I could go with the way the template has created this for me. However, what I think I want to do is I want to leverage something really groovy about ASP.NET MVC, and it's a thing called model binders. And what model binders simply do is they look at your model— in this case, my LINQ to SQL stuff, my classes, my dinner, RSVP and so on—and it tries to see if it can bind the request to your object, which is pretty groovy. I could take the form collection here, and the form collection is a bunch of name value pairs of information. I could use that if I wanted to, but I don't. I want it to do everything for me. I will come in here, hit control dot, add a using statement to the page, and so now what's going to happen is ASP.NET MVC is going to see that this action requires this argument, and it's going to say, well, let's see if I can create this object, and it will be able to. And now let's see if I can bind it, and it will also do that. So how do we know if it's bound correctly? What if there's a mistake? What if someone entered some bad information in the form? Will it still be bound? Will the whole thing explode? And the answer is no. It's very exciting. What we can do is we can test for this. We can ask ASP.NET how is that model state? Is it valid? If it's valid, we can go ahead and do our data input stuff. What I'm going to do is I'm going to move this try catch block up here, and we're good to go with that. What if it isn't valid? What are we going to do then? The good thing is that when the model binders try and bind some information and it fails, it will keep going, so it fails gracefully, as they say, and what's going to happen is the model state is going to capture those errors. What we're going to do is return the object partially bound down to the view, and that's going to happen on failure if our data access code doesn't work out right, and what we should also do is add it if it's not bound correct. Okay, now what we need to do is quite simply create a new data context. We need to add InsertOnSubmit(dinner). And then finally, probably submit the changes, and that's all we need to do, and now we have some nice data access, and so what's going to happen here is I'm going to run the application by hitting F5, and it's going to pop up, and I'm going to type in manually up here "dinner," and now I can hit Create New, and you can see now we have a nice form. What I'll do is add some information in here and show you how it gets added to the database. All right, I spared you from all my typing. Here's our create form, and we have some test information in here. Now when I hit Create, there we go. It's put in there. That's pretty easy stuff. Now if I hit Edit, of course, it's going to break, but let's take a look at something here. If I hit another Create New, and if I come in here and let's say I type in this information, which is always fun to see asd, asd, asd, there's 3 things that are going to go wrong here. Number 1, this is expecting a date. Asd is not a date. This is expecting a decimal, I believe, or a float, one of the two, and so is this. Actually, it's a double, so if I hit Create, this is failing gracefully, which is awesome. Notice if I come back in here into my controller, again, I didn't do anything to have this happen. All I've got is pure data access code in here, which I'm going to change in a little bit, by the way. But MVC helps us to fail gracefully, which is great, and so what we have here is an asterisk. It says, "Hey, there's errors. Go fix those." Well, if we want to do something a little bit more graceful, we can. Down here we have this thing called the HTML helper. This is hooked into the whole MVC runtime goodness, and I'll talk more about that a little bit later as we go and we work with the HTML stuff. But for right now, know that you can output this thing called a validation summary, and it outputs a message, as you can see right here. Down here, if we don't like the way the date looks, we can type in a better message, like "Incorrect Date" and so on. And so also let's fix up the latitude and longitude while we're here, and this should be something like 38.000, and we want to copy this as well and say this should be something like -152.999. Great, so now what we can do is we can allow this thing to fail gracefully. Now what I can do is head over to Dinner one more time. Great, and Create New, and I'll fill it full of asd again, and I'll stop right there when we hit that. That's pretty cool, so it's going to tell us a couple things, actually. A value is required. It caught that it was empty. That's pretty handy, but in here we also have an incorrect date. There's lots more that we can do with this, including using data annotations, which I'll show you in a little while. For right now let's continue on. Let's build out our edit form. There's a couple more things I want to show you in here. I'm going to pin this thing back open, head back over to the Dinner Controller, and let's create the edit form so we can edit the data, and this, once again, is as simple as coming in here and getting our dinner from the database. There we go, and we're going to return a single dinner down here. All right, I'm going to repeat this code down here, and yes, I will be fixing this in a little bit. Now, what I want to show you is I do want to do the same thing down here. I want to create the data access code at the same time I'm creating this edit view up here, because this is going to be the thing that handles the postback. Notice what I'm doing here. I have to pull the dinner out of the database. This is how I need to work with LINQ to SQL, because as I mentioned before, LINQ to SQL is going to keep track of all the changes to this object and then will make a transactional call to update those changes. What I need to do now is I need to do something a little bit different than I did with this postback up here, which accepted a dinner, because if that happens, what LINQ to SQL is going to do if I put dinner in here, what LINQ to SQL is going to do is it's going to create or it's going to instantiate a new dinner, and whenever I try and work with that dinner with a new data context I'm going to get an error. What I'm going to do instead is something that's super cool. I can use the model binders anyway. I can say, "Hey, update this model," and I'm going to pass in the dinner, and then I'm going to set this form collection that's passed in to a value provider. This is a little funky kind of wording, but a value provider is sort of an abstraction of a form collection. It could also be a query collection. It could be anything. Just think of it as a name value pairing of a dictionary, and you can see it's even based on IDictionary right here. I'm basically passing in the form collection here and saying bind it, which is kind of groovy if you think about it. It means you can use the update model with any sort of IDictionary. Okay, enough of that. And that's going to change our dinner for us, and then we need to simply submit the changes. Well, what happens if this thing fails? Again, we're going to pass this back down like that. And before we launch this thing, one last thing I want to do is I of course have to create the form. I'm going to hit Add View, Edit, again, Dinner, make sure I set Edit down here as my content, hit Add. Great, and this thing pops up. Again, I'm going to have to fix this right here, because I do not want to edit my dinner, and I will take out the validation thing. You might be wondering, "What is this model thing? "We haven't really talked about this, Rob. You're glancing over that," and that's true. Let's dive into this a little bit deeper. If we come back here to the top of the page, what we're working on here is a view page, and it's worth noting right now that you don't need to work with this exact view page. In fact, you can have your own view engine if you like to decorate your views using something other than this syntax right here, and a lot of people do not like these gator tags, as they're called. They say they look like spaghetti code, and that's fine. If you don't like that, there's all kinds of other view engines out there like Spark, NHaml and so on. This is the Web Forms view engine. We flex Web Forms to show data. It doesn't matter. One of the points of power of MVC is that your choice of view engine doesn't matter for your application. You can have anything. You can swap it out whenever you want. We pass in, we tell it you're going to be working with this typed data here. In this case, it's the notion of a dinner. To access this type up here that's passed in, you simply have to say Model dot, and up pops all your IntelliSense, which is groovy. All right, I'm going to leave this page exactly as it is, and I'm going to hit F5 again, and up pops our site, and now I'm going to type in "dinner," and I'm going to hit edit. Great, there we are, all my information. I can change this, "Rob's Happy Hour Party." Good, okay, and hit Save, and you can see it's been changed. The same thing happens here if I enter gobbledegook information. We're using the same model binders, and "Edit was unsuccessful. Please correct this." The validation doesn't work, so that's awesome. Okay, what is it that we just did? And the term is called scaffolding. I'm sure you've heard it before. It's been used a lot for forms over data approaches or data entry. But what it really is is a way for you to start from a standpoint of already having core data interactions but improving as you go on. What I mean by that is if you look back now— I'm going to start this application again— if you look back here at our main dinner page, and if we keep adding data, you'll notice what we're going to end up with is a long list of dinners. Well, if we take a look back at the Nerddinner site— and I'll bring this over here—what you'll notice is we have the exact same thing except it looks a lot prettier. This page right here can be considered to be dinner/index. In fact, this is the RESTful approach I was talking about, and if you are an administrator, then maybe a link might show up right down here that says, "Edit me," and if you clicked on "Edit me," then maybe you'd head over to this page here. This page can be as ugly as it wants. It's an administration screen. And it can even have this URL, so anyway, that's the point of the scaffolding. It puts you ahead a little bit. You can work with data. You can get data in, and all you've got to do is change and tweak, add some CSS, and you're off to go. But we have a little problem here, and that is notice if this is Dinner Index, notice this URL is the default URL. Let's fix that right now, and so what I want to do is I want to close down this, and I'm going to introduce routing. What is routing? You've heard me talk about routing. Let's dive into that. [Routing] I have my Dinner Controller, and I want this controller to be the default controller of the site. In fact, I don't have much use for this HomeController here, so what I'm going to do is I'm going to get rid of it. And so rather than delete it, I want to play it on the safe side, and I am going to exclude it from the project. It kind of makes it invisible. And if I use this little button up here, which Hanselman calls the "Don't Lie To Me Button," I can see my controller and my directory down here, and I can right click and include them if I want to, but I don't want to. I don't want them in the project. Okay, so that's easy enough to do, and what I need to do as well is come down here and kick out those tests too, but I'll talk more about tests in a little bit. What I need to do is I need to rejigger my routes. I want Dinners to be the root core of the site, so I'm going to come in here to Global asax, and I'm going to take this opportunity to start discussing routing and what it is. First and foremost, routing is the thing that I mentioned before. Routing is the thing that listens for URLs, and it routes those URLs to a controller and an action. If a URL comes in like Dinner/Edit/5, routing is going to listen for that, and it's going to say, "How can I find the controller that maps to this?" Well, Dinner/Edit/5, if we come over here to routing, controller, action, id. So where's the Dinner controller? What action am I looking for? Edit. The ID is 5. There's lots of freedom to this, and in fact, if I wanted to and I wanted to put in the year, I could have a year argument in here, and I could have it look something like that. That would be like 2009. The action could be monkey, and I could end up with the URL I discussed in the PowerPoint. So I'm going to leave this as a default route. I will be adding routes as we go along here, and you can see me do that, but right off the bat you can see that the default that's in here is the Home Controller, and I don't want it to go to the Home Controller. I want it to go to the Dinner Controller, because the Dinner Controller now is my home controller. So if I run the site now, instead of coming up and having the home index action show up now we have the dinner action. This is the power of routing, and so this is, again, at the core of the RESTful approach. I could, if I wanted to, change the information around and have something else show up in this URL. I could decorate this URL any way I want to. It's a very, very powerful feature. [Refactoring - Take 1] My Dinner Controller is almost completely scaffolded here. I have the C and the R and the U, create, read, update, but I don't have the delete, so I've added that in, and I've popped it down here at the bottom here. And one thing worth noting, as you can see here with my delete action, is I have made sure that it is a post. You want to make sure that when you have any data operations, such as edit and create up here, that you mark those as post. If you don't, then you can open your site up to what's known as cross-site request forgery. This can even happen if you have this nailed down with authorization. You're opening up to URL injection attacks and so on. One thing to always do is to make sure you accept post. Now, what I should also do here is I should also have the authorize attribute. This works with form validation and basically locks down this action so that if the user is unknown, well, then they're going to be redirected off. You can also restrict by roles. You can come here and say Roles="Admin." Well, I'm not going to do that today. Instead I'm going to show you really quickly how you add a delete functionality to your site. What I want to do is head over here to the edit view, and we'll open that up. And what I want to do is I want to be able to delete a record from the edit page, so I'll make them look at it first. What I want to do is introduce you really quickly to the HTML helpers, and specifically the one I'm going to be working with right now is creating a form. To create a form with ASP.NET MVC is pretty simple. You'll use this notation here. This is a using block, a C# using block that creates an opening tag above right here and down below creates a closing tag. I'm going to create my own form right here, and I'm going to copy and paste, being lazy. I'll line those up a little bit better. There we go. Next I need a submit tag to submit that form, and I'm going to rename this Delete. Good, and finally what I need is a hidden input, because the Dinner Controller delete action expects an ID, so I've got to pass that in. And so if I come back to the edit page here, I'm going to simply use the HTML helpers, HTML Hidden, and I'll call this id, and I'll pass in the Model.DinnerID. Good to go. Well, that's almost done. The last thing I need to do is I need to tell the form where it's going to submit. Now, if I leave it empty like this, it will submit back to its own URL. It will go to the edit action on the Dinner Controller, and I don't want that. What I want instead is I want it to go to the delete action on the Dinner Controller. I have to specify both those things. Notice here the name of the controller is dinner. Dinner Controller, even though it's a class name, Dinner Controller, it should be noted as dinner. That's easy now, and what I'm going to do is I'm going to hit F5, and I'm going to come in here and create some bogus data. That looks like a pretty good bogus amount of data. Hit Create, and now we have a bogus record. Whoops, let's get rid of that. I'll hit Edit, come back down here, hit Delete, and it's gone. Good, now we have delete, and what I should do right now that I know that it works is to close this thing down and come back here and put in Authorize(Roles="Administrator." There we go. Okay, quite happy now. That's how you can work with some of the HTML helpers, and what I want to do right now is I need to keep on refactoring, and I need to unhinge LINQ to SQL from my controller here. [Refactor Take 2: IRepository] My controller is coming along nicely. However, I have a small problem, and that is that I have a lot of repeated code in here, I'm instantiating a new data context, and I'm asking LINQ to SQL to go do a lot of things for me, and it's going to be a little bit difficult to test this controller, so if I want to test this index action I'm going to have to create a data context, which means I'm going to have to create a connection to a database, and then I'm going to have to test using the data that's in that database, and that's not a good idea for a couple of reasons. One primarily is speed. Anytime you have to access a database, if it's got a lot of records in it, that's just a pain in the butt. The other thing is that it's easy to fail. If you have some tests that are based on the data that's in that Dinners table, well, you can't guarantee that you know what data is going to be in there unless you stop and build your database for every test, and that's just ridiculous. And here we go. We have a very, very simple interface. We have add, update, delete, GetDinner, FindAllDinners. Notice here that I'm returning IQueryable. This is by design. I like having the flexibility of being able to tack on things, and I don't need to keep adjusting my repository interface. Now that I've done that, all I have to do is implement a repository implementation, and I can now change out my controller. Let's do that. Here is my SqlDinnerRepository implementation that uses LINQ to SQL. Pretty simple code in here, and not anything terribly shocking. Now what I can do is come back in here to my Dinners Controller, and I can use that dinner repository straight inside the Dinner Controller here. I'm going to call this "repository," and the best way to use this is a nice pattern that's going to allow the repository to be passed in. The Dinner Controller is going to have a dependency on this repository, and by that it can't really exist and can't really do much. As you can see, all of these actions here are data sensitive. It can't do anything unless it has this repository, so that is called a dependency. What I want to make sure I can do is I want to make sure I can pass that dependency in when the controller is instantiated. In other words, I want to inject that dependency. If I switch those words around, this is the dependency injection pattern. I simply do public, Dinner Controller, create a default constructor. This is the constructor that ASP.NET MVC is going to use, and so that means I'm going to default the repository here to a new SqlDinnerRepository. Great, and that is going to be the one that uses LINQ to SQL. Now what I want to do is I want to create another one that takes in an IDinnerRepository argument, and this is the one that testing is going to use, and again, I set this like that. Great, so now I just need to come down here and refactor this to use this passed in repository. Okay, I've refactored my controller. Now it's using repository, and that's groovy, and you can see I've lost a lot of code in here, a lot of repetition, and it looks a lot cleaner, and that makes me happy. It also means I can now start writing tests. [Unit Testing] It's time to start writing tests for my Dinner Controller here, and one of the things I want to do and I want to be sure of is that I am able to use a repository that does not hit the database. I mentioned it before, but it's really important that when you're testing your controllers you don't involve the database, because you might have a connection error. You might have a data error. You could have any number of errors involving a database, and that would destroy your test and cause it to fail. What you really want is you want the test to fail because the thing under test doesn't pass the assertion. What I need to do right now is I need to implement a brand-new repository. This repository is going to be known as a fake. It's not going to work with a database. It's going to work with an in-memory list. Down here in my test application I've created a directory called Fakes, and in it I'm going to create a new class, and I'm going to call it a FakeDinnerRepository. Now what I need to do in this FakeDinnerRepository is I need to implement an IDinnerRepository, and you can implement this by right clicking Implement Interface. Now what I need to do is to write some code to fill this repository out so I can use it in testing. Here is the code for my FakeDinnerRepository, and this, as you can see, is simply an in-memory list, and in the constructor of the repo here, I'm just looping 100 times, and I'm adding some dinner objects. What else I want to do is I want to vary the data a little bit. Something I know is that we're only going to show dinners with a date greater than or equal to today. I know we're going to need to show that on our controller, so I want to have some varying dates, and I might change this in the future depending on what my tests need. I don't want to go too crazy, because if I need something specific, I could also mock this interface here. But I don't think I'm going to address mocking today. For right now I want to show you how to do a fake repository. Now to use this with the rest of the methods what I can simply do is say "return dinners.AsQueryable" which is a fun way to turn a list into IQueryable. And then down here I can return singles. I can add dinners to the list and so on, so let's implement that. Here you go. We are just doing some list operations here. We're returning the single up here, as you can see, adding a dinner to the list, updating by finding and removing and then readding, and then deleting out of the list, so we're good to go with our fake. Now what we can do is use this FakeDinnerRepository. We'll set this as public. We can use this FakeDinnerRepository in our test, our controller test, and we can write a test. What I'm going to do is add a class in here. We had it right the first test, as you can see here. I followed Brad Wilson's advice. If you don't know what to call a test, call it Monkey until you can think of a better name, and that's the first important thing that I want to get across here is no test is ever necessarily permanent. You can change it as your needs change, and in fact, you probably will split one test into many. The naming of the first one, well, call it what you like. In this case, what I think I want to do is I want to test the controller, the index action. Might as well start somewhere and start at the index action. I want a test that returns dinners down to the view, just a really simple test, and that's a great place to start. Now, it might seem like what are you really testing? And it really should be stated that if you can write your test from a basic standpoint and then get more and more complicated, well, if it fails and you go down a linear path from complicated to simple, it makes it easy to narrow down the problem. What I want to do here is I'm going to give this a name, and I'll say "Index_Should_Return_1_or_more_Dinners." There we go. My casing is a little bit off, but that's okay. Now what I need to do is I need to create a controller. So if I run this test now, and I can right click here and hit Run Test, or I can be a good ninja and I can hit Control, r, t, or control run test, and it runs, and if I pop up the test results, it passed. That's all good. Now, if you're a fan of TDD, or test-driven development, you can use that with MVC just fine as well. Let's do that. Let's write another test method here. And in this test, what I think I want to test is the number of dinners that are returned. Let's think about that for a second. What dinners should we be returning? This is why I changed the event date in the FakeDinnerRepository right here. I put a switch in there to say, well, if it's greater than 50, then the events should occur yesterday. And so back in my Dinner Controller test what I want to do now is I want to write a test and say how many dinners am I getting back from my controller? Well, it should only show the dinners that are greater than today, or today or greater, I should say. I should write "index_Should_Return_Dinners_For_Today_Or_Later." And so what I'm going to do is I'm going to copy and paste this exact same thing, and then I want to make sure that there are no dinners that are in this data that occur yesterday. What I want to do is I want to say "Assert.IsFalse." This assertion is testing that there should be no event dates in the dinners that occur yesterday. Well, if I run this, it should fail, and this is part of red green refactor, and it did fail, because we have dinners in there that occur yesterday. If I come in here what I can do now—excuse me, go back to the Dinner Controller. I can change my index here, and I can say "FindAllDinners.Where EventDate >=Today." That should work. If I come back here to our Dinner Controller test, TDD in action. Red green refactor, so I've got my green. [Tackling Tough UI with ViewModels] There's still some refactoring that I can do here to tighten things up a little bit, and what this is going to allow me to do is also address a question which I hear a lot of, which is what if I have a complicated UI that has a lot of information on it, like a portal page, for instance? How do I handle that? And the answer is you can follow a pattern called the presentation model pattern, or you could use something which we call a view model. If we take a look at the Nerddinner.com website here you can see we do have a little bit of logic in this page, and specifically we have the notion of RSVPs here, and if I come up here to Host a Dinner we have a few other things in here that we have to show and tweak and display. We might have something in here that shows a filter, for instance, for swear words if someone is putting some inappropriate language and so on. If we look at the Nerddinner code that is behind this site, we also see a few other things. This is the Dinner Controller from the Nerddinner.com website, but we have the notion of a constant of page size in our controller. This is a UI concern. Not a big deal. It's not a big deal at all. But if you want to encapsulate this so that in the future maybe if you add Silverlight capabilities to your site maybe you'll have a different UI you want to plug in. You can put this all in one place, and I'll show you how that works in a second. Another thing that we have in here is a quick test to see if the user is the owner of the dinner. Now, if they are, then we show some links that they can edit or cancel their dinner. This is now buried inside the controller, as you can see in a couple of different places. We have one there, and we have one there. And I believe we have another one down here. I want to unhinge all that, and the way that I'm going to do that is to use a thing called a presentation model or a view model. You've probably seen this before in the Dinner Controller that we had on Nerddinner previously where we had a different class up here. You've probably seen that in a couple examples where you come up here and create a class called DinnerViewModel. But I'm going to make this a little bit more formal. I'm going to create a class right here inside of my Model folder, and I will call this a DinnerViewModel. There we go, so it's a brand-new class, and what I want to do now is I want to add some information to it so then I can use it to display on the page. It's a very small beginning, but here we are. Just a quick property to display a selected dinner. We have something to display in RSVP count, so if I head back over to the Nerddinner Controller here, Nerddinner Dinner Controller, the live one, one of the other things I want to pop in here is page size. The reason why this is a good idea is because now this becomes logic that is built in specifically to a presentation class, and so this is nice, because you can share this, again, across all UIs that might access your site's back end such as Silverlight or Flash or whatever you're going to use. Now we know that the page size should be 25, and that's great. The other thing that we can do is we can have this method right here encapsulated in our class if we like, so we can use it everywhere, and it's a simple check. It checks if the hosted by is equal to the current user's name. This uses user.identity.name. It's an IPrincipal, and it's not necessarily created by HTTP context. But unfortunately, we don't have a controller to work with here in the view model, so I'll show you what we can do. There's a way around this, but first of all, what I'm going to do is I'm going to write the method that's going to allow me to access this. Here's the code that we have. Just a quick boolean method to find out is the current user the owner? And I'm accessing HTTP context current user identity name. This isn't a good idea, because if I test this, this is going to fail, because it's going to be null. There is no HTTP context in a testing project. But I can get around that, and I can get around that by writing a method or having a property up here for the current user. I can simply type in this. That way I can set it wherever I like, and so then I can copy this down. There we go, and we have an ignore case, and so we're good to go with that. One of the other things I don't particularly care for is when you do go to create a new dinner, as you can see, this event date is set in the future, which is good. But we also want to be able to include time in here. We went with using Date and then some text for the time. We don't have a date selector, because this is really important. It's the start time. I think I want to separate these 2 out, because having a date selector is very important, and working with times between the 2 is a little bit tough. In other words, we really want this to be something meaningful, and also it doesn't have to be a rigorous time. It could be after work or happy hour or whatever we want it to be. What I think I'll do is I'll create the notion of a prompt in here. What I can do is I can say let's have a date prompt. That's what we'll call it. Here's my current date and time prompt, and it's exactly what I want to see on the UI, and so what we can do is add a week to today and then default the time until 6 PM. I think that works out good. While I was at it, I also improved the way the current user property works, and what I'm doing instead now is I'm doing it old school here where I'm returning a local variable, and I'm going to default it to the HTTP context current if it's not null, because if it's not null, that means the website is using it, and you might as well default it to the name. [Making Things Pretty] It's time to add a little spit and polish to the default view of the site, which is the index view of the Dinner Controller, and if I run the site, you can see that I still have the baby blue and white default template look and feel. What I'm going to do is I'm going to implement here the CSS and the images that we put together for— or I should say Dave Ward and Michael Dorian Bach put together for the Nerddinner site, and so being a good demo guy, I'm not going to make you watch me build out the CSS. I am going to drag it from the Content folder of the Nerddinner site, and I'm going to drop it in here, and so there goes the CSS. It's exciting, and there's our nerd image, which is pretty cool. The next thing I need to do is I need to work with the site master page. Now, a lot of people find it very strange that we still work with site masters in an MVC, and you sure can. If you look in Views and Shared, this is where you have a bunch of shared stuff, which includes a log on user control, an error page that we redirect folks to, and a site master, and this is a Web Form. You can do all the stuff in here that you could normally do with a Web Form. You just can't post back, but if you have things like a menu control that you want to use, you sure can. What I want to do is replace what's in here with the site master from Nerddinner. That's what I'll do. I'm going to be bold. I'm going to grab it, drag it, drop it, add it. That's kind of crazy. There we are, and there it is. Up it comes. There's a couple other views in here that I think I'll grab and drop them in as well. They're just shared views. I'll say yes to all. Well, let's see what we've got in here in the site master. As you can see, it's pretty basic stuff. We have links to scripts, and inside here we also have a link to our production CSS, which is pretty cool. And we're rendering a login status partial, so I've got to make sure I have that, and I do. Let's run it and see what happens. No errors yet. That's exciting. Let's see how everything looks. Look at that. Hey, what do you know? Wow, that was pretty easy. I have to say, I'm a little bit surprised. We even have the UserVoice feedback tag. That's pretty cool. Well, now what I need to do is I need to hook up the maps. The site looks pretty good, and Nerddinner is starting to come together. Let's hook up some JavaScript and some maps. [Bing Maps] Today what I want to work with is Bing maps, and it's going to show where all the dinners are on the map, and this map is pretty interactive. It's kind of nice. You zoom in, zoom out, all that with my mouse wheel. It's kind of fun, so let's get started. To work with Bing maps you can read up on the API. It's over here at MSDN. If you don't remember this long URL, you can type in "Bing maps API" in your search engine, or you can type in dev.virtualearth.net. They have all kinds of information here, and curiously, it looks like it's sorted by—no it's not. I was going to say it's sorted by alphabetical, but they start you off with a tutorial on box, radius, and polygon searches and so on. Finding information, that's a good one. But where I want to start today is I want to start on importing and mapping data. If you look at this, you have all kinds of code in here, which is cool, so I'm going to pull this over so you can see it more. And that's what I like. I like examples with code. So to make this super easy, what I'm going to do is copy and paste this. This is creating a basic map. It's going to be my script tag. This is what I need, and it's going to show me the HTML that I need, and it's going to show me down here what I get, so that's exciting. I'm going to simply drop it in like that. Copy and paste. It's the best kind of demo ever. Copy and paste code. I think everyone should do that. If I refresh, hopefully I will get, and I do, a map. That's exciting. Let's continue on here. What I'm going to do now is cruise down this example site, because the next thing is going to show me how to add a pushpin, so I'm going to copy and paste that as well. And I've got to move these windows out of the way, and to add a pushpin I use the map object. I add what's called a virtual earth shape. VE, V stands for virtual earth. And have it be a pushpin, and I'm going to pop it right in the center of the site. This right here is known as a coordinate. It has a latitude and longitude to it, but you can ask the map, "Hey, man, what's your center?" and it will tell you and give you back a set of coordinates. So I've added that in, and I need to save my page. Here we go, and now if I refresh it, we should get a nice pin. Yep, that's what I want. The pin is groovy. It doesn't really do much for us. What I need to do now is I need to add text. Title and description would be great, so there it is. I think what I'm going to do is drop this here. Set the properties of it. Look at that. HTML embedded in JavaScript. Doesn't that make you happy? If I right click this, and now that's groovy. Let's do it again. There we go. You've got to hover over it. The pushpin title looks like a broken image. That's okay. But isn't that neat? It's kind of cool. You hover over it, and it gives you a little bit of a status thing saying, "Loading something." That's exactly what we need to do. Nothing more, nothing less. I'm going to take this code right here and get started building out all of the dinner pins— let's call them that—and loading them on the page. This is good code to get started with, but I can refine this a little bit. In fact, I'm going to, because I have some problems, as you've probably noticed. Right here I have the ghost of the end of a head tag. Also, I have duplicate body tags. I have one tag in the site master, which sort of surrounds this content page, if you will. And I'm relying on the onload tag here inside my HTML, and it's not exactly elegant, so what I can do is I can use jQuery, and I'm sure you've heard of jQuery before. What I'm going to do is I'm going to reference it, and in case you didn't know, jQuery comes with the MVC template. You get a number of files here, as you can see. You've got jQuery proper, as you will, and also the min file. The min file squeezes out things like white space and debug information. It makes it nice and small. I'll be using regular old jQuery today, and in here I'm going to get rid of this link, and we'll add a reference to scripts and then jQuery-1.3.2.js. Great, okay, that's referenced. Now what I want to do is I want to hook in to jQuery's built-in ready function, and what that means is when an element is rendered or basically has been added into the document object model it is then ready, and so that could be thought of as an event, and so I want to hook in to the document's ready event, sort of like body onload. So what I'm going to do is write a little jQuery syntax. I'll put it at the very, very top here, and this is the ubiquitous jQuery call, and it usually always begins with a selector, and that's the $ sign. The selector means here comes a selection request or a query. That's why they call it jQuery, in case you've ever wondered. You're querying your document object for elements, and in this case, we can do a number of things in here. I can say, "Give me an ID. Give me the my map, the div or the object with the ID my map." It will run out and grab it, and then you can manipulate it using code here. You can also say, "Here, give me everything with the class foo, or give me all list items" and so on. In this case, what I want to do is I simply want to grab the document element. Go select the document element, and then for the ready function, what I'm going to do is on ready I'm going to pass in this function right here, and then I'm going to close it off like a good developer. There we are, so when the document is ready, I want you to run this function, and that function is simply going to be this down here. I'm going to rename to LoadMap. There we are. I'm going to pop it in there. LoadMap. Good. I'm going to leave this up here, because I know there's going to be a few more things I'm going to be doing with that map, but I'm going to load up that map, and that should be good to go. Yeah, everything looks good. What I want to do is hit F5, make sure the map loads, and it does. Great, so we're all jQuery-ed up. I feel better about this. Now let's see if we can add in some data. [But First, Let's Get to Know jQuery...] One of the tools that you get when you download the ASP.NET MVC project templates and you do a final new MVC project is jQuery, and a lot of web developers have heard of it. I know a lot of them have used it, but some of them haven't, and they're not quite sure what it is. It's kind of a funny name, jQuery. What I'd like to do is really quickly show you how you can use it, because it's really, really powerful. To get right to it, what I want to do is tell you here's the jQuery site at jquery.com. You can read a lot here, including all the documentation. You can see some of the things that it can do for you. But for straightaway the things that it can do for you you should head over to the UI elements here. The jQuery UI is kind of a separate— I don't want to say it's separate from jQuery, but it's sort of an add-on, or it's on top of it, a different layer, and what the jQuery UI will do is it will add all kinds of widgets to your site that replace server components that you might be missing in the Web Forms world. If we go over to Demos & Documentation to take a look at some of these widgets, well, let's go ahead and look at them. You have things like the accordion, which is pretty groovy. There's draggable and droppable components. Drag it around, and you have all kinds of things you can do. This is all stuff that's built into the jQuery UI stuff, including tabs. There's a progress bar even, which is groovy, and one of the main things that a lot of people don't know about this is jQuery is themed, so all the tools that you see here you can change the theme on. You might want to say, "Well, I'm not a big fan of the orange and blue. I'm really more of a dark guy." And so they have a darker theme, which is pretty cool. If we head over to the accordion and we change the theme to darkness, you can see that indeed it changes as well, which is kind of cool. Well, if you don't like what they have, you can head over to the Themes page, and this is where I like to go, because on here you can change whatever it is you don't like about the themes. If you don't like a certain color, a certain radius, you can change it, and when you're done with it, you can download the theme that you've created. You can have it very specific to your stuff. And if you're like me and you say, "Well, you know what, these themes are pretty good. I like this one right here. It's kind of nice." This is the overcast theme, as you can tell by the name right here, and what I really like is this highlight/error box that they show you. They also have dialog overlays, all these icons. There's so much you can do. I like this dialog. It's kind of cool. Nice modal dialog. Anyway, if you want to download it this is another nice feature. You go over here to the download page, and you can choose the things that you want. You don't have to have all of it, and so if you don't want a huge file and you only need drag and drop, let's say, you can uncheck everything and go for these, but what I'm going to do right now is I'm going to download all of this stuff, and I'm going to choose my overcast theme. What that's going to do is it's going to include that theme in my download, and the current one is 172, so when I hit Download down it comes. I'm going to open this up and show you the files inside. I downloaded it to my desktop and dropped everything in a brand-new folder, and inside here is a nice HTML page that you get with the download. If you double click this, it will open up, and here's all the samples that you're going to need, which is great. If you need any kind of guidance or how do I do this you simply right click here, view source, and it will show you how you can work it on your page. There's also a nice development bundle, so if you want to get in there and start working on stuff you sure can. I'm not going to dive too much in there. The only thing we're going to need here are 2 things. One, we're going to need this JavaScript that comes in here, and 2, we're going to need the CSS in here, because it's got my overcast theme. What I'm going to do is I'm going to add this to my project, and I'm going to add my script files here. Well, only one, because I have the 132 already. I'm only going to add 172, the jQuery UI, into my Scripts folder, and I'll do it right now. And then the other thing I'm going to do is I love the overcast theme, so in my CSS inside here I'm going to drag and drop these things as well into the Scripts folder. Now, I could probably—and I probably should— drop these in the Content folder. However, I like to keep all my scripting stuff together, even the look and feel. The thing I'm going to show you to do is how mercilessly simple it is to create something like a calendar. What I need to do, of course, is first and foremost reference the jQuery UI library. I'm going to copy and paste that. Okay, I have my scripts laid out here. I've got my CSS referenced, and now what I need to do is I need to have a control that is going to handle the data input. And what better control than a regular old text input? It doesn't need to be anything special, and so in here I tell it I'm going to type it out to text, and I'm going to give it an ID, and I'm going to call it dateInput, and I'll give it a name with the same, dateInput. There we are. Well, the way the jQuery works, again, is when you want something to have an ability, like in this case we want this to be a date input, and I should have surrounded those by quotes. Anyway, you just use it as sort of a method. You select the element, and then you add what you need to do to it. In this case, what I need to do is I first need to select it, so I use my selector syntax, and the ID of my input is dateinput, so I say #, which is the ID selector, and dateinput, and the function I need to call is datepicker. There it is. Now, if you were to open up the bits in here and take a look in index.html, that's exactly what you'd see for the date. This is all we need to do. We've enabled this text input to be a date picker, which is groovy. I'm going to hit run, and it pops up. We now have—whoops, you know what I need to do is I need to turn that map loader off. For some reason they don't like living side by side. Hit run, and now there's my date picker. As easy as that. I'll split out the functionality a bit here to be a little cleaner, and now what I have is a nice, new function called LoadPoint, and I pass it the latitude, longitude, title and description, and what this is going to do is create a point to pass off to the pushpin saying this is where you're supposed to go. You can see I'm passing it here, and I'm setting the title and description for the pin, and finally, adding the shape. To test this out, we could load a point straight in here after we load the map up, and these are the coordinates, as you probably can guess, to my house. If I hit F5 and up pops the map, and hey, wait a minute. For those of you who don't know, I live out in the middle of the ocean, so maybe we can cruise in here a little closer, and you can see where my house is. There's my small island and my small town, and that's where I live. That's good, and if I hover over this, hey, Rob, there it is. Great, now we're ready to go. We can add some data to the page, so there's a couple different ways we can do this, and I'm going to show you both. By far and away the best way to put the data onto the map is to use a nice Ajax callback using jQuery and then let the script load the points. Now, I could use server-side tags, as discussed previously, but that would litter my pretty jQuery code on the client here with some ugly gator tags. Developers in the future are going to look at this and say, "Oh, my goodness, what was this guy thinking?" Secondarily, should you ever decide to clean up the JavaScript, which I'm about to, and add some name spacing and so on, put it in a nice, centralized file, well, server-side code does not run in centralized files. Instead what I think I'm going to do is, again, let jQuery handle the callbacks, and that's easy enough to do. What I can do is use the built-in Ajax functionality inside jQuery, and I can do something like this, .ajax, and I can put in the URL, and off we go. Actually, that should be a /. And then I could add some other options in there, callback functionality. I could specify content type and so on. If I wanted to be super lightweight, I can do get, and that will send a get request off to the server. I'll also use post, but this isn't a postback, but should I ever need to post data to the server, that's how you do it. You use post, and finally, the thing I'm going to do is I'm going to use the shortcut getJSON method from jQuery, which is literally getJSON. And what I need to do here is I need to pass in /dinner, and next up, I'm going to send in a callback function, and it's going to accept some JSON data. There we go. The way this works is it makes a request to the dinner URL. When it gets the data back, it passes it off to this function. This is the callback function, and we're going to do something fun in there. I'll save this down. Notice that this URL is this headed off to dinner index. Dinner index right now is set up, as you can see here, to go pull all the dinners and return them to the view. I need to change this. I need to actually change this based on the format of the request. In other words, is it HTML that's needed? Is it XML, JSON, whatever? And right now all I need to care about is whether it's JSON or not, and an Ajax request or not. And the neat thing is that Phil and team have already thought of this, and so what you can do is you can sniff the headers and look for certain content types, because jQuery always sends back x-requested-with, and it says jQuery. Or you can simply say if request.IsAjaxRequest, and that is a built-in method that Phil and team put in there to smell if jQuery or Microsoft Ajax are calling. What I can do here is I can say, "Hey, is this an AJAX request?" If it is, load the data, and then pass it back as JSON, and I'll address that in a second. If it's not, just return the view, and this is exactly what I want, and now we're not running the query first. We'll run the view, and in here we don't even need to do any of this. Great, so now what I need to do is I need to parse this stuff down to JSON, and that is not as hard as it seems. All I have to do is say return Json(dinners). Done. Our Ajax magic is almost ready to go, but we have one last hurdle we have to get by, and you can see what I mean if we set a little break point here, old school style break point, where we output the results to a message box, and back here in the controller what I want to do also is set a break point, because I want to look at what happens. I want to make sure that this callback is happening, and then I want to see if it's going to pop up a message box with what's returned. And if I'm right, then it shouldn't return anything. We wait for the page to load, and there is our first trip, and this is the get request. This is the non-Ajax request from the page, and if we keep on going here, do we get a callback from the page? Yep, and it trips again. This is our Ajax request. And it's going to hit the database there, and it pulls out 12 dinners, and I'm sending it down to the JSON serializer. What I should see next is a message box saying object, object, object. If I run this, the page will load, and nothing happens, and so that's not what we want to see. So what exactly is happening here? Well, let's take a look. If I come in here and I create a new dinner object and take a look at it, see what the JSON serializer is trying to serialize, I go down, and it's a bunch of strings and so on, so that's all good, dates and latitude, longitude, but if I keep on going, bam, I get a list of RVSPs. Now, normally that's okay. Child collections are just fine. What a JSON serializer will do is it will go and try and serialize those as well, so so far that's okay, but if I take an RSVP and I create a new one, and I take a look at its properties, well, the second one tips me off as to the problem. These are linked to SQL-generated classes, and LINQ to SQL is awesome. It does us a bunch of good favors, but unfortunately, sometimes it creates these circular relationships. Because of the serializer, it's going to try and serialize the dinner property on the RSVP, and it's going to reference back to the original object, and we have a recursive explosion. What I need to do to make this work is I need to create a new JSON object, and I could create a new anonymous type in here. I could say New and assign some properties and so on, but that's a little bit ugly, and I don't want that kind of thing embedded into my controller, plus I might want to reuse it on a show request, for instance. Or details, I should say. What I'm going to do is I'm going to work with the Dinner View Model. I'm going to use a nice, lightweight class and give it a factory method, and let's see what we come up with. Here we go. It's a very, very easy class. Again, super lightweight. This should be no problem for the serializer to munch up and crunch up. And then on Dinner View Model, I have a factory method here that's going to return IList of Json Dinner kind of in the same way I'm returning IList of Dinner View Model by passing in an IEnumerable of Dinners, and you can see I'm spinning everything to a list. This is good. This constructor here takes a dinner object, and it sets the properties. Now I should be good to go with the serializer. I come back in here to the controller, and I say DinnerViewModel, and I say GetJsonDinners, and then I pass in dinners. Great. Now I can reuse this everywhere. Whoops, I need another parenthesis. There we go. Now I can reuse this everywhere, and I'm happy, so hopefully everybody else will be happy. I hit F5, and my stuff should load, and I should see a big, fat bang. Yep, good news. Object, object, object, object. That's exactly what we want to see. Now we can use this thing to load the pins on the map. The final step here is I'm going to remove the alert, and I'm going to use some more jQuery goodness, and I'm going to use the each function, which is pretty cool. This is basically saying a for each inside of jQuery, and what I'm able to do, since I'm working with JSON data, is I can take the data that's passed down from the getJSON method. You can see it's being passed in on the fly right there. And I can create a new function to deal with it. I'm calling it a dinner, so basically I'm saying for each object in the JSON result here's a function, so you can go do something with it. And then I'll close that off. Great. I, in case you're wondering what this is, is the loop counter. It's built in to the each function, which is pretty groovy. Now what I really need to do is I need to load a pin with the dinner data. This is something that a lot of people don't quite catch with JSON, and JavaScript itself is a pretty free, dynamic language, so we know that when we get the JSON results back they are part of our JSON dinner. If I open up that Dinner View Model here, JsonDinner, these properties should be exposed on the object. I should be able to take the latitude, longitude, title and description and send it over to the load points thing. I can say LoadPin, and I can pass in dinner.Latitude, dinner.Longitude, if I can spell it right, and then dinner.Title, and finally, dinner.Description. Okay, great, that's it. This is how we handle JSON callback, and I will clean this up in a second. I know that looks crunchy and munchy there. There we go. There's our pins. Awesome stuff, and this is all the test data that I just put in. That's how we deal with JSON callback. It's pretty easy. What I think I'm going to do now is parse this out a little cleaner so you don't have to sit here and look at all these nested function calls. There we go, a little bit cleaner. We now have a nice load dinner function that passes in a dinner object, and again, this is JavaScript, and we're good to go. This looks pretty clean, and when I run this everything will pop up nicely. Now, I should say there is a lot of cleanup I can do with this JavaScript, but I'd like to continue on and keep on moving. Getting close to being finished with the mapping functionality here on the index view, and so far everything seems to be going together pretty well. I've added a little bit more styling and layout to the home page here, so now we have the map shoved to the left and a list that is set up for me on the right side here, which presents me with an interesting issue. As you remember, I'm loading all the dinners with a JSON callback, so I don't really need my model anymore, because I'm not doing any server side stuff on the page. Yet if I look at the Nerddinner.com site, over here you can see I have a list of popular dinners, and each one of these things links off back to the dinner that we can click on. I need to fix that. That's okay, jQuery to the rescue again. I can reuse the client side code, and let's do that. What I'm going to do is I'm going to load a list on the fly and shove it into this div tag, and cover your eyes. This isn't going to be the nicest code, but again, we can always tweak this as time goes on. Something like this ought to do the trick, and then I know when I run this it's going to look ugly, but I will have a function where I load in the information. Right now I want to see if it's going to load up and display. If I load up the page, good. It displays all of the dinners on the right side. That's nice, but of course, as we can see, we've got the title. That's good. We have an ugly date. We also need to format this a little bit better, so what I need to do now is to write some formatting code and a centralized function that can handle this output. Let's write that really quick. Still not optimal, but getting there. I have a function here that is separated out a little bit, and it's loading up the link. It's going to go in the list on the right side, and I have some formatting functionality that I dropped in. It formats the link and the HTML, formats the date, etc. That's all good stuff. Again, it's not that much code, but I'm going to drop all of this into a separate JavaScript file in just a little bit. The good news is if I run this and it pops up, I will now see a nice list on the right side, and that's what I want to see. If I click it, Curing Polio, that's always a good dinner. [Finishing Up] I'm nearing the finish line here, and I have just 1 last thing to do, and that is I've got to make it so that this page makes some sense. In preparation for this, what I've done is I've gone into the site here, and I've cleaned things up a lot. What I've done is I've centralized all of the scripts into a single nerddinner.js file. Not all of them, just a lot of the main ones, like LoadPoint, LoadPin, LoadMap and all the formatters and so on. What I need to do now is I need to expand this details page. I'm going to start by adding references to the script files, and then I want to output my map again, and then finally the data itself. Here we go. Here's the references that I need to use for the page. I've got my jQuery and nerddinner.js. I've referenced the mapping functionality, and I know previously I said you don't want to put service side code into JavaScript. However, this page is incredibly simple, and to do anything different would probably add a layer of complexity, so I'm going to go back on what I just said. I think it's okay if you have a little bit, and I think this is fairly clear. And then I'm loading up the map, and I'm loading a pin onto the map, and so that couldn't be simpler. We've centralized all that into a central nerddinner.js file, and here's the page. It pops up when I click on .NET Futures. Great, so the last thing I need to do is to add some details over here, and that is pretty simple. Let's add that really quick. Okay, here's the final list of things that we need. This says the when and the where and the description and so on. Notice here that I'm HTML encoding everything. What this does is it takes special characters that are HTML, and it codes them into decipherable characters by the browser. It's like a replacement technique. The last thing you want is someone writing a script into their description of their dinner and having that script cause havoc on your pages. I hope you've enjoyed this deep dive into ASP.NET MVC as we rebuilt the Nerddinner.com website. The point of this webcast was to give you a deep look at building out a site with ASP.NET MVC. I've enjoyed doing it, and I look forward to doing another one. [Questions?] [[email protected]] [[email protected]m] [[email protected] microsoft.com] [Microsoft ASP.NET] [www.ASP.net]

Video Details

Duration: 1 hour, 20 minutes and 29 seconds
Country: United States
Language: English
License: All rights reserved
Genre: None
Views: 5
Posted by: neudesicasp on Sep 16, 2013

An in-depth tutorial on building an application with ASP.NET MVC. In this video we build the basics of Nerddinner.com and cover issues such as Unit Testing, Javascript (using jQuery), and how to use the new tooling features for Visual Studio 2008 which are installed with the ASP.NET MVC project templates.

Caption and Translate

    Sign In/Register for Dotsub to translate this video.