Remove Index from MVC url with routeValue - asp.net-mvc-2

How can I remove the Index from the MVC url that has a routeValue?
E.g.
http://localhost/Beverage/Index/WhiteWine
to
http://localhost/Beverage/WhiteWine
but still be able to have
http://localhost/Beverage/ShowBeverage/1

You can create a custom route:
MapRoute("My Route Name",
"Beverage/{id}",
new { controller = "Beverage", action = "Index" });
Note that the controller name must be hard-coded in the route, then specified in the defaults to tell MVC which controller to use.
If you take the naive approach and map {controller}/{id}, it will accept any URL of the form a/b, which is not what you want.

Related

how do you get a variable from a post address in zendframework 1

I am still new to Zend Framework and confused about a few concepts.
I have built a POST form and attached a unique Id to the URL at the end of the form. I now want to collect that Id when the form is submitted but I am unclear how to do that
I will show you want I have done:
Below is the function that renders the form from my controller page to the view. You will note that I have fed into the parameter, for the form, a return Action address with the ID
$action = "{$this->view->baseUrl()}/sample-manager/process-price/{$sampleId}";
$this->view->Form = $model= $this->_model->createForm($action);
The function to receive the post is below. However, I want to collect the Id that should have come back with the post return values, but I have no idea where to find it or how to attach it.
public function processPriceAction()
{
$this->requirePost();
if($this->_model->processTieredPriceForm($this->view->form, $this->getRequest()->getPost()))
{
$this->_helper->FlashMessenger('Changes saved');
return $this->_redirect("/product-ecommerce/{$this->_model->getProduct()->id}");
}
else
{
return $this->render('index');
}
}
In summary, when a post is returned, does the return address come with the post in Zend Framework?
Could you not supply the id into the construction of the form and assign it to a hidden element? For example, in your controller:
$action = "{$this->view->baseUrl()}/sample-manager/process-price";
$this->view->Form = $model= $this->_model->createForm($action, $sampleId);
In your form model (not provided so best guess here):
$sampleId = new Zend_Form_Element_Hidden('sampleId');
$sampleId->setValue($sampleId);
$form->addElement($sampleId);
Then once the form is posted, you should be able to get the sample id in your controller in the standard way:
$sampleId = $this->getParam('sampleId');
The answer depends a bit on how your routing is setup. If you're using the default setup, after the action name the default route allows for key/value pairs of additional data. So, you might have more luck with a URL like this:
{$this->view->baseUrl()}/sample-manager/process-price/id/{$sampleId}
That'll put your sampleId in a named parameter called 'id', which you can access in your controller action with $this->_getParam('id').

zend framework this->url get different url on the same page but different url

in application\modules\admin\layouts\scripts\layout.phtml
<?php echo $this->url(array('action'=>'logout','controller'=>'user','module'=>'admin'),null,true);?>
when I visited zfmul/public/admin-cate/ , It return
/zfmul/public/admin-cate/logout
but when I visited zfmul/public/admin/categories, It return
/zfmul/public/admin/user/logout
and the two url is render to the same module, same controller, same action, I wonder why it retrun different result?
I didi some configs in application.ini,
resources.router.routes.admincategories.route = "admin-cate/:action/:id"
resources.router.routes.admincategories.defaults.module = "admin"
resources.router.routes.admincategories.defaults.controller = "categories"
resources.router.routes.admincategories.defaults.action = "index"
resources.router.routes.admincategories.reqs.action = "save|edit|index|new"
resources.router.routes.admincategories.defaults.id = "1"
resources.router.routes.admincategories.reqs.id = "\d+"
When you use $this->url, you're in fact using function url from library/Zend/View/Helper/Url.php, whose 1st line is:
$router = Zend_Controller_Front::getInstance()->getRouter();
Since you declared a custom admincategories route, you now have 2 to access those particular module/controller/actions:
Default - accessible via zfmul/public/admin/categories;
Custom - accessible via zfmul/public/admin-cate/.
Depending on the URL you use to access, the $router variable value will change accordingly and so will the result of the $this->url call as you're experiencing.
Here are a few references to questions on SO that might help you work around that behaviour:
Zend Framework: How to disable default routing?;
Zend framework: Removing default routes.

Why is this IgnoreRoute call matching these requests?

