MapRoute for overload Action - asp.net-mvc-4

I have this Controller :
public class ProfileController : Controller
{
public ActionResult Index( long? userkey )
{
...
}
public ActionResult Index( string username )
{
...
}
}
how can i define MapRoute for this actions work like this:
mysite.com/Profile/8293378324043043840
this must be go to first action
mysite.com/Profile/MyUserName
this must be go to second action
I have this route for the first action
routes.MapRoute( name: "Profile" , url: "Profile/{userkey}" , defaults: new { controller = "Profile" , action = "Index" } );
do i need add another MapRoute ? or can i change the current MapRoute for both action?

First you cannot overload controller actions if you are using the same Http Verb (in your case GET) because you need to have unique action names.
So you need to name your actions differently:
public class ProfileController : Controller
{
public ActionResult IndexKey( long? userkey )
{
...
}
public ActionResult IndexName( string username )
{
...
}
}
Or you can use the ActionNameAttribute to give different names to your actions:
public class ProfileController : Controller
{
[ActionName("IndexKey")]
public ActionResult Index( long? userkey )
{
...
}
[ActionName("IndexName")]
public ActionResult Index( string username )
{
...
}
}
Then you will need two routes with using route constraints on the userkey to be a numeric value to setup your actions:
routes.MapRoute(name: "Profile", url: "Profile/{userkey}",
defaults: new { controller = "Profile", action = "IndexKey" },
constraints: new { userkey = #"\d*"});
routes.MapRoute(name: "ProfileName", url: "Profile/{userName}",
defaults: new {controller = "Profile", action = "IndexName"});

Related

Is it possible to use a variable for the action in the MVC routeconfig file

I am trying to see if I can use the action part of routes.MapRoute for a route in routeconfig.cs file
I tried:
routes.MapRoute(
name: "Person",
url: "person/{action}/{param1}",
new { controller = "Person", action ={action], param1 = UrlParameter.Optional }
);
Trying to use {action} in the new section gives a syntax error when I try to use action = {action}.
How can I use a variable to set the new controller action?
If you've specified {action} in the url parameter then that will be used as the action. I think you are getting confused with the defaults parameter. In here you specify defaults so something like {action} is out of place.
I believe this is the code you are looking for
routes.MapRoute(
name: "Person",
url: "person/{action}/{param1}",
defaults: new { controller = "Person", action ="Index", param1 = UrlParameter.Optional } );
Suppose this is your person controller
using System.Web.Mvc;
namespace ActionVar.Controllers
{
public class PersonController : Controller
{
public ActionResult Index(string param1 = null)
{
return Content($"Person controller default action. Param1 ={param1}");
}
public ActionResult Edit(string param1 = null)
{
return Content($"Person controller edit action. Param1 ={param1}");
}
}
}
Some urls and how they will be routed for the above controller:
/person - in this case no action provided so the default action will be used, i.e. index, and the value of param1 will be null
/person/index/myparam1 - The string after person is index so that will be the action and the value of param1 will be myparam1
/person/edit/myparam1 - This time the action will be edit and param1 will take the value myparam1

How to prevent Browser returning default value of int when input is an int parameter in the URL?

public IActionResult Info(int id)
{
return Content(id + "");
}
Whenever I input Jan/Info/2 the browser returns me the value 0. Why is this and how can I fix this? I'm using MVC core 1.1. UrlParameter.Optional is also not present in Visual Studio for some reason it's not accessible.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "Naam",
template: "{controller=Jan}/{action}/{voornaam}");
routes.MapRoute(
name: "Info",
template: "{controller=Jan}/{action}/{id}");
}
public IActionResult Naam(string voornaam)
{
return Content(voornaam);
}
Because you already have another route registration which is matching the exact pattern. As per that registration, it will read the value and assign to the voornaam parameter.
So this should work
public IActionResult Info(int voornaam)
{
return Content(voornaam + "");
}
Since you have unique names for your action method, you do not need to specify the custom routes for each action method. The default route registration will work fine.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "defaultroutes",
template: "{controller}/{action=Index}/{id?}",
defaults: new { controller = "jan" });
});
Assuming your controller looks like this
public class JanController : Controller
{
public IActionResult Info(int id)
{
return Content(id + " : id");
}
public IActionResult Naam(string voornaam)
{
return Content(voornaam+ ": param value");
}
}
When you access yourSite/jan/info/123, The Info method will handle that and when you request yourSite/jan/Naam?voornaam=shyju ,the Naam method will handle that.
If you want to support url structure like yourSite/jan/Naam/shyju instead of the explicit querystring, you can specify a route pattern on that action method with attribute routing
public class JanController : Controller
{
public IActionResult Info(int id)
{
return Content(id + " id");
}
[Route("[controller]/[action]/{voornaam}")]
public IActionResult Naam(string voornaam)
{
return Content(voornaam + " : param value");
}
}
Now when you request yourSite/jan/Naam/shyju, The Naam method will be called and the string "shyju" will be available in the voornaam parameter

