MapPageRoute fails to redirect to specified aspx page - asp.net

I have the following in my RouteConfig.cs file
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
// route default URL to index.aspx
routes.MapPageRoute(
routeName: "LoginPageRoute",
routeUrl: "login",
physicalFile: "~/Login.aspx"
);
routes.MapPageRoute("LoginPageRoute2", "login2", "~/Login.aspx");
}
However if I try to access my WebApp using "login" or "login2" I get a resource cannot be found error message.
http://localhost:4200/login2 - fails
http://localhost:4200/login - fails
http://localhost:4200/Login.aspx - loads fine
My Global.asax has the following
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}

A comment from somebody under my question guided me to the solution which was to move my custom routes ahead of the default routes.
Adding the following to Global.asax helped prove that this was indeed the issue.
public override void Init()
{
base.Init();
this.AcquireRequestState += showRouteValues;
}
protected void showRouteValues(object sender, EventArgs e)
{
var context = HttpContext.Current;
if (context == null)
return;
var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(context));
}
Putting a breakpoint on
var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(context));
Showed that my "login" mapping was using the default route mapping instead of my custom route mapping.
Thanks again #mason!

Related

Keep MVC.NET automatic routing, but add additional specific routes

I have a MVC.NET application that used the default routing engine to connect {controller}/{action}/{*pathInfo} and everything works fine. I've added some WCF services to the project and need to setup specific routes to reach them. The problem I'm running into is when I add the specific routes, the default automatic routing no longer functions. How can I either use the default route handler with some overrides, or if that is not possible setup a generic route handler that automatically handles all existing Controllers/Actions and static resources?
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add(new ServiceRoute("services/rest/InvoiceService", new WebServiceHostFactory(), typeof(InvoiceService)));
routes.Add(new ServiceRoute("services/soap/InvoiceService", new ServiceHostFactory(), typeof(InvoiceService)));
routes.Add(new ServiceRoute("services/soap/LoginService", new ServiceHostFactory(), typeof(LoginService)));
routes.Add(new ServiceRoute("services/rest/LoginService", new WebServiceHostFactory(), typeof(LoginService)));
/** WHAT GOES HERE? **/
routes.MapHttpRoute("Default", "{controller}/{action}/{*pathInfo}",
new { controller = "Home", action = "Index", id = "" });
}
protected void Application_Start()
{
//RouteConfig.RegisterRoutes(RouteTable.Routes); //OLD code that automatically handled routing
RegisterRoutes(RouteTable.Routes); //NEW code
}
I figured it out - for posterity, you need to add a constraint clause to the MapRoute MVC handler that excludes the pattern you have for the WCF services. Here is the final code block that worked. The key part was the REGEX to exclude services as a valid controller name.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { controller = #"^(?!services)\w+$" }
);
RouteTable.Routes.Add(new ServiceRoute("services/rest/InvoiceService", new WebServiceHostFactory(), typeof(InvoiceService)));
RouteTable.Routes.Add(new ServiceRoute("services/soap/InvoiceService", new ServiceHostFactory(), typeof(InvoiceService)));
RouteTable.Routes.Add(new ServiceRoute("services/soap/LoginService", new ServiceHostFactory(), typeof(LoginService)));
RouteTable.Routes.Add(new ServiceRoute("services/rest/LoginService", new WebServiceHostFactory(), typeof(LoginService)));
}

Best place to set CurrentCulture for multilingual ASP.NET WebAPI applications

