RedirectToAction with parameters in Route - c#

I have some problem with redirecting to some action basicly if I have no paramers on route or parameter which calls Id it works fine, yet when i add some different parameters to route RedirectToAction does not work, it throws an error: No route in the route table matches the supplied values.
[Route("First")]
public ActionResult First()
{
//THIS DOESN'T WORK
//return RedirectToAction("Second", new { area = "plans"});
//THIS WORKS
return RedirectToAction("Third", new { id = "12" });
}
[Route("Second/{area}")]
public ActionResult Second(string area)
{
return new ContentResult() { Content = "Second : " + area};
}
[Route("Third/{id}")]
public ActionResult Third(string id)
{
return new ContentResult() { Content = "Third " + id };
}
So when i enter /First it redirect correctly to Third but to Second it throw error.
I don't have anything extra in RouteConfig just:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
}

Probably, you are conflicting the area parameter with area route parameters. Areas is a resource from Asp.Net MVC with the following definition:
Areas are logical grouping of Controller, Models and Views and other
related folders for a module in MVC applications. By convention, a top
Areas folder can contain multiple areas. Using areas, we can write
more maintainable code for an application cleanly separated according
to the modules.
You could try to rename this parameter and use it, for sample, try to rename the area to areaName:
[Route("First")]
public ActionResult First()
{
return RedirectToAction("Second", new { areaName= "plans"});
}
[Route("Second/{areaName}")]
public ActionResult Second(string areaName)
{
return new ContentResult() { Content = "Second : " + areaName};
}

Related

Custom route is not hitting in asp.net core mvc?

