ASP.NET MVC - Dynamic Url routing to Layout View - asp.net-mvc

Firstly, I don't expect to be handed an answer on my plate, however any examples you think will help me will be readily received! I am mainly struggling with how to phrase my question due to being unfamiliar with the terminology and therefore, have not found many suitable resources as of yet.
I have a .net core 2 mvc application. On one page "home/categories" I have a list of items from a database. I wish to click on one of these items for example, tents, and pass a subset of data to a generic layout view that will take data from my model I have just passed in and display a list of products.
I would like the url to be home/categories/tents. I would be using this generic view for many other categories.
I have come across articles about URL Routing. Is this what I need to be looking at to get my solution?
If not URL Routing, should I be looking at a solution involving passing parameters? For example, I see urls containing, eg, categories/?=tents?=summertents. ( I do not know what this method is called, or whether it is suitable. )
Thank you for any help.

You could definitely combine both methodologies. I would say using the URL Routing to get you to home/categories/tents and from there if you want to further filter results use parameters (home/categories/tents?=summertents).
I think this gives a clean look and ability to manage filtering parameters easier.
public class ProductsController : Controller
{
//GET /Products/Categories
public void Categories()
{
//return your list
}
//GET /Products/Tents?season=summertime
public void Tents(string? season)
{
//return a list of tents in a particular season
}
}

Related

Where should I place sub-structures within a MVC controller

I am trying to build a controller that will enable the user to add/remove subcontent to an item.
Think of it like a document where you can add different types of sections, like headlines, paragraphs, images etc. (they each have their own attributes so they are in seperate tables in the SQL)
My question is where should I put the code to handle the different types of subsections within this "document controller"?
They are all attached to this "document"/entity through database relations, but should I make a "crudl" controller for each type or should I do a base kinda crudl and then let them all inherit this?
I've looked into "Models" and "service layers" - is that the right way to do it?
I am still rather new with MVC, using C# and ASP.net I was hoping for someone to give me a hint in the right direction.
Nb. please let me know if I should rephrase the question. Didn't know what to ask to get the right answer here.
Specs: I use EF 4.x and MVC3 will upgrade to latest when available, if needed.
In hope of some clever answers or guidance. Thanks in advance people. And yes, I have tried to Google too. Don't know what to search for, so I come here.
where should I put the code to handle the different types of subsections within this "documentcontroller"?
The code for this would ultimately go into a controller action which you then handle and update the database accordingly. There are multiple ways of doing this, you could be generic e.g.
[HttpPost]
public ActionResult AddSection(string type)
{
switch (type)
{
case "HEADING":
// add new heading to database
case "PARAGRAPH":
// add new paragraph to database
}
return View(type);
}
Or you could be specific e.g.
[HttpPost]
public ActionResult AddHeadingSection()
{
// add to db
return View("Heading");
}
[HttpPost]
public ActionResult AddParagraphSection()
{
// add to db
return View("Parapgraph");
}
The above is just really pseudo code to give you a rough idea of how you could do it with minimal effort. IN a real life situation you will probably be posting extra information along with it e.g. AddHeadingSection(HeadingModel model). It's really up to you how you go about implementing this.
Also, you might want to consider using AJAX over full postbacks it would make your app a bit slicker.

Best way to add filter to URL in .NET MVC

