How to route a .aspx page in asp.net mvc 3 project? - c#

I have a .aspx page in the following path:
Areas/Management/Views/Ticket/Report.aspx
I want to route that to the following path in my browser:
http://localhost/Reports/Tickets
How can i do that?
I try this:
routes.MapRoute(
"Tickets", // Route name
"Areas/Management/Views/Ticket/Report.aspx", // Original URL
new { controller = "Reports", action = "Tickets" } // New URL
);
But i got the 404 error.
What i'm doing wrong?
Obs: I put that before the Default route.

If you are trying to utilise web forms in a MVC project then I would move your .aspx out of the views folder, as it isn't really a view, so something like WebForms/Tickets/Report.aspx.
In web forms you map a route by calling the MapPageRoute method.
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapPageRoute("Tickets", "Reports/Tickets", "~/WebForms/Tickets/Report.aspx");
routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional });
You'll need to put that before the default MVC route.

Solved! So, we need to add a route contraint to the webforms route to ensure that it only catches on incoming routes, not outgoing route generation.
Add the following class to your project (either in a new file or the bottom of global.asax.cs):
public class MyCustomConstaint : IRouteConstraint{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection){
return routeDirection == RouteDirection.IncomingRequest;
}
}
Then change the Tickets route to the following:
routes.MapPageRoute(
"Tickets",
"Reports/Tickets",
"~/WebForms/Reports/Tickets.aspx",
true, null,
new RouteValueDictionary { { "outgoing", new MyCustomConstaint() } }
);

you are doing it opposite. this maps your url Areas/Management/Views/Ticket/Report.aspx to { controller = "Reports", action = "Tickets" }
what u should do instead is
set the url as Reports/Tickets
EDIT:- you can create a routeHandler just for routing to this .aspx page.. like this.
public class ASPXRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return BuildManager.CreateInstanceFromVirtualPath("~/Areas/Management/Views/Ticket/Report.aspx", typeof(Page)) as Page;
}
}
then u can add ur route to the existing routes table using
Route customRoute = new Route("Reports/Ticket",null, new ASPXRouteHandler());
routes.Add(customRoute);

if you leave the default routing when you create the asp.net project
public class ReportsController : Controller
{
public ActionResult Ticket()
{
return View();
}
}
this should do the trick.
The routing in asp.net mvc means that you don't link directly to .aspx but to Actions (methods) that in turn return an appropriate view (.aspx)

Related

setting custom routes only form some pages in asp.net web forms

I made a website using asp.net webforms. It uses the default route which is url friendly. Can I set a custom route for some pages by assigning it to global.asax without affecting all other pages route?
By default MVC uses the conventional routing which uses something of this sort.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Which translates to http://localhost:9999/<controllerName>/<ActionName>/<OptionalIDs>
But if you want custom routes its possible in ASP.NET MVC 5 this feature is called Attribute Routing, if you are using Visual Studio 2015 or above.
For example:
Adding the following line to your global.asax.cs file will enable attribute routing in your MVC 5 application:
routes.MapMvcAttributeRoutes();
This will be rendered as http://localhost:9999
[HttpGet]
[Route(Name = "HomeView")]
public ActionResult Index()
{
return View();
}
This will be rendered as http://localhost:9999/Login
[HttpGet]
[Route("~/Login", Name = "LoginGET")]
public ActionResult Login()
{
return View();
}
In your view you can use the Html.BeginRouteForm("<RouteName>", FormMethod.Post) helper method for handling routes.
[HttpPost]
[Route("~/Login", Name = "LoginPOST")]
public ActionResult Login(FormCollection UserCredentials)
{
//do stuff
return RedirectToRoute("HomeView");
}
For referring MVC Actions via Routes in _layout.html you can use:
Html.RouteLink("Link text that you want to display in the view", "<RouteName>");
For More information you can always check MSDN Attribute Routing.

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.

Is it possible for two areas to share the same route and still both be reachable?

