Why is mandatory the "Route" attribute on methods of a custom-routed controller? - asp.net-core

Consider a fresh Asp.Net Core 2.1 MVC Web app created via the Visual Studio 2017 template. Now, consider a custom view (MyView) and also a controller (ActualController) so that the project structure looks similar to this picture:
The MyView shows nothing special, and it's off the point. However, the page should appear when the user enters an URL like http://(domain)/desired/myview or also via a hyperlink in the home page:
<a asp-area="" asp-controller="Desired" asp-action="MyView">MyView</a>
Now let's focus on the controller, which is a class named differently from what the routing expects:
[Route("desired")]
public class ActualController : Controller
{
[Route("MyView")] //without this the method won't be called
public IActionResult MyView()
{
return this.View();
}
}
From what I know, by decorating the controller with a Route attribute tells the URL resolver to match this class. However, the mapping works only if I explicitly add a (redundant) Route attribute on the target method/action. If I remove it, the path won't be found, and the server returns a 404-error.
The question is: why should be mandatory to decorate with Route the method, even the action is implicitly defined by the method name (as usual)?
NOTE: is rather simple for me to rename the controller class, but I'd like to know what are the reasons behind this behavior.

You are overriding the default route of [controller]/[action] with [Route("desired")]. Since you don't define an action parameter on controller level, all other routes have to be done explicitly.
Changing the top route parameter to [Route("desired/[action]")] should solve it and the method name will be used as parameter. You can still override single actions if you want to name them differently by adding the [Route("")] attribute to them.
Also see the docs (Token replacement in route templates) for further description on the route parameters

Related

Umbraco with MVC Controller

I am working on MVC and i started learning Umbraco, I didn't get how to bind the umbraco page with mvc controller get method to show the database values. can anyone suggest any url or video?
Thansk...
What you're looking for is Umbraco route hijacking.
You can read about it here.
https://our.umbraco.org/documentation/reference/routing/custom-controllers
It's easiest to demonstrate with an example : let's say you have a Document Type called 'Home'. You can create a custom locally declared controller in your MVC web project called 'HomeController' and ensure that it inherits from Umbraco.Web.Mvc.RenderMvcController and now all pages that are of document type 'Home' will be routed through your custom controller! Pretty easy right :-) OK so let's see how we can extend this concept. In order for you to run some code in your controller you'll need to override the Index Action.
So, basically, you "simply" need to create a controller named after your document type, so for example, a document type with the name "TextPage" would need a controller called "TextPageController". Now, if you read through the documentation, you'll find that your "TextPageController" will need to inherit from the RenderMvcController. Here's an example how to achieve this.
public class TextPageController : RenderMvcController
{
public ActionResult Index()
{
return View("~/Views/TextPage.cshtml");
}
}
This forum link may help you:
https://our.umbraco.org/forum/developers/razor/38242-Umbraco-MVC4111-Surface-controller-using-an-AJAX-form

ASP.NET WebAPI2 Attribute Routing and SubFolders

I'm using Attribute Routing in WebAPI. My question is more on creating sub-folders under controllers in WebAPI (not in MVC, I'm using Areas for that)
I searched what kind of impact it would cause to the existing routing pattern and mostly they referred like adding custom routing template in WebAPIConfig.cs. But since I'm using AttributeRouting, is it really required to create custom template??
I tested my code and it seems to be working fine without any custom templates and I'm also able to achieve modularization by creating sub-folders under Controllers folder but would like to know the best practice and solution.
No - as you've found you don't need to create custom templates if you're using Attribute Routing.
The underlying method (MapAttributeRoutes) calls into the Controller factory to find all classes that inherit from Controller and then checks those for a Route attribute - so where they sit in the namespace hierarchy shouldn't matter.
If you are trying to mix Attribute and Convention routing and have sub-folders for convention based routes then you will need to define a custom template.
FYI: There is one small 'catcha' that you need to be aware off when (re)organizing your controllers in subfolders using attribute routing. Make sure your controller class has a unique name! Otherwise attribute routing gets confused and will not work. To illustrate:
// File: ~/Controllers/Customers/DetailsController.cs
namespace MyProject.Controllers.Customerss
{
[RoutePrefix("~/api/customers/{id}")]
public class DetailsController: ApiController {
[HttpGet]
public IHttpMessageResult GetItem(int id) {...}
}
}
and
// File: ~/Controllers/Orders/DetailsController.cs
namespace MyProject.Controllers.Orders
{
[RoutePrefix("~/api/orders/{id}")]
public class DetailsController: ApiController {
[HttpGet]
public IHttpMessageResult GetItem(int id) {...}
}
}
Although, cleary having different routes and certainly pointing to different controller classes it will throw off the attribute routing. By changing the controller classes to CustomerDetailsControlller and OrderDetailsController the routing issue resolved itself.