I have sample .net core mvc application, im testing SEO friendly url creating ,
which is posted Here
I have created all the code as in the post.
My testing controller action is as follows
public IActionResult Index(int id, string titl)
{
//string titl = "";
var viewModel = new FriendlyUrlViewModel() { Id = 1, Name = "Detail home view." };
string friendlyTitle = FriendlyUrlHelper.GetFriendlyTitle(viewModel.Name);
// Compare the title with the friendly title.
if (!string.Equals(friendlyTitle, titl, StringComparison.Ordinal))
{
return RedirectToRoutePermanent("post_detail", new { id = viewModel.Id, title = friendlyTitle });
}
return View(viewModel);
}
and i have create custom route in startup.cs
app.UseMvc(routes =>
{
routes.MapRoute(
name: "post_detail",
template: "FriendlyUrl/index/{id}/{title}"
).MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
when i navigate to
https://xxxxx:2222/FriendlyUrl/index/2/dfdsfdsfds
browser display nothing,
I think issue is with custom routing, but i cant find it,
can someone help on this?
Thanks.
You don't have to add:
routes.MapRoute(
name: "post_detail",
template: "FriendlyUrl/index/{id}/{title}")
That is for the global 'controller/action' map rule.
Instead, to map specified path to action, consider adding an attribute like this:
[Route("FriendlyUrl/index/{id}/{title}")]
public IActionResult Index([FromRoute]int id, [FromRoute]string title)
{
}
FAQ
How to use route name to redirect?
Simply add a name to your route. Like this:
[Route("FriendlyUrl/index/{id}/{title}", Name = "post_detail")]
public IActionResult Index([FromRoute]int id, [FromRoute]string title)
{
}
To route to this action from another controller or action, call it with:
// in action
return RedirectToRoute("post_detail");
// or
return RedirectToRoutePermanent("post_detail");
// I guess you don't have to lose the `Id`:
return RedirectToRoutePermanent("post_detail", new { id = 5 });
How to allow receiving null to title
Simply add a ? to the route template. Like this:
[Route("FriendlyUrl/index/{id}/{title?}", Name = "post_detail")]
public IActionResult Index([FromRoute]int id, [FromRoute]string title)
{
}

Nopcommerce RegisterRoutes

Hi I have problem with routes in plugin, in nopcommerce 3.6
I have in folder Controller TestPohodaController.cs contains method ImportProductInfo()
There is my RegisterRoutes:
namespace Nop.Plugin.Test.Pohoda
{
public partial class RouteProvider : IRouteProvider
{
public void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute("Plugin.Test.Pohoda.ImportProductInfo",
"Plugins/TestPohoda/ImportProductInfo",
new { controller = "TestPohoda", action = "ImportProductInfo" },
new[] { "Nop.Plugin.Test.Pohoda.Controllers" }
);
}
public int Priority
{
get
{
return 0;
}
}
}
}
Installation to nopCommerce is ok, but when I go to mypage/Plugins/TestPohoda/ImportProductInfo page return 404.
I need url of TestPohodaController to call this controller from economic system. Can You help me please? Thanks.
ASP.NET MVC Routing evaluates routes from top to bottom. So if two routes match, the first one it hits (the one closer to the 'top' of the RegisterRoutes method) will take precedence over the subsequent one.
With that in mind, you need to do two things to fix your problem:
Your default route should be at the bottom.
Your routes need to have constraints on them if they contain the same number of segments:
What's the difference between:
example.com/1
and
example.com/index
To the parser, they contain the same number of segments, and there's no differentiator, so it's going to hit the first route in the list that matches.
To fix that, you should make sure the routes that use ProductIds take constraints:
routes.MapRoute(
"TestRoute",
"{id}",
new { controller = "Product", action = "Index3", id = UrlParameter.Optional },
new { id = #"\d+" } //one or more digits only, no alphabetical characters
);
You don't need to start with Plugins for your route url. it is enough
to follow this pattern {controller}/{Action}/{parameter}
Make sure also namespace for the controller is correct as you define
in the routing. Nop.Plugin.Test.Pohoda.Controllers
You can define an optional productId parameter as well. so it will
work for mypage/TestPohoda/ImportProductInfo or
mypage/TestPohoda/ImportProductInfo/123
You can also set the priority higher than 0 which is priority of the
default routeprovider in the nop.web. this way you ensure that your
plugin reads it first. Indeed it is not necessary as you have
specific url. this is only required if you have similar route url
Try using this route
namespace Nop.Plugin.Test.Pohoda
{
public partial class RouteProvider : IRouteProvider
{
public void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute("Plugin.Test.Pohoda.ImportProductInfo",
"TestPohoda/ImportProductInfo/{productId}",
new { controller = "TestPohoda", action = "ImportProductInfo" , productId = = UrlParameter.Optional },
new[] { "Nop.Plugin.Test.Pohoda.Controllers" }
);
}
public int Priority
{
get
{
return 1;
}
}
}
}
We will have a look at how to register plugin routes. ASP.NET routing is responsible for mapping incoming browser requests to particular MVC controller actions. You can find more information about routing here. So follow the next steps:
If you need to add some custom route, then create RouteProvider.cs file. It informs the nopCommerce system about plugin routes. For example, the following RouteProvider class adds a new route which can be accessed by opening your web browser and navigating to http://www.yourStore.com/Plugins/PaymentPayPalStandard/PDTHandler URL (used by PayPal plugin):
public partial class RouteProvider : IRouteProvider
{
public void RegisterRoutes(IRouteBuilder routeBuilder)
{
routeBuilder.MapRoute("Plugin.Payments.PayPalStandard.PDTHandler", "Plugins/PaymentPayPalStandard/PDTHandler",
new { controller = "PaymentPayPalStandard", action = "PDTHandler" });
}
public int Priority
{
get
{
return -1;
}
}
}
It could be cache problem, try to restart IIS
actually you do nota have to register route by default you can call your method
/TestPohoda/ImportProductInfo

Strange behaviour with controller and view inside area MVC 5

I have one area called user.
The area configuration looks like this
context.MapRouteLowercase(name: "User_Member", url: "User/Member", defaults: new { controller = "User", action = "Member", id = UrlParameter.Optional });
When I browse to this page without passing in a id, it returns the view my url looks like this /user/member
When I type the following into the browser /user/member/1
I've put a break point on
var userId
and it gets hit and I check the id parameter and its 1 which is correct.
[HttpGet]
[Authorize]
public ActionResult Member(Int64 id = 0)
{
var userId = id != 0 ? id : ReturnUserId();
var model = _userProfileBusinessLayer.GetProfile(userId);
return View(model);
}
Yet when I press F5 I get the following page
Server Error in '/' Application.
The view 'member' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/user/member.aspx
~/Views/user/member.ascx
~/Views/Shared/member.aspx
~/Views/Shared/member.ascx
~/Views/user/member.cshtml
~/Views/user/member.vbhtml
~/Views/Shared/member.cshtml
~/Views/Shared/member.vbhtml
I'm unsure why I'm seeing that because all I have done is added /1 to the url?
I should be seeing the profile of the user which matches then id of 1, yet I remove /1 and it returns the view ?!?!?!?! slightly baffled
In your project, the area user should have a class that inherits from AreaRegistration e.g.
public class UserAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "user";
}
}
}
In that class you can define routes sepcific for that area:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"UserManagement",
"user/Admin",
new { controller = "UserAdmin", action = "Index" });
}
The file Global.asax.cs should have an Application_Start() method which calls:
AreaRegistration.RegisterAllAreas();
That will pick up the area routes you have configured. This is usually how area routes are configured. Do you have a similar setup for your project?