I have two areas that register routes as shown below:
"Website" area:
context.MapRoute(
"Landing Controllers",
"{controller}/{action}",
new { controller = "Home", action = "Index" }
);
"Mobile" area:
context.MapRoute(
"Mobile Defaults",
"{controller}/{action}",
new { controller = "MobileHome", action = "Index" },
new { controller = "MobileHome", action = "Index" }
);
By default, one or the other of these routes would be consistently taken when trying to go to the root URL /. But suppose we decorated our controller actions with a custom AuthorizeAttribute, where the OnAuthorization method is overridden to redirect the user to the correct controller when appropriate, as below. (Idea taken from a great blog post.)
public class MobileRedirectAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
var result = // Logic to generate the ActionResult that conditionally
// takes us to the other route goes here.
filterContext.Result = result;
}
}
I've tried using a new RedirectResult and RedirectToRouteResult, neither of which work as I'd like because of the routing conflict. Is there a way to set AuthorizationContext.Result to a value that would take us to the action that we're not currently executing? (As a last resort, I can just prefix the mobile route with some sort of namespacing variable, but I'd like to avoid going down that road just yet.)
My question can probably also be summarized by having a look at Wikipedia's desktop/mobile routing. Their two sites, http://en.m.wikipedia.org/wiki/Main_Page and http://en.wikipedia.org/wiki/Main_Page also share identical routes, but, depending on which mode you're in, return very different results.
Would it be possible to set up Wikipedia's routing in an MVC project where each environment (mobile/desktop) is registered in its own area?
A colleague led me to a promising solution using a custom IRouteConstraint.
public class HelloWorldConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route,
string parameterName, RouteValueDictionary values,
RouteDirection routeDirection)
{
// Determine whether to accept the route for this request.
var browser = BrowserDetector.Parse(httpContext.Request.UserAgent);
if (browser == BrowserPlatform.Mobile)
{
return true;
}
return false;
}
}
And my route declaration now looks like the below, where the route constraint is attached to a route parameter chosen at random.
context.MapRouteLowercase(
"Mobile Defaults",
"{controller}/{action}",
new { controller = "MobileHome", action = "Index" },
// In this case, it's not so much necessary to attach the constraint to
// a particular route parameter as it is important to be able to inspect
// the HttpContextBase provided by the IRouteConstraint.
new {
controller = new HelloWorldConstraint()
}
);
Not with standard MVC Routing. You can probably do with attribute routing, available in either MVC 5 or via the nuget package, AttributeRouting.

How to set up routing so that Index does show?