How can I use asp.net mvc routing to call a different ActionResult method and display a different URL than what is actually there?

Lets say I have a Controller class called ProductController.
I'll use Samsung as a hypothetical product category.
I have an Html.ActionLink on a page that looks like this
~/Product/Samsung?t=Sony
Now lets say I don't have an ActionResult method named Samsung.
But lets say I have more links like the one above like
~/Product/Toshiba?t=LG
~/Product/Sony?t=Dynex
Never mind the t=? part.
Is there a way that I can make all of these ActionLinks hit the same ActionResult method in my Product Controller?
public ActionResult TelevisionCategory()
{
}
Like some sort of URL routing so that any URL in a specific format will hit the TelevisionCategory method?
Sounds like you just need a custom route that takes an identifier as a second URL segment instead of an action name.
Something like the following should suffice (you'll need to add this above the default route in your route config):
routes.MapRoute(
"Products",
"Product/{category}",
new { controller = "Product", action = "TelevisionCategory" }
);
Then, your action method should look like this:
public ActionResult TelevisionCategory(string category)
See here for more on creating custom routes.
If using MVC5 is an option, you can also use attribute routing, which is a little more intuitive and succinct.

How to expose and call methods on MVC 4 user controls

I am converting my asp.net site to MVC 4. My site has a control called loginbox that prompts the user for username and password. The control also exposes a method called IsLoggedIn that a hosting page can call. I want to continue to encapsulate the login logic in my loginbox control and call it in a similar fashion from a parent level page (i.e loginBoxInstance.IsLoggedIn()). How do I do that?
MVC doesn't have a concept of user controls. The whole setup of MVC is to separate logic from the view. You could achieve a similar setup by creating a separate controller and a partial view.
Then in your main view you could call RenderAction on the controller, which renders the partial view. However, this is only valid for the rendering stage, so something like IsLoggedIn() is not something you can (or should) do in MVC.
Example:
Controller
public class LoginController
{
public ActionResult Login()
{
return PartialView();
}
}
Partial View
// Place this file in Views/Login/Login.cshtml
<div>
<!-- Your markup -->
</div>
Main view
#Html.RenderAction("Login", "Login")
This will allow you to separate the view part (and also the logic) of the login rendering into a separate controller and view, which can be included in another view.
However, what you probably want is something like Action-attributes or inherit from a base controller class which handles all this for you.
The paradigm of MVC versus Web Forms is very different, and I think you should look into a more appropriate way of doing this.

how to redirect one area to another area

I have two controllers in my MVC4 Project.
One controller is in default controller name called Login.
another controller is in area .area name called HR.inside controller name called AddNewHire.
inside AddNewHire i written AddNewEmployee method.
in Login controller i am having one method .that name is LoginButton
inside LoginButton method i written
return RedirectToAction("AddNewEmployee","AddNewHire",new {area="HR"});
am getting Error Like
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /AddNewHireController/AddNewEmployee
Try using RedirectToRoute instead of RedirectToAction. What you would have to do is to define a route. Have a look at this MSDN link (Walkthrough: Creating an ASP.NET MVC Areas Application Using Multiple Projects