Administration Area in Asp.Net MVC - asp.net-mvc

My question may be obvious but I'd like to build a well-designed web application.
As for any administration area, the admin should be able to list/create/delete/modify users, articles, posts, etc...
I'd like to know what is the best way to design the application.
Should I create a controller for each one of those items (/Users/Create/id or /Posts/Delete/id), or create all of the action in my Administration Controller (/Administration/CreateUser/id or /Administration/DeletePost/id) ?

You should write a separate controller for each entity to keep a clean separation of concerns for your controller classes. If you only have one controller, then you will only have one Views directory with dozens of views, and your controller will contain dozens of methods, and that will soon become unmanageable.

The answer depends on how much functionality will be in the controllers. Just start of with one controller and if it gets too much split it into a few.
The great thing about MVC is where you put things in your controllers doesn't have to have any effect on the URLs. you can very easily map /Users/Create to e.g. UserAdminController class.

I would just build a new MVC website that handles the administration.
You have a more flexible solution as long as you've separated the data and the business logic in different assembly's. You could then publish your website to a subdomain, admin.yoursite.com for example. That way you don't have to mess with your routes and you can keep them in separate views which imho is the most elegant solution.
Pro's and Con's would be nice to hear.
I'm working on a project which will need the same administration site but haven't got that far yet so this question interests me a lot.

I'm currently using ASP.NET for a large client.
The approach I've adopted is to put the functionality of the action into another class.
Example
I am writing an administration section also. There will be one Administration controller (our admin section is small, if it was larger I would change the routing to allow more controllers, for now we are using the out of the box configuration). If I create an "EditUser" view. I will also create an "EditUserAction" class. All EditUser code will go into the class. I construct the EditUserAction class in the Administration controller class in the Edit User method. This removes all the action specific code out of the Controller class. This way all the action specific code is either in the action method or in the action class. Otherwise, the controller would quickly become overrun with code from various actions. The controller class would balloon to an unmanageable mess in short order.
Class examples
public class Administration: Controller
{
public ActionResult EditUser(string userId)
{
EditUserAction action = new EditUserAction();
}
}
public class EditUserAction
{
public void Save(User user)
{
//save code here
}
}
I hope this explanation is clear. If it's not let me know and I'll clarify.
To answer your question I am doing it the latter(/Administration/CreateUser/id or /Administration/DeletePost/id).

You could use DynamicData for this. It isn't MVC but it can be used together with it and it is really easy to setup and use.

Here is another way of asking my question.
A part of my Master Page:
<% if (!String.Equals(ViewContext.RequestContext.RouteData.GetRequiredString("controller"), "Administration")) { %>
<div>
<!-- Some Code -->
</div> <% } %>
As you can see, in my master page, I'd like to display some part of the page, depending on the user working on the administration area or not.
It works pretty well with only the Administration Controller (/Administration/CreateUser/id)... but it becomes a big mess when I use different controller as User or Article (/User/DeleteUser/id or /Article/Details/id).
I'd prefer to use one controller per entity, but I can't find a way to bond this approach with multiple controllers.

I suggest to use this solution.
But I changed definition to this:
public ThemedViewEngine()
{
base.MasterLocationFormats = new string[] {
"~/Views/{1}/{0}.master",
"~/Views/Shared/{0}.master",
"~/Themes/{2}/Views/{1}/{0}.master",
"~/Themes/{2}/Views/Shared/{0}.master",
"~/Themes/Default/Views/{1}/{0}.master",
"~/Themes/Default/Views/Shared/{0}.master"
};
base.ViewLocationFormats = new string[] {
"~/Views/{1}/{0}.aspx",
"~/Views/{1}/{0}.ascx",
"~/Views/Shared/{0}.aspx",
"~/Views/Shared/{0}.ascx",
"~/Themes/{2}/Views/{1}/{0}.aspx",
"~/Themes/{2}/Views/{1}/{0}.ascx",
"~/Themes/{2}/Views/Shared/{0}.aspx",
"~/Themes/{2}/Views/Shared/{0}.ascx",
"~/Themes/Default/Views/{1}/{0}.aspx",
"~/Themes/Default/Views/{1}/{0}.ascx",
"~/Themes/Default/Views/Shared/{0}.aspx",
"~/Themes/Default/Views/Shared/{0}.ascx"
};
base.PartialViewLocationFormats = new string[] {
"~/Views/{1}/{0}.aspx",
"~/Views/{1}/{0}.ascx",
"~/Views/Shared/{0}.aspx",
"~/Views/Shared/{0}.ascx",
"~/Themes/{2}/Views/{1}/{0}.aspx",
"~/Themes/{2}/Views/{1}/{0}.ascx",
"~/Themes/{2}/Views/Shared/{0}.aspx",
"~/Themes/{2}/Views/Shared/{0}.ascx",
"~/Themes/Default/Views/{1}/{0}.aspx",
"~/Themes/Default/Views/{1}/{0}.ascx",
"~/Themes/Default/Views/Shared/{0}.aspx",
"~/Themes/Default/Views/Shared/{0}.ascx"
};
}
Default theme is default so it is required to exists.
Structure of directory will be:
Content
Themes
Default
Content
Views
Home
Blog
Whatever should be skinned
OtherTheme
Content
Views
Home
Blog
Whatever should be skinned
Views
Articles
Posts
Users
Settings
Other Administration stuff