Add parameter to all Incoming/Outgoing URL's

I'm having trouble adding a URL parameter to every URL generated, or redirected to in an ASP MVC 4 application.
I want to generate an ID, and use this ID at any point throughout the application. Storing the id in session is not an option as a single session may have multiple browser windows/tabs open concurrently (each with a different id)
RouteConfig
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{customId}",
defaults: new { controller = "Home", action = "Index", customid = UrlParameter.Optional }
);
HomeController.cs
public class HomeController : Controller
{
public ActionResult Index()
{
var customId = Guid.NewGuid();
ControllerContext.RequestContext.RouteData.Values.Add("customId", customId);
//How do I get this redirect to add customid to the url?
//E.g. /Home/Start/{customId}
return RedirectToAction("Start");
//I could do this: But I want it this to happen for every URL,
//and I don't want to replicate this code everywhere
//return RedirectToAction("Start", new { customId = customId });
}
public ActionResult Start()
{
object customId;
//Redirect Loop
if (!Request.RequestContext.RouteData.Values.TryGetValue("customId", out customId))
{
//To generate the ID
return RedirectToAction("Index");
}
ViewData["customId"] = Guid.Parse(customId.ToString());
return View();
}
public ActionResult Next()
{
object customId;
//Redirect Loop
if (!Request.RequestContext.RouteData.Values.TryGetValue("customId", out customId))
{
//To generate the ID
return RedirectToAction("Index");
}
ViewData["customId"] = Guid.Parse(customId.ToString());
return View();
}
}
Not only do I want the ID to be automatically inserted into any Redirect results, but when a View is rendered #Url.Action() and #Html.ActionLink() should also add the ID to the generated URL's.
Start.cshtml
#*Both of these should generate an href="~/Home/Next/{customId}"*#
#Html.ActionLink("Go to Next", "Next", "Home")
Go to Next
How do I automatically add an ID to ALL outgoing routes in ASP MVC?
Create an action filter that will add the ID to the route data in the OnActionExecuting method? You can access the controller through the filter context (and the viewbag). As long as your viewbag contains the customId, you should be able to add it to the route data. At least this way you only need to remember to add the attribute on the controller.
OR
Create a base class that inherits from System.Web.Mvc.Controller and implement your own RedirectToAction. Then have all your controllers inherit form MyControllerBase. Something like this.
public class MyControllerBase : Controller
{
public RedirectToRouteResult RedirectToAction<TController>(Expression<Func<TController, object>> actionExpression)
{
var custId = ControllerContext.Controller.ViewBag["customId"];
string controllerName = typeof(TController).GetControllerName();
string actionName = actionExpression.GetActionName();
return RedirectToAction(actionName, controllerName, new {cId = custId});
}
}
PART 2:
Another way I've modified a URL (I knew I had the code somewhere!) on every view, I needed the URL to link from a mobile site to a full browser site and read the mappings from the database. So in my footer, I have the following:
<a id="fullSiteLink" href="<%= ViewData[AppConstants.MainSiteUrl] %>">Visit our Full Browser site</a><br />
I then added a filter to the base controller class and onactionexecuting (before the action),
public void OnActionExecuting(ActionExecutingContext filterContext)
{
var mainSiteUrl = _mobileToMainRedirect.GetMainSiteUrl(filterContext.HttpContext.Request.Url);
filterContext.Controller.ViewData.Add(AppConstants.MainSiteUrl, string.IsNullOrEmpty(mainSiteUrl) ? UrlHelperExtensions.FullBrowserSite(filterContext.HttpContext.Request.Url) : mainSiteUrl);
}
Complete shot in the dark....
You can set up the route so that if a value is not provided, you create the Id. This way, if the value is there, it will use the provided one. Otherwise, it will create one.
Since this is leveraging the routes, you will be able to generate the Id even when using:
#Html.ActionLink("Go to Next", "Next", "Home")
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{customid}",
defaults: new { controller = "Home", action = "Index", customid = Guid.NewGuid() }
);
NOTE: You would replace Guid.NewGuid() with your own Id generator.