Attribute routing - every method, class or as needed?

Let's say you have an API controller. Some methods of this controller use the same routes:
[HttpPost] // /api/entities
public IHttpActionResult Add(Entity entity)
{
...
}
[HttpGet] // /api/entities
public IHttpActionResult FindAll()
{
...
}
[HttpGet] // /api/entities
public IHttpActionResult Find(String name)
{
...
}
[HttpGet] // /api/entities/id
public IHttpActionResult Find(Int32 id)
{
...
}
[HttpDelete] /api/entities/id
public IHttpActionResult Remove(Int32 id)
{
...
}
Do I apply RouteAttribute to all methods or only to two methods to cover for "api/entities" and "api/entities/id"? Or is it better to apply two RouteAttribute to the class itself?
If you have default routes specified in the configuration, that is:
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
You don't have to apply routing attributes, don't forget that requests will be mapped to the actions not only by HTTP method, but by parameter type also, so there should be no problem.
Take a look at the "Action" section of the documentation.

ASP MVC default route is not applying for root site url

I'm having trouble getting ASP.net MVC to serve up the default controllers index view for the root site url http://mysite:8080/. All I get back is a 404 with The resource cannot be found. It works fine if I specify the full route path in the url : http://mysite:8080/Default/Index, however, I want the default route to apply even if the user doesn't specify the route path though. It seems that this should just work out of the gate. This is a fresh project from the VS2013 MVC 4 template.
I've tried both route mappings below and neither seems to work. How can this be achieved?
routes.MapRoute(
"Root",
"",
new { controller = "DefaultController", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "DefaultController", action = "Index", id = UrlParameter.Optional }
);
Here is a solution to this problem. It's disappointing that the default route's defaults do not apply for the root site url though.
routes.Add(new Route("", new SiteRootRouteHandler("~/Default/Index")));
public class SiteRootRouteHandler : IRouteHandler
{
private readonly string _redirectUrl;
public SiteRootRouteHandler(string redirectUrl)
{
_redirectUrl = redirectUrl;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new SiteRootHandler(_redirectUrl);
}
}
public class SiteRootHandler: IHttpHandler
{
private readonly string _redirectUrl;
public SiteRootHandler(string redirectUrl)
{
_redirectUrl = redirectUrl;
}
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.RedirectPermanent(_redirectUrl);
}
}

MVC 4 creating slug type url

i am trying to create a stackoverflow like url.
I the following example works fine. But if i remove the controller then it errors out.
http://localhost:12719/Thread/Thread/500/slug-url-text
Note the first Thread is the controller the second is the action.
How can i make the above URL look like the following excluding the controller name from the url?
http://localhost:12719/Thread/500/slug-url-text
My Routes
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Default", // Route name
"{controller}/{action}/{id}/{ignoreThisBit}",
new
{
controller = "Home",
action = "Index",
id = "",
ignoreThisBit = ""
}); // Parameter defaults )
}
}
Thread Controller
public class ThreadController : Controller
{
//
// GET: /Thread/
public ActionResult Index()
{
string s = URLFriendly("slug-url-text");
string url = "Thread/" + 500 + "/" + s;
return RedirectPermanent(url);
}
public ActionResult Thread(int id, string slug)
{
return View("Index");
}
}
Placing the following route before the default route definition will directly call the 'Thread' action in 'Thread' controller with the 'id' and 'slug' parameter.
routes.MapRoute(
name: "Thread",
url: "Thread/{id}/{slug}",
defaults: new { controller = "Thread", action = "Thread", slug = UrlParameter.Optional },
constraints: new { id = #"\d+" }
);
Then if you really want it to be like stackoverflow, and assume someone enters the id part and not the slug part,
public ActionResult Thread(int id, string slug)
{
if(string.IsNullOrEmpty(slug)){
slug = //Get the slug value from db with the given id
return RedirectToRoute("Thread", new {id = id, slug = slug});
}
return View();
}
hope this helps.