I've got a localization httphandler that's running in the context of my ASP.Net MVC2 Content folder (part of what it's doing is compiling .less files that are in /Content/css). My default route for this particular set of requests looks like this:
context.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
context.MapRoute(
"Area_default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { controller = new VirtualDirectoryConstraint("VDirectory1") },
new string[] { "Namespace.One.MVC" }
);
(As an aside - I don't think it's relevant, but just in case - the VirtualDirectoryConstraint rejects matches on this route if the request is not coming from the passed-in application path/virtual directory)
With this configuration a call to http://server.net/VDirectory1/Content/css/LessCompiler.axd fails because there's no ContentController class. All well and good.
When I add
context.Routes.IgnoreRoute("{Content}/{*pathInfo}");
that call succeeds, but subsequent calls to
http://server.net/VDirectory1/Localization/ClientScript/en-US.js
and
http://server.net/VDirectory1/Authorization/ClientScript
fail. Looking at Phil Haack's RouteDebugger tool, those calls are matching the Content IgnoreRoute route:
True {Content}/{*pathInfo} (null) (null) (null)
and are therefore not being routed to the LocalizationController and AuthorizationController, respectively.
Clearly I'm misunderstanding something about how the IgnoreRoute is supposed to be used and why that particular IgnoreRoute is matching those requests. What am I missing?
Shouldn't your IgnoreRoute use Content instead of {Content} ?
context.Routes.IgnoreRoute("Content/{*pathInfo}");
At the moment, {Content} is probably being expanded as a variable to nothing, which makes the pathinfo match everything.

ASP.NET MVC2 - passing a parameter to a controller

This is for a project I'm doing in the university. We're using ASP.NET MVC2 to build a mini-prototype of a website just to show what we can do.
Now, I have a controller called ItemController.cs, a view Item/Index.aspx, a model Item.cs and a ViewModel ViewItems.cs. I use the ViewModel to pass information to the view from the controller. My question is - how do I call a controller method with parameters? Currently, I use
Html.ActionLink("View Event Items", "Index", "Item")
which points to ItemController's Index() method. Say I want it to take an int parameter (Index(int eventId)) How would I write the ActionLink to pass the parameter to it?
Also, if I have any errors in how I think this stuff works, please feel free to point them out.
You'll need to use the routevalues object (or RouteValuesDictionary) to pass values to your action.
In your example it would look like this:
Html.ActionLink("View Event Items", "Index", "Item", new { eventId = 1}, new {})
...where 2 is your event id. The second empty object (new {}) is for html attributes. Nate's answer is close, but I don't think there is an overload that takes a routevalues object as the second parameter.
I think that
Html.ActionLink("View Event Items", new { controller = "Item", action = "Index", id = 5 })
should get you in the vicinity of where you're looking to go.

MVC Areas and routing

I'd like to have an area called "Products", where I can use routes such as
http://localhost/products/foo
http://localhost/products/bar
I would like to have the views and other assets organized into a folder structure like
/areas/products/views/foo/index.aspx
/areas/products/views/bar/index.aspx
I'd like to keep images, etc specifically related to each product (foo, bar) in their respective /area/products/views/(foo|bar)/ folder.
I also do not want to have to add a controller action for each product.
If I declare a route like
context.MapRoute(
"products-show-product"
, "Products/{id}"
, new { controller = "Products", action = "Index", id=UrlParameter.Optional }
);
and request the url
http://localhost/products/foo
then ProductsController.Index() is called, as I would expect. However, since the view "foo" is not in the views/products or views/shared folder, it isn't being found.
How can I do this so that I can keep each product's pages in a separate folder?
I don't have a concrete answer to your question since I am not sure about my understanding of it. However I have a general feeling for the direction for the solution.
When one starts to change locations of views, the corresponding methods that find those views also need to change. A simple approach would be to override the FindView and FindPartialView methods.
A simple demo. I created an Area called Blog, a Blog controller with an Index method. In my case I user the controller action as the SubFolder but I am sure that this can be extended to your case for each product folder. I assume that the product will be a request argument. Area http://www.freeimagehosting.net/uploads/85b5306402.gif
The basic idea is to interrogate the controllercontext for the controller, area, action and id and modify the what the default viewengine looks for. The default locations for area views looks like "~/Areas/{2}/Views/{1}/{0}.aspx", so we can basically inject values for the view name and in this case ActionName/Index. The view location will end up being ~/Area/Blog/Views/Blog/Index/Index.aspx.
This is just a rough outline, of the code that can be used. The string comparisons can definitely be updated to more robust methods. As it stands this method will work for the entire app as expected, except for the case when a request is made to the Blog area for the Index action.
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
if (controllerContext.RouteData.DataTokens ["Area"] == "Blog" )
{
if (String.Compare(controllerContext.RouteData.Values ["Action"].ToString(),"Index",true) == 0)
{
var viewLocation = String.Format("{0}/{1}", controllerContext.RouteData.Values["Action"].ToString(), viewName);
return base.FindView(controllerContext, viewLocation , masterName, useCache);
}
}
return base.FindView(controllerContext, viewName, masterName, useCache);
}