based on this question (Best place to set CurrentCulture for multilingual ASP.NET MVC web applications) I'm looking for a global way to do the same for ASP.NET WebAPI.
My current implementation for ASP.NET MVC looks like this:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new CultureAwareControllerActivator()));
}
}
public class CultureAwareControllerActivator : System.Web.Mvc.IControllerActivator
{
public System.Web.Mvc.IController Create(System.Web.Routing.RequestContext requestContext, System.Type controllerType)
{
string cultureName = null;
// Attempt to read the culture cookie from Request
HttpCookie cultureCookie = requestContext.HttpContext.Request.Cookies["_culture"];
if (cultureCookie != null)
cultureName = cultureCookie.Value;
else
cultureName = requestContext.HttpContext.Request.UserLanguages != null && requestContext.HttpContext.Request.UserLanguages.Length > 0 ?
requestContext.HttpContext.Request.UserLanguages[0] : // obtain it from HTTP header AcceptLanguages
null;
// Validate culture name
cultureName = RoedingGmbh.Pis2Go.Web.Mvc.Helpers.CultureHelper.GetImplementedCulture(cultureName); // This is safe
// Modify current thread's cultures
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
// Currently the UI Language is only english
//Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
return DependencyResolver.Current.GetService(controllerType) as IController;
}
}
I'm trying to do the same things as in ASP.NET MVC, but following code doesn't work properly.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
GlobalConfiguration.Configuration.Services.Replace(typeof(System.Web.Http.Dispatcher.IHttpControllerActivator), new CultureAwareHttpControllerActivator());
}
}
public class CultureAwareHttpControllerActivator : System.Web.Http.Dispatcher.IHttpControllerActivator
{
public System.Web.Http.Controllers.IHttpController Create(System.Net.Http.HttpRequestMessage request, System.Web.Http.Controllers.HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("DE-de");
return GlobalConfiguration.Configuration.DependencyResolver.GetService(controllerType) as System.Web.Http.Controllers.IHttpController;
}
}
With that code, WebAPI cannot find any route anymore :(
What have I to do to get this to work!
Regards,
Daniel
If you want global localization for whole application, you can put the set culture code into the BeginRequest method of the HttpApplication in global asax file. This will set your culture in the most first place of each request and will affect every MVC and webapi request.
I'd use a ActionFilter
If you are using Asp.Net MVC
//A foreigner, has possibly brew a cookie for me
public class SpeakNativeTongueAttribute : ActionFilterAttribute, IActionFilter
{
const string cookieName = "culture";
void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
{
var cookieKeys = filterContext.RequestContext.HttpContext.Request.Cookies.AllKeys;
if (cookieKeys.Contains(cookieName))
{
//eat the cookie
var theCultureCookie = filterContext.RequestContext.HttpContext.Request.Cookies[cookieName];
var theCulture = theCultureCookie.Value;
//say thanks in native tongue
System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.GetCultureInfo(theCulture);
System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(theCulture);
}
else
{
//Didn't receive a cookie, don't speak their language, those bastards!
}
}
}
In Javascript you can set the language in a cookie named "culture"

Multiple types were found that match the controller named 'Home'. (Two Areas, Same controller name)

This is probably a duplicate to many but the obvious answers in them do not solve my problem.
I get:
Multiple types were found that match the controller named 'Home'. This can happen if the route that services this request ('{controller}/{action}/{id}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
The request for 'Home' has found the following matching controllers:
App.Web.Controllers.HomeController
App.Web.Areas.Mobile.Controllers.HomeController
I've setup a default namespace for my HomeController in Global.ascx.cs:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new string[] { "App.Web.Controllers.HomeController" }
);
(Verified that App.Web.Controllers.HomeController is not a typo).
And also registered the Mobile's HomeController in MobileAreaRegistration:
public override void RegisterArea(AreaRegistrationContext context) {
context.MapRoute(
"Mobile_default",
"Mobile/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Therefore, why is it that I still see the error message? I've built/cleaned and ran again. Still the same outcome.
This is how I register my routes:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
In your Global.asax route registration for obvious reasons replace:
new string[] { "App.Web.Controllers.HomeController" }
with:
new string[] { "App.Web.Controllers" }
That's a namespace constraint that you should use there, not a specific type.

how to simulate IgnoreRoute in my custom MvcRouteHandler

In my ASP.NET MVC3 App I try simulate "routes.IgnoreRoute("...")"
I create CustomMvcRouteHandler:
public class CustomMvcRouteHandler: MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
// do something
....
return base.GetHttpHandler(requestContext);
}
}
in my Global.asax.cs file i have:
protected void Application_Start()
{
// ............
RegisterRoutes(RouteTable.Routes);
// ............
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("elmah.axd");
//routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
).RouteHandler = new CustomMvcRouteHandler();
}
How can I do this ?
I'm not entirely sure what you mean in your question, but I'll try to answer it...
To simulate an IgnoreRoute all you need to do is associate an instance of the StopRoutingHandler from your route. If you're using the built-in ASP.NET "Route" class then you would do something like this:
routes.MapRoute(
"Ignore-This", // Route name
"ignore/{this}/{pattern}" // URL with parameters
).RouteHandler = new StopRoutingHandler();
Anything that matches that pattern will cause the routing system to immediately stop processing any more routes.
If you want to write your own custom route (for example, a new route type that derives from RouteBase), then from its GetRouteData method you need to return the StopRoutingHandler.
#Eilon is the correct answer. Here is an alternative syntax that feels more MVCish.
routes.Add("Ignore-This",
new Route(
"ignore/{this}/{pattern}",
new StopRoutingHandler())
);

