Change routing of the controller to include it under another controller - asp.net-mvc-4

I have a controller named DummyController when i call the controller it is like DummyController/Index i want this controller to be called as maincontroller/dummycontroller/index where mainController is a different controller altogether.
Code for DummyController:
public ActionResult Index()
{
return View("~/Views/main/dummy/index.cshtml",db.Users.ToList());
}
the location of index file of Dummy Controller is main/dummy
Now the problem is when I call the dummy controller's index page i get the url as dummy/index i want the url to be displayed as main/dummy/index.
Is there any way to create child controllers? o change the url only for the specific controller

This was relatively straightforward, once I got past a simple issue.
By using a combination of [RoutePrefix("")] & [Route("")] on my controller, I was able to make this work. Attribute Routing requires a call to routes.MapMvcAttributeRoutes() in your Global.asax.cs RegisterRoutes() method.
[RoutePrefix("main/dummy")]
[Route("{action=index}/{id:long?}")]
{action=index} defines the action handling for the route, and specifies /index as the default action, if it's not supplied (ie, ~/main/dummy/ will render ~/main/dummy/index
{id:long?} specifies the id route attribute
:long is the syntax for constraining the param to the long datatype
? denotes this param is optional. (more on this here)
This could also be done using the standard MapRoute() technique:
routes.MapRoute(
name: "DummyControllerRoute",
url: "main/dummy/{action}/{id}",
defaults: new { controller = "Dummy", action = "Index", id = UrlParameter.Optional });
I forgot to add what my simple issue was..
I had 2 actions in the controller: Index() and Index(id), which would always result in the AmbiguousRouteException, and was leading me to believe my Route was defined incorrectly. Changing that to View(id) solved it. (I guess technically the route was wrong, but I didn't need to spend any more time trying to make it work that way)

Related

Route segment without matching controller or action in ASP.NET Core

Take a look at this route:
{controller}/{currency=USD}/{action=view}
It matches URLs of type rates/GBP/edit (and others as well..). Rates map to controller and edit maps to view. Thats fine. What I don't understand is to what the middle segment GBP is matched to.
If it would be the other way around => {controller}/{action=view}/{currency=USD}, GPB would be a parameter to action method. But with current syntax, it looks like a parameter for controller which doesn't make sense.
Example route config:
app.UseMvc(routes =>{
routes.MapRoute(
name:"def",
template:"{controller}/{currency=USD}/{action=view}"
);
});
Example controller:
public class RatesController : Controller{
public IActionResult Edit(){
return View();
}
}
So, to what code is currency matched, if any? Perhaps the same question.. how can I access the currency segment value?

ASP.NET MVC: First parameter in action method is always empty when form is submitted

I am having a problem when passing values to Controller action method.
I have a route map like this:
routes.MapRoute(
name: "VehicleAdvancedSearchResult",
url: "search-result/{searchTypeSlug}/{condition}/{makeSlug}/{modelName}/{modelExt}/{categorySlug}/{parishSlug}/{yearRange}/{priceRange}",
defaults: new
{
controller = "SearchResult",
action = "VehicleAdvanceSearch",
//SearchTypeSlug = UrlParameter.Optional
//Condition = UrlParameter.Optional,
//MakeSlug = UrlParameter.Optional,
//ModelName = UrlParameter.Optional,
//ModelExt = UrlParameter.Optional,
//CategorySlug = UrlParameter.Optional,
//ParishSlug = UrlParameter.Optional,
//YearRange = UrlParameter.Optional,
//PriceRange = UrlParameter.Optional
}
);
I tried with UrlParameter.Optional but it did not work.
In the View I have a form with no action defined by default but when I hit submit the action attribute is added to it with correct values.
The problem is the first parameter value is always coming as empty string when the controller method is actually called.
What I am doing wrong?
The other issue is I want the action method to be called even if the URL is partially complete or even it has no parameter. In my case if I type in just http://locahots:55904/search-result/ or http://locahots:55904/search-result/for-sale/, meaning as long as it is partial, I am always ending up with a 404. But I want them to redirect to another page if it is a partial URL.
I have already done that check in my action method but the method is not at all being called with a partial URL.
This is required because Google crawls the URL with every single folder structure separately to index them.
How can I prevent this from happening?
For controller method if you want to partially call you need to defined optional parameters in method
For example,
Public ActionResult <method name>(string param1="",string param2=""){}
Now if you want to call method with partial arguments you need to pass argument right to left.
Or an alternative way is you can override method with different arguments option you have.
For this action method to be called by partial url, you can create a new route in RouteConfig file having different route name pointing to the same action method.
routes.MapRoute(
name: "VehicleAdvancedSearchResult_V2",
url: "search-result/{parameterName?}",
defaults: new
{
controller = "SearchResult",
action = "VehicleAdvanceSearch",
}
);
Second way is that you can apply Attribute Routing on this action using the Route Attribute.
For Example:
[Route("[action]/{parameterName?}")] //?--> for optional parameter
public ActionResult VehicleAdvanceSearch()
In Order to resolve the issue of First Parameter null, you can create a Model for all the parameters and then hit the controller action with Modal as parameter.
For Example:
[HttpPost]
public ActionResult VehicleAdvanceSearch(SearchResultModel model){}

HandleUnknownAction in ASP.NET 5

What's an equivalent of ASP.NET MVC 5
Controller.HandleUnknownAction()
in ASP.NET MVC 6 / ASP.NET 5?
There's no real equivalent.
Action Selection in MVC5/WebAPI2 was a three stage process:
1. Run the routes
2. Select a controller
3. Select an action
In MVC6, step 2 is gone. Actions are selected directly using route values - you'll notice that Controller.BeginExecute is gone as well. Controllers are 'thin' now.
You can simulate this behavior if you want by using a route that goes directly to your action in question.
Define an action called HandleUnknownAction in your controller
routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
routes.MapRoute("unknown_action", "{controller}/{*params}", defaults: new { action = "HandleUnknownAction"});
An alternative approach is to simply define the unknown action as a parameter of your route:
[Route("[controller]")]
public class FooController : Controller
{
[HttpGet("{viewName}")]
public IActionResult HandleUnknownAction(string viewName)
{
return View(viewName);
}
}
Using this approach, the url foo/bar would return the View bar.cshtml, foo/baz would return baz.cshtml etc.

Switching MVC view on Post back using strongly typed views/view models

User requests page for Step1, fills out and submits form that contains selected person, so far so good. After validation of ModelState the next viewmodel is constructed properly using the selected person. I then attempt a redirect to action using the newVM but find on entry to Step2 that MVC wipes out the viewmodel attempted to be passed in. I suspect this is due to how MVC attempts to new up and instance based on query string results. I'll put a breakpoint in and check that, but am wondering how does one change a view from a post back with a new view model passed in?
public ActionResult Step1()
{
var vm = new VMStep1();
return View(vm);
}
[HttpPost]
public ActionResult Step1(VMStep1 vm)
{
if (ModelState.IsValid)
{
var newVM = new VMStep2(vm.SelectedPerson);
return RedirectToAction("Step2", newVM);
}
return View(vm);
}
public ActionResult Step2(VMStep2 vm)
{
return View(vm);
}
I can fix this by containing VMStep2 and a partial to Step2 in Step1 view, but that requires hide and seek logic when really I just want user to see Step2.
I don't see why you should want to call RedirectToAction! What it does it the following:
it tells your browser to redirect and like it or not your browser doesn't understand how to handle your object -- what it does understand is JSON. So if you really insist on using return RedirectToAction("Step2", newVM); you should consider a way to serialize your VMStep2 object to JSON and when the browser requests the Redirect, it will be properly passed and created in your action method public ActionResult Step2(VMStep2 vm)
HOWEVER I'd use a much simpler way ---
instead of
return RedirectToAction("Step2", newVM);
I would use
return View("Step2", newVM);
Thanks to everyone for the great input!
Here's what I did...
I created three views MainView, Step1View, Step2View (Step 1 and 2 were partial strong typed views)
I created a MainViewModel that contained VMStep1 and VMStep2
When controller served Step1 the MainViewModel only initialized VMStep1 and set state logic to tell MainView Step1 was to be shown.
When user posted back the MainView containing the MainViewModel, the MainViewModel knew what to do by the answers provided in VMStep1.
VMStep2 was initialized on the post back, and state was set to tell MainView to show Step2. VMStep1 was no longer relevant and was set to null.
User was now able to answer using VMStep2 and all was well.
The key to this working is that some flag tells the view which partial to show, the partial takes a model supporting it's strong type which is initialized at the right time. End result is fast rendering and good state machine progression.

Is it possible to render View without create Action in ASP.NET MVC?

Is it possible to get/render View without creating Action in Controller? I have many Views where I dont need pass any model or viewbag variables and I thing, its useless to create only empty Actions with names of my Views.
You could create a custom route, and handle it in a generic controller:
In your RouteConfig.cs:
routes.MapRoute(
"GenericRoute", // Route name
"Generic/{viewName}", // URL with parameters
new { controller = "Generic", action = "RenderView", }
);
And then implement a controller like this
public GenericContoller : ...
{
public ActionResult RenderView(string viewName)
{
// depending on where you store your routes perhaps you need
// to use the controller name to choose the rigth view
return View(viewName);
}
}
Then when a url like this is requested:
http://..../Generic/ViewName
The View, with the provided name will be rendered.
Of course, you can make variations of this idea to adapt it to your case. For example:
routes.MapRoute(
"GenericRoute", // Route name
"{controller}/{viewName}", // URL with parameters
new { action = "RenderView", }
);
In this case, all your controllers need to implement a RenderView, and the url is http://.../ControllerName/ViewName.
In my opinion it's not possible, the least you can create is
public ActionResult yourView()
{
return View();
}
If these views are partial views that are part of a view that corresponds to an action, you can use #Html.Partial in your main view to render the partial without an action.
For example:
#Html.Partial("MyPartialName")