I'll try to make this as concise as possible.
Webpage contains a table that allows for filtering and sorting
Changes to filtering and sorting should be reflected in the URL so the user can bookmark or share filtered views.
The question is: What is an effective convention of allowing all of the sort and filter syntax to be part of the URL and easily interpret/use it on the server without having to write a bunch of custom code that interprets it?
I've been doing some research and I came across the OData URI conventions and I like the way they do things.
http://www.odata.org/developers/protocols/uri-conventions
More research shows the the MVC 4 Web API allows for use of that convention by returning an IQueryable. This looks fantastic except for one part... I'm not implementing a RESTful API at this point and that's all it seems to work with. So how can I use something like OData and still return a View or PartialView? Is there something that will parse the OData URI convention into a C# object?
If anyone has any insights into this problem or suggestions, I'm all ears.
As for the url convention part of your question, I think you have answered your own question with OData. As for getting this data into a C# object I would use the following approach:
Use an action filter to interperet the url parameters and parse them into a c# object.
In your action filter add the url parameters to the route data and the c# object will be available in your action.
ASP.NET MVC Pass object from Custom Action Filter to Action
Take a look at the Telerik MVC grid, they use a GridAction action filter that does pretty much what you are asking.
I would look at custom model binding. A good overview can be found here: http://weblogs.asp.net/nmarun/archive/2010/02/25/asp-net-mvc-model-binding.aspx
It's typically used for POST requests with forms but there's no reason why you can't use it for GET requests too.
Basically, your approach should be to:
Create a new Model class with your filter/sorting parameters as properties:
public class TableParameters {
public string TableFilter { get; set; }
}
In your Controller's Action, add the model as a parameter
public ActionResult TableAction(TableParameters parameters) { /* Action logic */ }
Set your parameters in the URL by saying:
/Controller/TableAction?TableFilter=[your-filter-string]
The parameters object in your action will have the property populated with the value from the query string.

ASP.NET MVC - CMS Questions

I'm looking at developing an application that will include a CMS. I'm a seasoned web forms developer but only really just moving into MVC.
I have a couple of questions that I hope some of you guys can answer:
First, my current web forms CMS allows users to create a page, and then "drop" any number of user controls onto that page they have created. The way I do this is to create an entry in the DB together with the path and then use the LoadControl method.
I can see I can do this with partial views, but partial views have no code behind. If I've potentially got 100 controls that people can drop onto a page, does this mean that the ViewBag in the controller needs to cater for all 100 controls just in case they are used on the view? For example, a web forms user control will contain logic: rptItems.DataSource = blah; rptItems.DataBind()
With MVC, I'm assuming that logic will be in the view controller and the view would access it by the ViewBag? I'm a little confused at how to do this.
Secondly, how would you handle deep routing?
EG:
Store/Products/Category is fine, but what about Store/Products/Category/Delivery/UK ? Would I need to set up a route in global.asax for each route I need? In web forms, I just called the ReWritePath method and handled the routing myself using regular expressions.
Thanks for the time to read this, and hopefully answer some of my queries
For your second question, (ie, "deep routing"), you can handle this within your controller instead of adding real routes. Each part of the url is available via the RouteData.Values collection inside of your controller action. So, your route may look like
~/Store/Products/Category/{*params}
Assuming typical route configuration, this would call the Category(...) action method on ~/areas/store/controllers/storeController, which could then grap delivery and uk from the RouteData.Values collection.
There are a lot of other approaches to this - storing routes in a database and using associated metadata to find the correct controller and method - but I think this is the simplest. Also, it may be obvious, but if you really only need two parameters beyond 'Category' in your example, you could just use
public ActionResult Category(string category, string region)
{
...
}
and a route:
~/store/{controller}/{action}/{category}/{region}/{*params}
Delivery and UK would be mapped to the the category and region parameters, respectively. Anything beyond uk would still be available via the RouteData.Values collection. This assumes that you don't have more specific routes, like
~/store/{controller}/{action}/{category}/{region}/{foo}/{bar}/{long_url}/{etc}
that would be a better match. ({*params} might conflict with the second route; you'll have to investigate to see if it's a problem.)
For your first question:
You can dynamically generate the view source and return it as a string from the controller, eliminating the need to pass a lot of stuff via ViewBag. If a virtual page from your CMS database requires inclusion of partial views, you would add the references to those components when generating the page. (This may or may not address your problem - if not, please provide more information.)

ASP.Net MVC: Creating an Area for json requests