It depends on the scale size of your admin area,
I suggest you consider to do the following (or maybe document it a bit)
Consider how many entities you want to manage independently,
Consider how many actions each one will have,
Check that is there any dependency between your application and admin area (user access, for user friendly URLs )
then you can specify which approach can help you, Having one admin controller, admin actions in entity controllers, or defining a new Admin project in case of large functional applications.
*If the project scale is growing fast and soon it needs large scale, I would choose third one - having a new admin mvc project.
I hope it help you decide.

Related

ASP.NET WEB API Multiple Interfaces

I am designing ASP.NET WEB API service with two interfaces. First interface is read-only and second one is admin interface (to be used with MVC app) with full CRUD support. Does anyone know where I can get more information on such setup, any tutorials, walk thought, sample design document?
Also does it worth splitting these into two interfaces or keep them in same? But problem is that in read-only I expose 2-3 properties for every object while for admin there are 10-15?
Similar setup for WCF or design spec will do.
If I understand what your wanting to do, may I suggest rather than having one URL, i.e. \dataStuff\dataView split off into another view, maybe \dataStuff\edit\ which only admin's have access to, can be done like so:
[Authorize(Roles = "Administrators")]
public ActionResult edit()
{
return View();
}
then next to each data element that your viewing add the following to ONLY admin's through use of User.IsInRole
#foreach (var item in Model.dataTable)
{
#*
write a value from the data table here
*#
#Html.ActionLink("edit", "edit").If(User.IsInRole("Administrators"))
<br/>
}
obviously you don't have to display your data like this, I'm just showing that you add to the end of each element of the database an edit ActionLink IF the user is admin.
This allows your admin to view data like a user and also have the added functionality they need. Code re-use is better than a single view which has two states, Admin and non Admin.
Sorry if this isn't the best explanation, fairly new to MVC
Seems like this concept is sometimes called CQRS.
Sample: http://martinfowler.com/bliki/CQRS.html

ASP.Net MVC dynamically switching Views

I have an ASP.Net MVC 4 application where the user can choose a theme or a design of for their hosted one-page site (within this application). At first, I thought to do this with the built-in Areas but due to some application restrictions I've decided not to use that method. The way I thought to do it (which so far works) is to send the user to the index action of the controller, there find out which theme they have chosen and then return the appropriate view. this way I don't have the action name on the url which is nice since the url needs to be simple like: abc.com/cb/websiteID. btw, every theme/design has one view in the folder.
For some reason this method does not sit well with me and I think there should be a better way of doing this. Is there a downfall to this? Is this method a bad practice? is there a better way?
If I've left out a detail, please let me know and I'll do my best to address it.
Do you have a limited set of themes, which your users can choose from?
If so, I would consider to have a layout-per-theme instead, have a single view and dynamically switch layout based on params...
//in your controller
public ActionResult(int id) {
string layoutForThemeName = SomeService.GetThemeForUser(id);
ViewBag.LayoutName = layoutForThemeName
}
// in your view Index.cshtml
#{
Layout = ViewBag.LayoutName;
}
Do not forget that Razor let you inherit one layout from another, so you could event create base layout with script references etc. and layout for every of your themes.

asp.net MVC - complex example?

