UrlMapping :: View attribute in matched block ignored - grails

Given URI /admin/article/index, why would this url mapping not work?
"/admin/$controller/$action?/$id?"{
view = "/admin/index" // no dice, ignored
//action = "foo" // uncommented, this is picked up
}
I'd like for all admin controllers to use the admin view by default (and not have to render the view in each action of each controller). Same goes for "/account/$controller/..." and any other site module that should use a common view.
Perhaps there's another way to achieve this, but assumed that UrlMappings is the place to do it...

Looks like you are trying to do something very different than what you wrote.
You already have the action mapped in the base URL mapping, and the view is automatically selected based on the controller, so you need to define different mappings for those views that don't have a controller, and yet another mapping for items with a default action of foo. The default action on controllers is index, though, so there is usually no need to supply a default action without also specifying a controller.
I think you are, in general, misunderstanding how an MVC framework works. The controller should not be rendering anything, and the views should be specific to the controller/action. If multiple controllers are rendering the exact same view, I'd be willing to bet that either the controller is rendering HTML or the view is overly complicated.
You should look into Layouts with SiteMesh, which allows you to create default template structures, then just have the specific content change through views.

Related

sitecore mvc ControllerRenderer and the context item Layout

Just playing around with Sitecore 7 and MVC, and I try to get the rendering basics working.
So far, I have been able to create a View Rendering (and mapped to the relevant .cshtml file) within the Renderings section, and applied these to the presentation details of the item (in much the same way you do with ASPX Layouts/ASCX Sublayouts).
I have also been able to map the Item to a controller (using the Controller and Action fields on the item), have the Index action on the controller (inherited from SitecoreController) return the view ~/Views/Home/Index.
The issue I can't seem to wrap my head around is merging the two rendering methods. I want to be able to create controllers that map to an Item, but render the item using the ViewRenderer, rather than using the default MVC conventing of return View(), so that I can:
Specify the location of the view files within a multi-site environment by setting the path parameter of the rendering; and
Have content authors/managers manage the renderings the way that the Layout/Sublayout does with place holders.
Does anyone know of a way that this can be achieved?
Have you taken a look at Controller Renderings in Sitecore MVC? These give you the ability to map a controller class to a Sitecore presentation item that can be statically or dynamically bound to your layout details.
This post has a reasonable overview of how to get started with controller renderings.
As for specifying the location of View files for multi-site environments you can pass the path to the razor file into the Controller View method, for example:
return View("~/Areas/SampleArea/Views/SampleArea/Index.cshtml");
I hope this helps.

MVC controller vs. out-of-box Sitecore Controller