Just wondering what people think about creating an area to hold/manage json based requests (note I am thinking mostly get data not post data). I know its not your typical use of an area (i.e. normally you would create a different area for blog vs forum) but I am getting to the point where my project isn't huge but I definitely have a a lot of json stuff which seems to be confusing the issue and is making things look "unclean".
For instance, at the bottom of each controller is where I am putting json actions and so that they don't get mixed up with the other actions I prefix them with json - I shouldn't have to do this... Also I have specific view models for json which I have to prefix with json as well... etc, etc.
It would seem much cleaner to have them off in their own area and be able to drop the json prefix all together and have that defined by the area... what do you think or is this a bad idea?
Cheers
Anthony
I think it's a good idea. Having an asynchronous area where all controllers implement only asynchronous actions will certainly clean up your code. The problem will come when your project does become so big you want to expand into regular areas, then you'll end up with some naming conventions that might end up a bit messy.
You could also just create a separate controller for your json actions. I think this makes more sense than creating an area. Do you need json specific views, content, model etc or just some asynchronous actions?
I think that it's not nessesery to create separate area or even separate actions. If the actions return the same data and differ only in the type of the request - ajax or non-ajax you can just check what is the request and use the corresponding data format.
public ActionResult Index()
{
MyViewModel model = DataAccess.GetMyViewModel(); // Data access code
if (Request.IsAjaxRequest())
{
return Json(model);
}
else
{
return View(model);
}
}

MVC: How to work with entities with many child entities?

