FREELessons: 22Length: 5.5 hours

Next lesson playing in 5 seconds

  • Overview
  • Transcript

8.1 Incorporating a Menu

We need an easier way to get around our admin system. We'll solve this problem by writing a menu.

8.1 Incorporating a Menu

For the most part, we're done with the admin portion of our application. There's just a few things that we need to do to enhance the user experience. And that is understating the problem because we have no user experience right now. In order to go to posts and then tags and then to users we have to manually manipulate the URL and that's not very helpful. So in this lesson we are going to implement an AdminMenu. It's basically just going to be a list of links and of course we don't want to display all of. The links for all of the users. For example, an author has no business seeing the tag's link or even the user's link. But they should be able to see a link for changing their own user information. So, instead of users It would be called profile, or something like that. Now we can implement a menu like this in a couple of different ways. Used to I would do everything inside of the view, so first I'm going to paste in some HTML. Now I've gotten this from the NVC application template what I did is I just created another NVC application and I chose the HTML and CSS that I wanted to use. And in this case, this is going to put a black bar at the top. And this is where our menu is going to be. It's going to be inside of this unordered list. So, I would have a lot of if statements. First of all, I would check to see if the user is authenticated so I would have User.Identity.IsAuthenticated. And if they were, then I would display log out link. Otherwise, I would display the log in link. And then I would also check to see if the user was in a given role. If they were in the admin role, then I would display the links for the admin role, and so on and so forth. You get the idea. And basically you end up with a very cluttered view, and it really helps no one to have a cluttered view, so I stopped doing it this way, and instead, I started doing everything inside of the controller, so I will have an action method that actually generates the items within the menu. So that all of that logic is in the controller where really it should be. It generates a model that it then sends to the view and then the view is responsible for taking that model and creating links from those. So instead this is the type of code that we will end with. We'll have a razor code block and inside of here we will call Html. And we have a method called RenderAction. This calls an action method on a controller, and we can specify that in action method returns a partial view result. So instead of returning a full view, it just returns a partial view. So I would call Html.RenderAction I would specify the action name, so we can call this AdminMenu. And then we would need to supply the route values. So that would be a new anonymous object, and we would set the controller to whatever controller. Ideally we would have a separate controller for generating the menu, but in this case it kind of makes since to put this on the AdminMenu. So that's what we're going to do. And then we need to specify the admin area as well. So inside of the view this is all of the code that is there. There's no nested "if" statements or things like that, it's just nice and clean. So, let's go to the admin controller, and let's add a method called AdminMenu and this needs to return a type of partial result. Actually, we're going to make it asynchronous, but we're not actually going to do anything asynchronous inside of it. So, let's do public async task of a partial view result and we will call it Admin Menu. Now before we do anything else. Seeing the dispose method reminds me of something. At the end of the previous lesson, I believe I put the disposed method or the dispose method rather. In the wrong class I think I've put it inside of the post repository and that is definitely not where it needs to go, it needs to go inside of the post controller. So, I made that modification so the code for this lesson is going to have the correct code inside of the post controller, so the dispose method will be here and it will not be inside of the post repository. I just wanted to point that out for you. Okay, so we have this AdminMenu and basically we need a model that we are going to generate to send to the view. So let's create a new class. Let's call it AdminMenuItem. And it's going to represent each item in the menu. So basically it's going to represent a link. So lets go to our models name space. We could make the argument that this is a view model as well. In fact, yeah, lets make it a view model. So, lets add a new class. And let's call it AdminMenuItem. And there are several pieces of information that an AdminMenuItem needs. First is the text that is going to be used to display with the link. So this is obviously going to be a string and let's just call it Text. We also need to note the actions, so let's have ActionName or let's just have Action. And then we can have. An object of route information. So this is going to be an anonymous object that has the controller and the area and so on and so forth. So now let's go back to our admin controller and inside of the AdminMenu we first of all want to check to see if the user is logged in. So If user identity is authenticated, then we want to display the different links for our menu. So the first thing should be the admin home. Now we could make the argument that we don't have to be authenticated in order to see the home link. But if it turns up that we need to do that we can always change it later. So let's first of all create a list of this AdmiMenuItem. Let's call this simply items and we want to new op list of AdminMenuItem. And this is going to contain all our items that we are then going to send. To the partial view. So if the user is authenticated, the first thing we want is to add in the menu item for the admin home. So we're going to do "Items.Add(new AdminMenuItem). We'll use initializer syntax, and we'll set "Text = Admin Home," the action Is going to be index and then the route info is going to be a new object where the controller is = to admin and the area is = to admin. And then we can move on to the next item. So let's say that next is the user's links, so the user's is only visible to admins. So we can do if User.IsInRole Role and admin. Then we want to add a new AdminMenuItem to our items collection. So let's just copy this code and then we just need to make a few modifications. So the text will be Users the action will be index, the controller will be user, and the area will be admin. But if the user is not an admin, we want to display another link so that that user can modify their profile information. So we'll call this profile. The action in this case is going to be edit. The controller is going to be user. The area is going to be admin. But we also need to specify the username = to The next item in our list can be the tags link. And we only show tags for admins. And editors, so we can basically say if the user is not in the author role, then we want to add the tags link, so we will grab that, and we will paste it in. Let's change this to Tags, the action will be index. The controller will be tag, admin is the area and we no longer need this username. So we can get rid of that. And then the final item is the posts, and everybody can see the posts. So we don't need an if statement for that. We will just simply add a new AdminMenuItem. And the text will be "Posts," the action will be "index," and the controller will be "post." and then finally we pass our items to the view. So, we will return partial view, and we will pass in the items collection. So, now we just need a view for the AdminMenu action method. So, let's right-click and add a view. We want to call this AdminMenu, and this is a partial view. Now we can go ahead and we can specify a template. Let's do list and let's set the model class = to AdminMenuItem. Now, we're not going to use pretty much everything here. The reason why I did it this way is so that we can get to the @model at the top. And we also get our for each loop. But everything else is going to go away. So let's get rid of everything. And then inside of this for each loop, we basically want to generate our link. So each link is inside of an li element because this is inside of a list. So we will use the ActionLink method. The text is item.text. And then the action is item.action. And then the route values are item.RouteInfo. And that's really all that we need to do here. Now, let's go back to the AdminController, because we need to add the allow anonymous attribute. To this action method because if we are not logged in, we are going to run into some issues, if we try to use this action method inside of our views. So, we need AllowAnonymous here, so that no matter where we are, we can use this AdminMenu action method. And we don't have to worry about anybody making a request for this action method because It has the return of partial view results. The NVC framework is automatically not going to allow us to make a request for that. We should have everything ready to go. We do need to add some CSS so things look pretty. Let's go and find, I don't think we have the content folder. Let's collapse everything. And no we don't, but we really don't need the content folder. I'm going to add a folder at the root called, CSS. And then I'm going to add in some CSS files. Once again this CSS that I'm going to add are part of the MVC application template. So, I want to choose existing item. And all of this is inside of my Documents. So let me find. We want Site.css, and then bootstrap.min.css. So we will add those, and we also need to add these to the layout page. So we can do this very easily by just dragging and dropping those files. That's a very nice little feature. Here we go. So, we have those CSS files, let's run our application and let's see if this works. So, first of all we need to go our admin and we will need to log in, so let's log in an as author because that is the most restrictive and we know exactly what we should be seeing. So, author, and password is the password. And, let's log in. And we have admin home. Great. We have profile. The link is admin slash user slash edit slash author. So, if we click on Profile. It prompts us to login, so there's definitely something wrong there. We will just need to find out why. We should not be seeing tags, so we are definitely going to have to debug this. And posts [LAUGH] thankfully works. And we are seeing admin stuff, too. So we definitely need to, look at some of the code that we wrote in the previous lesson. Okay, so let's first of all, go to our AdminController, and let's look at the AdminMenu action method. Let's make sure that everything is right here. Ok, so the first item is the Admin Home. We then check to see if the user is in the admin role. Well I guess it's possible that author is an admin. So, let's go back, and let's run this. And then let's set the author as an author, and then hopefully we will see things change. So,admin and then we will log back in as the author. And password. And let's go to, well, we can't edit. We tried to do that and we get this. Okay. So, we're going to have to debug this. Let's go to our user controllers. So, areas and then user controller. Let's go down to the edit method, the one that handles Git requests, cause that is where we were having our problem. So, let's set the break point on line 68 on the first statement there and let's hit back. Let's click on the Profile link once again. And that's not even letting us go through. The only other issue could be that we don't have any roles assigned for the author user. Because we created the user before we even had the ability to add roles. So, let's stop running our application. No, let's not. Let's logout. So, we need a menu item for logging out, and we will add that later. But let's first. Log out, and then let's log in as the Admin. Now I don't remember what the password was for Admin, so we're going to go to the app_start folder, the auth DB config. And let's find this password here, so let's go back. Let's log in, so let's go to /Admin and then we want admin and then password. And then hopefully we should be able to edit these things, and we can. Okay, so, let's go to the author. Let's edit, and of course we hit the breakpoint, so let's continue on so that we can modify this we want to set this as author, so we will save. Let's also do the same thing for editor. So we will change that. Well, that was already set. So save there. And while we're here we can go ahead and just check everything else. So if we go to tags then that's great. If we go to posts. As great as well. So let's log out, and then we will log back in as the author, and then hopefully everything should be as we have planned. So the user is author, the password is password, and great, here we go. We have the Admin Home, we have the profile. So if we click on the Profile then we can edit that if we need to. Oh, that could be dangerous. That's definitely something that we need to change. Only an administrator should be able to set the role, so that's something that we will need to look into. And then if we go to Posts, we don't have any posts by an author so, we don't see anything. So the menu seems to be working pretty well. All we need is a link for logging in and logging out. And I'm going to put this inside of another action method. The reason being because this is something that we could use throughout the entire website. It's not just for the administration portion. No matter what visitor or user comes to our application, we can always display a link for logging in or logging out. So let's go back to our AdminController, and after this AdminMenu, let's add another public async. It will return task of partial view result, and let's call this authentication link. Let's create a new menu item. So, if our item equals new AdminMenuItem, let's use initializer syntax to set the route information because that is going to be the same regardless if it's the log in or log out. So, route info equals a new object where the controller is admin, and the area is admin, and then we need to check to see if the user is authenticated. So if user.identity.IsAuthenticated, then we want to display a log out link. So item.text will be log out, and then Item.Action will be logout, and then for the else statement we will display login, because if they are not authenticated, they need to log in. So login and login. And then finally, we will return a partial view. But we need one for displaying just a single link. So let's call this _menuLink and then we will pass in our item as the model. And so let's right-click and we want to add a new view. let's call it _menu link, and it will be a partial view. Now we can actually grab a lot of what we have inside of the AdminMenView. So let's just copy all of that, let's paste it, let's change the model from an IEnumerable of AdminMenu item to simply just add an AdminMenuItem, and we don't need the for each loop. But we do need the LI element and instead of item.text we have Model.Text and then Model.Item and then Mode.RouteInfo. So then we can go back to the AdminMenuView and we can do this. Instead of generating of the ActionLink we can say at Html partial, we will pass in _menulink and then the model for that partial view, which is our item. Then we can get rid of that. And then we just need to render that action. So we need to go to the _AdminLayout and we need to call RenderAction once again but instead of using the AdminMenu action, we want that new action method which is called AuthenticationLink. So we will pass that as the first argument, and the controller and area are still admin. So now let's run the application again. And whenever we go to the admin area, we will of course need to log in. But we should see a link for logging in as well. So let's go to Admin. And hopefully we will see log-in. No we don't, we have an error. And we can see what the requested URL is and that is because we did not add the allow anonymous attributes to that new method. So because we have to log-in in order to for that action method to execute. This is what we get. And it's not very pretty, is it? So let's go back to our AdminController, and let's add the AllowAnonymous attribute, that will fix that problem. So we can once again go back to admin. And then we will be asked to login. And we have our Login menu item. So let's log in as the author, once again. Specify password, and we have Admin Home, Profile, Posts, and Logout. So if we click on Logout, we're logged out. So now that we have a menu, we can go between the different parts of the Admin system a lot easier than we could before. Now we just need to add some AJAX and some other JavaScript things to make our lives just a little bit easier. And we will do that in the next lesson.

Back to the top