We're evaluating asp.net MVC and are looking for some more complicated examples over and above NerdDinner.
Specifically, in a more complex web app, I might have a navigation bar (including primary nav, a search box and a log-in status display), a main content area, a sub-content area (including related content) and a footer. In MVC a controller returns a ViewModel (not a View if I'm thinking that I want to de-couple my Controller from my View) - would my ViewModel have to have properties to cover each and every aspect of the "page" I am aiming to render as output?
If this is unclear, I may be able to re-word my question.
BTW - I know this site is built using MVC. I'm after downloadable examples.
Thanks in advance.
Take a look at CodeCampServer.
Edit: With reference to your query about view models, this isn't the perfect answer to it but thought I'd draw attention to AutoMapper (used by CodeCampServer) which can assist with auto mapping data between models and view models which is a real time saver. Also worth considering the concept of Input Builders (there's some available with MVCContrib and also some in ASP.NET MVC 2) which will also reduce the amount of data you have to pass into a view by encapsulating common functionality across the board.
There's a good video on the ASP.NET MVC 2 offering here: http://channel9.msdn.com/posts/Glucose/Hanselminutes-on-9-ASPNET-MVC-2-Preview-1-with-Phil-Haack-and-Virtual-Scott/.
Here ya go:
<% Html.RenderAction<LayoutController>(c => c.SearchBox()); %>
<% Html.RenderAction<LayoutController>(c => c.NavBox(Model)); %>
Put these in your masterpages, or on specific views for sidebar widgets, and abstract their logic away from your controller/viewmodel you are working on. They can even read the current RouteData (url/action) and ControllerContext (parameters/models), cause you are dealing with ambient values in these objects - and executing a full ActionMethod request!
I blogged about this little known secret here. I also blogged about where this is located, which is the ASP.NET 1.0 MVC Futures assembly that is a seperate add-on from Microsoft.
Steve Sanderson actually gives gives examples of complex logic and application building in a book I have called Pro ASP.NET MVC (shameless plug, I know, but it's what you are looking for in your question), where he actually uses the RenderAction! I made the blog post, before I even read the book so I am glad we are on the same page.
Actually, there are dozens of extensions and functionality that was developed by the ASP.NET MVC team that was left out of the ASP.NET MVC 1.0 project - most of which makes complex projects much more managable. This is why more complex examples (list above in most people's answers) have to use some type of custom ViewEngine, or some big hoop jumping with base controllers and custom controllers. I've looked at almost all of the open source versions listed above.
But what it comes down to is not looking at a complex example, but instead knowing the ways to implement the complex logic that you desire - such as your Navigation bar when all you have is a ViewModel in a single controller to deal with. It gets tiring very quickly having to bind your navbar to each and every ViewModel.
So, an example of these is the Html.RenderAction() extension (as I started off with) that allows you to move that more complex/abstracted logic off of the viewmodel/controller (where it is NOT even your concern), and place it in its own controller action where it belongs.
This littler baby has saved MVC for me, especally on large scale enterprise projects I am currently working on.
You can pass your viewmodel into the RenderAction, or just render anything like a Footer or Header area - and let the logic be contained within those actions where you can just fire and forget (write the RenderAction, and forget about any concern of what it does for a header or footer).
You are welcome to take a look at good.codeplex.com
It has much of what you seek above but there is work to be done! However, after you've looked I'd be happy to field questions on it here or over on codeplex.
This is what mygoodpoints.org is currently running on.
would my ViewModel have to have
properties to cover each and every
aspect of the "page" I am aiming to
render as output?
Yes. There is another option with RenderAction, but apart from that a ViewModel in generall is often big and you have to find a good way to fill it. I admit this sounds like a trouble spot first.
AtomSite is a blog engine written using ASP.NET MVC
As far as I know, a Controller directly returns a View and can pass data to the View using either the ViewData or the Context.
The former is just a loose bag of various bits of data, whereas the latter is a specific type.
The ViewModel would be passed to the View as the Context (and the mark-up of the View would be strongly-typed to the type of ViewModel it expects).
That's my 2c worth :) Hope that helped-- sorry I could not include any downloadable examples.
To automatically pass data to all views, you can make your own controller class and use that:
Example
public class MyController : Controller
{
private User _CurrentUser;
public User CurrentUser
{
get
{
if (_CurrentUser == null)
_CurrentUser = (User)Session["CurrentUser"];
return _CurrentUser;
}
set
{
_CurrentUser = value;
Session["CurrentUser"] = _CurrentUser;
}
}
/// <summary>
/// Use this override to pass data to all views automatically
/// </summary>
/// <param name="context"></param>
protected override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
if (context.Result is ViewResult)
{
ViewData["CurrentUser"] = CurrentUser;
}
}
}

ASP.NET MVC How many levels deep should a view or URL be?

I am still learning ASP.NET MVC. With webforms, I would create a new folder let's call it admin. In there I might have many pages for create_product, edit_product, etc. So the URL might look like http://somesite.com/admin/create_product.aspx.
But with MVC it is a little different. I am trying to see what would be the best way to do this.
Would doing http://somesite.com/admin/product/create be right? Or should it just be http://somesite.com/product/create? If I do it as the first way, do I put everything in the "admin" controller or should it be separated into a "product" controller?
I know this is probably subjective or personal choice, but I would like to get some advise.
Thanks.
Part of the benefit of ASP.NET MVC (and more generally, the URL Routing Engine common to all of ASP.NET in .NET 3.5 SP1) is that the URLs can be flexibly configured to map to any folder / file structure you prefer. That means it's much easier than it was in the days of WebForms to modify your URLs after you've started building your project.
To your specific questions:
One Admin Controller vs. Product Controller - In general, the guidance is to keep controllers focused so that they are easier to test and maintain. For that reason, I would suggest using a single controller per object type (like Product) with your CRUD actions. Examples in your case:
/admin/product/create
/admin/product/edit/34 or /admin/product/edit/red-shoes (if name is unique)
In either case, the Create, Edit, Deatils actions will all be in the ProductController. You may just have custom routes for the "admin actions" (like Create and Edit) that limit their usage (and add the "admin" text to the URL), and then the Details action would be usable by all visitors to your site.
Securing Admin Views - One important fact to remember with MVC: all requests go directly to controllers, not views. That means the old "secure a directory with web.config" does not apply (usually) to MVC for securing your Admin. Instead, you should now apply security directly to the controllers. This can easily be achieved by using attributes to Controller classes like:
[Authorize] - Just checks that the user is logged-in
[Authorize(Roles = "Admin")] - Limit to specific user roles
[Authorize(Users = "Joe")] - Limit to specific users
You can even create a custom route for "Admin" views in your site and limit access to those views by enforcing your authorization check in the URL routing, like this:
routes.MapRoute(
"Admin",
"Admin/{controller}/{action}",
new { controller = "Product", action = "Index" },
new { authenticated= new AuthenticatedConstraint()}
);
Where AuthenticatedConstraint looks something like:
using System.Web;
using System.Web.Routing;
public class AuthenticatedConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return httpContext.Request.IsAuthenticated;
}
}
Good details on Stephen Walther's blog:
ASP.NET MVC Tip #30 – Create Custom Route Constraints
For admin stuff, just mark with [Authorize] attribute. To ensure only admins can use it, do something like [Authorize(Roles = "Admin")]. Check out this question
Also, /product/create is most common, I think :)
I3Dx definitely has the right guidance for the Authorize attribute, this is essential for keeping controller secure, you can apply to a controller or individual actions.
As far as the URL depth, I would not worry about the depth, I would be more concerned that the route made logical sense for example:
domain.com/admin/products/edit/1
domain.com/admin/groups/edit/1
domain.com/products/view/1
domain.com/groups/view/1
This way you know what is happening with each route. it is obvious that one is an admin and one is an end user.
The easyest way to check is to get someone to read your URL and ask them what they would expect to see.
Hope this helps.
OH and one last thing, for client side routes we often use "slugs" rather than ids so that it is more readable. So when someone creates a product we slugify the name so it can be used in the route such as:
domain.com/products/view/big-red-bucket
rather than
domain.com/products/view/1