Redirect to another controller/Action not registered in route

iam having controller like below which is not registered in routes table
public class InternalController : Controller
{
/*this controller is not registered in routes table*/
public ActionResult Foo()
{
return Content("Text from foo");
}
}
From another controller which is registered in Routes table i want to call/redirect action of previous controller, one which is not registered in routes table.
public class AjaxController : Controller
{
/*this controller is registered in routes table*/
public ActionResult Foo()
{
/*FROM HERE HOW DO I RETURN CONTENTS OF
controller=InternalController, action = Foo
*/
/*
i tried below piece of code but that doesnt seem to work
*/
return RedirectToAction("Foo", "InternalController ");
}
}
Defined Routes (only one item added)
public void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute("Ajax","ajax/{action}",new {
controller="Ajax",
action="Index"
});
}
If you are choosing not to register a route... then you probably have the file/controller in a specific location that will not change.
In that event, just use the "Redirect" method, instead of "RedirectToAction".
For example:
return Redirect("~/Internal/Foo");
Now that you have shown your routes definition, it is obvious that you can never invoke any other controller than AjaxController. You simply forbid them in your routes, so InternalController could never be served. You will have to change your route definition.
Depending on what you want to achieve and how you want your urls to look like you have a couple of possibilities:
Leave the default route
Modify your existing route definition like so:
routes.MapRoute(
"Ajax",
"{controller}/{action}",
new { controller = "Ajax", action = "Index" }
);
You can create RedirectController for redirecting more Url and pages:
public class RedirectController : Controller
{
public ActionResult Index()
{
var rd = this.RouteData.Values;
string controller = rd["controller2"] as string;
string action = rd["action2"] as string;
rd.Remove("controller2");
rd.Remove("action2");
rd.Remove("controller");
rd.Remove("action");
return RedirectToActionPermanent(action, controller, rd);
}
}
And then you can define redirect from old url in routing tables:
routes.MapRoute(
null, // Name
"ajax/foo",
new { controller = "Redirect",
action = "Index",
controller2 = "InternalController",
action2 = "Foo"}
);
This pattern is also useful if you redirect old url to new one. For example:
routes.MapRoute(
null, // Name
"default.aspx", // redirect from old ASP.NET
new { controller = "Redirect",
action = "Index",
controller2 = "Home",
action2 = "Index" }
);

Categories

Resources