So I know google can penalize a site if you have the same content on multiple urls... unfortunately, in MVC this is too common i can have example.com/, example.com/Home/ and example.com/Home/Index and all three urls would take me to the same page... so how do I make sure that whenever Index is in the url, that it redirects to the same without the Index and of course the same thing with the Home
Perhaps this little library may be useful for you.
This library is not very convinient in your case, but it should work.
var route = routes.MapRoute(name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
routes.Redirect(r => r.MapRoute("home_index", "/home/index")).To(route);
routes.Redirect(r => r.MapRoute("home", "/home")).To(route);
The way I handle this is for default pages like Index is to simply create an explicit route for only one of them. I.e. "example.com/People" would be the route for People/Index, and there would be no valid page at the url "/example.com/People/Index".
The Home example is unique in that it has potentially three different URLs. Again in this case I'd simply create a route for "example.com" for that Index action, and not support the other two urls. In other words, you would never link to the other forms of the URL, so their absence should never cause a problem.
We use a Nuget package called AttributeRouting to support this. When you specifiy a GET route for a page, it overrides the defaults for MVC.
Using AttributeRouting usually you'd map the index to [GET("")] but for the special case of Home where you also want to also support the root URL that omits the controller name , I think you'd also add an additional attribute with IsAbsoluteUrl:
public class HomeController : BaseController
{
[GET("")]
[GET("", IsAbsoluteUrl = true)]
public ActionResult Index()
{...
So I found a way to do it without any external Library...
In my RouteConfig I had to add these two routes at the top, just below the IgnoreRoute
routes.MapRoute(
"Root",
"Home/",
new { controller = "Redirect", action = "Home" }
);
routes.MapRoute(
"Index",
"{action}/Index",
new { controller = "Redirect", action = "Home" }
);
Then I had to create a new Controller called Redirect and I created a method for each of my other Controllers like this:
public class RedirectController : Controller
{
public ActionResult Home()
{
return RedirectPermanent("~/");
}
public ActionResult News()
{
return RedirectPermanent("~/News/");
}
public ActionResult ContactUs()
{
return RedirectPermanent("~/ContactUs/");
}
// A method for each of my Controllers
}
That's it, now my site looks legit. No more Home, no more Index in my URLs, this of course has the limitation of not being able to accept parameters to any of the Index methods of your Controllers though if it was really necessary, you should be able to tweak this to achieve what you want.
Just an FYI, if you want to pass an argument to your Index Action, then you can add a third route like this:
routes.MapRoute(
name: "ContactUs",
url: "ContactUs/{id}/{action}",
defaults: new { controller = "ContactUs", action = "Index", id = UrlParameter.Optional }
);
This will create a URL like this: /ContactUs/14

ASP.Net MVC route mapping

I'm new to MVC (and ASP.Net routing). I'm trying to map *.aspx to a controller called PageController.
routes.MapRoute(
"Page",
"{name}.aspx",
new { controller = "Page", action = "Index", id = "" }
);
Wouldn't the code above map *.aspx to PageController? When I run this and type in any .aspx page I get the following error:
The controller for path '/Page.aspx' could not be found or it does not implement the IController interface.
Parameter name: controllerType
Is there something I'm not doing here?
I just answered my own question. I had
the routes backwards (Default was
above page).
Yeah, you have to put all custom routes above the Default route.
So this brings up the next question...
how does the "Default" route match (I
assume they use regular expressions
here) the "Page" route?
The Default route matches based on what we call Convention over Configuration. Scott Guthrie explains it well in his first blog post on ASP.NET MVC. I recommend that you read through it and also his other posts. Keep in mind that these were posted based on the first CTP and the framework has changed. You can also find web cast on ASP.NET MVC on the asp.net site by Scott Hanselman.
http://weblogs.asp.net/scottgu/archive/2007/11/13/asp-net-mvc-framework-part-1.aspx
http://www.asp.net/MVC/
I just answered my own question. I had the routes backwards (Default was above page). Below is the correct order. So this brings up the next question... how does the "Default" route match (I assume they use regular expressions here) the "Page" route?
routes.MapRoute(
"Page",
"{Name}.aspx",
new { controller = "Page", action = "Display", id = "" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
On one of Rob Conery's MVC Storefront screencasts, he encounters this exact issue. It's at around the 23 minute mark if you're interested.
Not sure how your controller looks, the error seems to be pointing to the fact that it can't find the controller. Did you inherit off of Controller after creating the PageController class? Is the PageController located in the Controllers directory?
Here is my route in the Global.asax.cs
routes.MapRoute(
"Page",
"{Page}.aspx",
new { controller = "Page", action = "Index", id = "" }
);
Here is my controller, which is located in the Controllers folder:
using System.Web.Mvc;
namespace MvcApplication1.Controllers
{
public class PageController : Controller
{
public void Index()
{
Response.Write("Page.aspx content.");
}
}
}
public class AspxRouteConstraint : IRouteConstraint
{
#region IRouteConstraint Members
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return values["aspx"].ToString().EndsWith(".aspx");
}
#endregion
}
register the route for all aspx
routes.MapRoute("all",
"{*aspx}",//catch all url
new { Controller = "Page", Action = "index" },
new AspxRouteConstraint() //return true when the url is end with ".aspx"
);
And you can test the routes by MvcRouteVisualizer

Categories

Resources