Where to apply logic for a sidebar control in ASP.NET MVC

Take the example of wanting to have a "Latest news items" sidebar on every page of your ASP.NET MVC web site. I have a NewsItemController which is fine for pages dedicating their attention to NewsItems. What about having a news sidebar appear on the HomeController for the home page though? Or any other controller for that matter?
My first instinct is to put the logic for selecting top 5 NewsItems in a user control which is then called in the Master Page. That way every page gets a news sidebar without having to contaminate any of the other controllers with NewsItem logic. This then means putting logic in what I understood to be the presentation layer which would normally go in a Controller.
I can think of about half a dozen different ways to approach it but none of them seem 'right' in terms of separation of concerns and other related buzz-words.
I think you should consider putting it in your master page. Your controller can gather data (asynchronously, of course), store it in a nice ViewModel property for your view (or in TempData) and then you can call RenderPartial() in your master page to render the data.
The keeps everything "separate"
http://eduncan911.com/blog/html-renderaction-for-asp-net-mvc-1-0.aspx
This seems to address the question - even using the instance of a sidebar - but using a feature not included with MVC 1 by default.
http://blogs.intesoft.net/post/2009/02/renderaction-versus-renderpartial-aspnet-mvc.aspx
This also indicates the answer lies in RenderAction.
For anyone else interested, here's how I ended up doing it. Note you'll need to the MVC Futures assembly for RenderAction.
Basically you'd have something like this in your controller:
public class PostController
{
//...
public ActionResult SidebarBox()
{
// I use a repository pattern to get records
// Just replace it with whatever you use
return View(repoArticles.GetAllArticles().Take(5).ToList());
}
//...
}
Then create a partial view for SidebarBox with the content you want displayed, and in your Master Page (or wherever you want to display it) you'd use:
<% Html.RenderAction<PostController>(c => c.SidebarBox()); %>
Not so hard after all.
You can create a user control (.ascx) and then call RenderPartial().
Design a method in your controller with JsonResult as return type. Use it along with jQuery.
Use RenderAction() as suggested by elsewhere.
News section with ASP.NET MVC

Resources