I've been reading a lots of blogs on MVC provided here:
http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog.aspx
However, I am not being able to explain/convience myself/team:
When to use custom control vs. out of box site core controller?
When does the Out of Box Controller gets invoked?
Benifit of custom control vs. out of box controllers?
If we go with out of box, should we include all business logic on Views. Is this testable?
I also looked at below and still not certain:
https://bitbucket.org/demoniusrex/launch-sitecore-mvc-demo
Any help will be appreciated.
Whilst I broadly agree with Kevin Obee's statement I think it's worth reminding ourselves that controllers are being used in two distinct roles in Sitecore:
Page level controller (invoked by item route)
Component level controller (invoked by redering mechanism)
When to use: Custom controller / default Sitecore controller
Page level controller
Any route that matches an item path will by default use the Index action on the Sitecore.Mvc.Controllers.SitecoreController. This action will return a ViewResult based on the layout configuration of the item.
If you have a need for changing this behaviour (e.g. something that impacts the entire page) you can specify a custom controller and action on the item (or the Standard Values for the item). For the custom controller you can either roll your own or subclass the default controller.
Component level controller
For ViewRendering Sitecore renders the Razor views without the need for a specific controller (well I guess it's the page level controller that is in play - but just imagine that Sitecore provides a default controller that gets the model using the mvc.getModel pipeline and feeds it to the Razor view).
For ControllerRendering you provide a custom controller that can execute logic (see Kevin's answer) and provide a model for the view. There is no benefit from subclassing Sitecore.Mvc.Controllers.SitecoreController.
When are controllers invoked
Page level controller
The action on the page level controller is invoked by the routing engine.
Component level controller
The action on a ControllerRendering is invoked as the page view renders.
Benefit of using: Custom controller / default Sitecore controller
The benefit of a custom controller over the default Sitecore controller is that you are in control of the logic. The benefit of using the default Sitecore controller is that Sitecore provides the logic for you.
Should we include all business logic on Views
No. (See Kevin's answer)
My personal view is that the business logic should go in command and query classes that are invoked from the controller class. From these calls you can assemble a strongly typed view model which gets passed to a dumb razor view for rendering.
Ensure that any services that the controller relies on are passed into it via constructor injection using contracts (interfaces) instead of concrete classes and you should end up with solution that is unit testable.

ASP.Net MVC: same action name in different controllers

I have 2 controllers which are SearchController and SearchByStaffController respectively. They are very similar and both have an action with action name "Search". When I call View("Search") in their common super class, the confusion comes. Only the "Search" view with SearchController is rendered.
Does the MVC framework get only the first view that matches the name and ignore the rest?
I tried to pass the view path in View() and it worked. Would there be any side effect for doing so? I searched over the web and seems no one has done this before.
Thanks!
Does the MVC framework get only the first view that matches the name and ignore the rest?
Yes. The routing rules are aparsed (top to bottom) and when a rule is matched all end.
I tried to pass the view path in View() and it worked. Would there be any side effect for doing so? I searched over the web and seems no one has done this before.
You can but I don't like that because MVC is based on conventions. So, I see forcing the path of the view a way to broke a convention. Are you sure you can't simply create two routing rules for the two methods? So you can do something like this:
return RedirectToAction("Search", "Controller1");
and
return RedirectToAction("Search", "Controller2");
user932390,
mvc uses convention over configuration. this means that the 'search' view will have to be located in both the:
views/Search
and
views/SearchByStaff
folders respectively. the only way around this is to locate the search view under the views/shared folder, then the viewengine will find it there in both cases and use it (assuming they have the same model).

asp.net mvc how it decides which view to load

I am attempting to construct an asp.net mvc app which will use the urls like:
/Controller/[Number]/Action/Id
I have got it to always call my controller and pass it the Number and the Id fine...
However I now want to return a different view depending on the Number
I could have options like:
if([Number] == 1) { return View("ViewName");}
if([Number] == 2) { return View("ViewName2");}
however I instead was wondering if there was a way to change the core so that instead of searching at ~/Views/controller/action.aspx I could have my own method which did some checking on the Number then passed to the virtual file provider is a different path
Hope this makes sense!
Decide which view to load, depending on input parameters is a controller task. You could write your own view engine.
But it is easier to return the full path to the view you want to return.
return View("~/myviews/ViewName3.aspx");
This will render ViewName3 from given directory.
You might want to look at decorating your controller method with Action Filter Attributes.
Then, you could do something special inside the Action Filter Attribute.
Or, you could pass Number to a Model object, then have the model Object return the right View path.
Either way, your instinct of trying to keep too much logic out of the Controller is sound, especially if [Number] is somehow a business concern and not a view concern.
You need to look into / google creating a custom view engine.
By the sounds of things you probably just want to extend the built-in WebFormViewEngine and just override the locations and the .FindView() method.
HTHs,
Charles

ASP.NET MVC - switching the VIew to be used dynamically

What is the correct way to dynamically change the View (the view aspx) that a controller method uses versus using the standard naming convention.
I'm guessing it has something to do with the ViewResult and ViewName, but what is the correct syntax?
Update:
One thing I forgot... is there a way to do this without having the "action" or method name not be part of the resulting URL?
For example,
If I wanted to have a list of all the states in the USA.
http://localhost/list/states
(displays a simple list of state names)
And If I wanted to have a list of the 50 largest cities in the USA.
http://localhost/list/largest-cities
(displays the city and the population - two column grid)
So I'd like to be able to pull in different "formatters" depending on the list name.
Should I do that in a single action / multiple views?
Could I then use Routes to hide the View name in the URL?
What is the best way to approach this?
Just use the method that takes the name of the view to choose. Be careful, though. Most times what you probably want to do is redirect to a different action instead. Returning a different view won't change the url like redirecting will.
string name = ...figure out which view you want...
return View( name );
If you need to render a different view from a controller action dynamically, you can simply supply a value to the base.View() method (or the ViewResult constructor). The location of the view will always be (for the web forms view engine):
/Views/{Controller}/{View}.aspx
Edit: (Thanks to Ithi) It could also be in:
/Views/Shared/{View}.aspx

Resources