Routing requests through controllers in asp mvc - asp.net-mvc

I'm fairly new to MVC and I hope someone can spare some time to point me in the right direction. I was given a school assignment to create a simple wiki page where a user can search for and create articles. So I have a main index page where I have a zone for the menu, another one for the table of contents, a welcome message, and a search box for an article.
One important directive I have is to implement my own routing (without modifying the RouteConfig.cs file). Each of the following requests must call the right action method in my controller:
/ or /home or home/index: displays the welcome page;
home/index/<title of article>: displays the article;
home/index/<inexisting title>: invitation to create the article;
home/modify/title: modify the article;
home/add/title: add an article;
home/delete/title: delete the article.
For now, I have a basic HomeController with an ActionResult Index() method that returns the index view, but I am a bit stumped as to how to properly get started and the next methods I should be creating to respond to these requests, most notably, how I go about passing on the specified parameters to these controller methods.
I would appreciate any advice to kick start things.
-Jeff

Related

How to sucessfully link to another cms page in Umbraco

I am growing increasingly frustrated with Umbraco. I've been working on an Umbraco project for a little while now and I have been unable to figure out how to solve my problem (one of many).
Scenario - I have a content managed page and on this page users can search for things (these things come from an entirely different database to Umbraco). This is fine, I've created a child action which loads the form for search and created the controller method which returns the results. However, each result I need to link to another content managed page (the same content managed page for each result) that takes an ID so I can inject some dynamic data into the content managed page.
Great, I've got a method for handling this request in my surface controller and I can create an Html.ActionLink for each result that when clicked hits my controller action with the id parameter.
Problem - When each link is clicked the url that gets hit is
http://localhost:5645/umbraco/surface/{controllername}/{actionname}/?id={id}
However this request is outside the Umbraco context, so when I try to return any page with the following controller code, I get the following error:
[ActionName("ShowDetials")]
public ActionResult GetProperty(int propertyId)
{
return View("~/Views/TestView.cshtml");
}
Cannot render a macro when UmbracoContext.PageId is null.
So my initial thoughts were to have a separate controller which inherits from Umbraco.Web.Mvc.RenderMvcController and try to handle the request in there, but then this raises other issues like being unable to use #Html.ActionLink to link to a RenderMvcController, I also don't want to have two controllers to handle content from the same section.
The other issues I have is passing custom models to the view.
If anyone can help me, I would be eternally grateful.
For any developer having this same issue the only way I have been able to solve it is by having two controllers. A surface controller to handle the initial rendering of the search form and page and to display the results of the search, then a separate rendermvccontroller to handle clicking on an individual result and displaying a 'details' page.
However, this in my opinion isn't great and I would still greatly appreciate it if anyone has another solution.

Views / Controller Actions / Routes / Gobal.asax

I am new to ASP.NET MVC, coming from a web forms background in the past year and I've started working with MVC 3 recently and have questions that seem to have no good answers (none that I can find at this point) and wanted to post them here. Any help would be appreciated. My questions focus solely on controllers, controller actions, views, and the global.asax.
I understand the relationship to views, controllers, and actions within controllers. When it comes to creating a view though, does every action associated with a view that is created have to be registered in the global.asax? Example: When creating an empty project, the global.asax already creates a default route for the Home controller with an action of Index and id being optional. So, if I create another view called "AboutUs" based on the Home controller, do I need to registered that in the global.asax as a part of the Home controller?
Is there a one-to-one relationship in terms of controller / action and registration in the global.asax for routes? Can more than one controller action be added to the same statement separated by comma (like as in the using the example Home controller in the global.asax and then adding another action to the same statement or does a new statement need to be added outside of that?
Is there a "best practices" standard to use when creating controllers / views / routes?
I am asking these questions since I am converting a web forms site over to MVC 3 and not finding many good answers to my questions. Looking forward to any and all responses.
Scott Gu had a great post about how MVC routing works on his blog, you should check it out!
There to be a matching pattern in the Global.asax for every route, but not necessarily an explicit match. For your example, if you have a view called 'AboutUs', if you have a controller action named that it will just work due to the pattern matching:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
The row: "{controller}/{action}/{id}" is the pattern that is being matched by the routing engine. It says that any URL path that matches above will be sent to the correct view. For your example if you were to follow the url: Home/AboutUs then it would take you to the Home Controller, About us view, with no parameter.
Regarding your 2nd question, the controller that is selected is also part of the pattern. If you added a second controller, called Contact, and then an action called email, then this url would still follow the same pattern: Contact/Email, so you would not need to add an extra route.
Here are some other great blog posts about how MVC routing works, which will point you in the right direction. One on Asp.Net, a blog post, and on MSDN
No you don't need to register every view you create in Global.asax. The routing will take care of that as long as you follow conventions (i.e routing that is defined for you or one you define yourself should you take this path)
Not again. When you create new Action inside your controller, you typically will need to create a view for that action to render what it intended to do (ajax/json actions can serve as an exception to this rule). But again, you don't need to register anything in Global.asax those. As long as you follow the routing convention defined in that Global file.
I'd say it comes with experience with MVC. In general, every problem has its own solution, so its up to task at hand, rather than general approach. You can, however, start with the default defined for you by MVC 3: I.E. redefined routing and multiple controllers with multiple actions in each. Again, following conventions.
Hope this helps.

Getting 404 on url <site>/auction/{Some Guid}

A bit new to Umbraco, so this might be a bit of a scattered question.
I'm using 5.1.
I have a document type called Auction with a selected Template called Auction Details
My end goal is to call this controller method on my AuctionSurfaceController
[ChildActionOnly]
public PartialViewResult Detail(string id)
{
Guid auctionId;
if (Guid.TryParse(id, out auctionId))
{
var auction = auctionService.Client.GetAuction(auctionId);
return PartialView(auction);
}
return null;
}
As of this moment when I go to /Auction - it hits this method and passes in "Auction" into the method, when I go to /Auction/{GUID} i just get a 404
Could I please get some general guidance - or requests for clarifications on how to accomplish this. I would very much appreciate it
Cheers!
It sounds like the routing is working properly.
Assuming that you're executing from the context of being on an 'auction detail' page, it would then make sense that /{GUID} would serve as the id parameter. (rather than www.mysite.com/auctions/auction/id)
Sometimes this question comes up because there's more than one form on a page, and it's difficult to figure out how umbraco will know which controller Umbraco will post to. This is where the bind attribute comes into play.
However, if you want to use custom routing, because Umbraco 5 is built on MVC, you can always create your own areas and controllers.

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.)

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