In the current examples on ASP.NET MVC I see quite basic entities, with simple CRUD methods.
But I'm not sure about what to do with more advanced models. Let me give an example:
We have a garage website. The garage has:
Inventory with carparts
Employees
Customers
Cars that consists of all cars that are/were in the garage
Now lets take the car, the car might have a collection of employees that worked on the car (derived from the original employee class, adds some extra props that tie him to the car), a collection of carparts that have been replaced (also derived, adds for example SerialNr, and ReplacementDate prop) , and of course a customer prop of the customer whoe owns the car.
Now in rest I would like to see the following:
/cars/423 [get] //show car # 423
/cars/423/edit [get] //shows the edit form (ajax enabled, so also shows the other props)
/cars/423/carparts [get] //gets the carparts inside the car
/cars/423/carparts/32/edit [post] //updates that specific carpart inside the specific car
/cars/423/employees [get] //gets the employees who worked on the car
/inventory [get]
/inventory/1234/edit [get] //gets the update form for carpart with ID 1234
/employees [get] //gets all the employees in the company
So how would I build my Controllers? Should I add all those CRUD methods for the child elements inside the CarsController? Doesn't that make a very fat controller because of the tens of methods (this model is overly simplified, the car has many more parent-child relationships)? Or should I create a EmployeesInCar controller (seems bad)...
Thanks a lot.
EDIT:
First of all the example is hypothetical only, just an example.
If I follow the suggestion I would have a CarController which only handles cars. And my PartsController would handle only Parts. But we have two sets of Parts, a general one (for the inventory); and we have a Part inside a car, which derives from the general one, but adds properties such as SerialNumber and ReplacementDate.
So my Parts controller becomes quite fat, for the example let's call the entities: GeneralPart (in inventory) and SpecificPart (the derived class, with the extra properties)
Index -> Returns all GeneralParts in inventory.
IndexByCar(int id) -> Return all SpecificParts by Car.
etc. etc.
Because each action deals with either a General Part or a Specific Part. The same is for employees, we have the base employee class, and a specific one, with extra properties.
If you wish to use the kinds of paths you provided in your example, then it sounds like you should learn how to use the Routing engine in .NET 3.5. You should be able to use the kinds of urls you need, but you will need to create several custom routes and probably a custom route handler to accomplish it. The Routing engine in .NET 3.5 is very flexible and was not designed specifically for MVC...its actually very generic and can provide a very broad, probably unlimited range of url rewriting.
Its a bit late where I live, so the example I was trying to write just isn't forming. :P Suffice to say, a custom route handler and some new route mappings should get you where you need to be.
EDIT: This may be of help:
http://codingcockerel.co.uk/2008/05/26/custom-routing-for-asp-net-mvc/
EDIT 2:
I left out controllers before. The routing just gets you the ability to use the kinds of URLs you want. And thats a good thing...the kinds of URL's you proposed will provide a better SEO experience long-term. As for organizing your controllers, I recommend keeping it simple:
/Controllers/CarsController.cs
/Controllers/PartsController.cs
/Controllers/EmployeesController.cs
/Controllers/InventoryController.cs
Your routes would match your url patterns, and turn them into a proper route to your controller, taking the ID's and matching them to the parameters of your actions.
EDIT 3:
So, now that I understand your question more fully, I hope I can answer it better. Generally speaking, I think controllers should map 1:1 with your entities. If you have a GeneralPart, then you should have a controller dedicated to managing general parts. If you have CarPart, then you should have a controller dedicated to managing car parts. If CarParts are GeneralParts, and they can behave like GeneralParts in some cases, then it is probably best to have those management aspects on the GeneralPartsController, unless that management deals with any special attributes of a CarPart...in which case management should be delegated to CarPartsController. It is kind of elegant how polymorphism plays into controller organization, and how the "is a" relationship allows you to reuse controllers to manage multiple types.
To be honest, you have a fairly complex scenario I havn't directly encountered in my time working with ASP.NET MVC. I try to avoid such scenarios as much as possible, because they give rise to complicated questions like this that tend to be subjective in their answers. Ultimately, you should organize your controllers in a way that makes logical sense to how they are used, how they map to your entities, and how well they organize the behavior you are interested in exposing. Sometimes, it isn't logical to map all of your controllers to a single entity. Sometimes you need to have a "composite" controller that deals with actions that operate on multiple entities at once, or graphs of entities. In these cases, its probably best to have controllers dedicated to those particular behavioral groups, rather than trying to find one entity-specific controller that "sorta fits".
Your design should initially focus on the entities. You have car, employees and inventory. Write a controller for each one of these. That will give you the basic routes:
/cars/{action}/{id}
/employees/{action}/{id}
/inventory/{action}/{id}
From here you should be able to write a new route with a custom route constraint with the following structure:
/cars/{id}/part/{id}/
This is also slightly better than /cars/{id}/carpart/{id} because the word car in carpart is redundant. /car/.../part/ indicates that part is for a car.
Thinking about things like these for URI design is really important early on because changing the URI design later will break search engine indices, bookmarks and links.
Your "CarPart" entity (class CarPartModel) can be in "stock" state (class StockCarPartModel : CarPartModel) or "replaced" state (class ReplacedCarPartModel : CarPartModel). Then:
GET to /carpart/index should return all entities (CarPartModel)
GET to /carpart/replaced should return replaced parts (ReplacedCarPartModel)
GET to /carpart/bycar/{id} should return parts, related to specific car (ReplacedCarPartModel)
GET to /carpart/inventory should return parts in stock (StockCarPartModel)
This all is handled by "Default" route and in your CarPartController your have actions:
public ActionResult Index() { ... }
public ActionResult Replaced() { ... }
public ActionResult ByCar(string carId) { ... }
public ActionResult Inventory() { ... }
I think your controller is not fat. It is normal for controller to deal with Model inheritance. The main complexity will be in your ViewModels and Views
You don't need to have too many things going on in a controller.
Think of a controller as a class that determines what the user wants and what it should see in the end.
What user wants is determined by the ASP.NET MVC engine automatically for you, with the help of the routes you defined in the Global.asax file. Then the controller should decide what view the user should see as a result of the request he/she made.
So for your application things would go something like this :
Global.asax
routes.MapRoute("Cars", "cars/{id}/{action}",
new { controller = "Cars", action = "Details", id = "" } );
//This route should give you the URLs you listed on your question
CarsController.cs
public class CarsController : Controller {
//this action will be called for URLs like "/cars/423"
//or /cars/423/details
public ActionResult Details(int id) {
//You would most likely have a service or business logic layer
//which handles talking to your DAL and returning the objects
//that are needed for presentation and likes
Car car = SomeClass.GetCar(id);
if (car == null) {
//if there's no car with the ID specified in the URL
//then show a view explaining that
return View("CarNotFound");
}
//if there's a car with that ID then return a view that
//takes Car as its model and shows details about it
return View(car);
}
//this action will be called for URLs like /cars/423/edit
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Edit(int id) {
//again get the car, show an edit form if it's available for editing
}
//this action will be called for URLs like /cars/423/edit too
//but only when the request verb is POST
[AcceptVerbs(HttpVerbs.Post), ActionName("Edit")]
public ActionResult Save(int id) {
//save the changes on the car, again using your business logic layer
//you don't need the actual implementation of saving the car here
//then either show a confirmation message with a view,
//saying the car was saved or redirect the user to the
//Details action with the id of the car they just edited
}
}
So basically this is how you would set up your controller(s) for an application like that.
I would recommend using Restful Routing for ASP .NET MVC:
https://github.com/stevehodgkiss/restful-routing

Resources