Setting the default page for ASP.NET (Visual Studio) server configuration

When I build and run my application I get a directory listing in the browser (also happens for sub folders), and I have to click on Index.aspx. It's making me crazy.
Visual Studio 2008
ASP.NET Development Server 9.0.0.0
Right click on the web page you want to use as the default page and choose "Set as Start Page" whenever you run the web application from Visual Studio, it will open the selected page.
The built-in webserver is hardwired to use Default.aspx as the default page.
The project must have atleast an empty Default.aspx file to overcome the Directory Listing problem for Global.asax.
:)
Once you add that empty file all requests can be handled in one location.
public class Global : System.Web.HttpApplication
{
protected void Application_BeginRequest(object sender, EventArgs e)
{
this.Response.Write("hi# " + this.Request.Path + "?" + this.Request.QueryString);
this.Response.StatusCode = 200;
this.Response.ContentType = "text/plain";
this.Response.End();
}
}
Go to the project's properties page, select the "Web" tab and on top (in the "Start Action" section), enter the page name in the "Specific Page" box. In your case index.aspx
Similar to zproxy's answer above I have used the folowing code in the Gloabal.asax.cs to achieve this:
public class Global : System.Web.HttpApplication
{
protected void Application_BeginRequest(object sender, EventArgs e)
{
if (Request.Url.AbsolutePath.EndsWith("/"))
{
Server.Transfer(Request.Url.AbsolutePath + "index.aspx");
}
}
}
public class Global : System.Web.HttpApplication
{
protected void Application_BeginRequest(object sender, EventArgs e)
{
if (Request.Url.AbsolutePath.EndsWith("/"))
{
Server.Transfer("~/index.aspx");
}
}
}
One way to achieve this is to add a DefaultDocument settings in the Web.config.
<system.webServer>
<defaultDocument>
<files>
<clear />
<add value="DefaultPage.aspx" />
</files>
</defaultDocument>
</system.webServer>
If you are running against IIS rather than the VS webdev server, ensure that Index.aspx is one of your default files and that directory browsing is turned off.
This One Method For Published Solution To Show SpeciFic Page on startup.
Here Is the Route Example to Redirect to Specific Page...
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "YourSolutionName.Controllers" }
);
}
}
By Default Home Controllers Index method is executed when application is started, Here You Can Define yours.
Note : I am Using Visual Studio 2013 and "YourSolutionName" is to changed to your project Name..
I'm not sure what framework you are using but in ASP.NET MVC you can simply go to the App_Start folder and open the RouteConfig.cs file. The code should look something like this:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
You can change the landing page on the last line of code there after defaults.

Resources