Background
In HomeController.cs I have:
[HttpGet]
public GetPerson(string name)
{
return View(new PersonModel { ... });
}
In Global.asax.cs I have:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Word", "person/{name}",
new { controller = "Home", action = "GetPerson" });
routes.MapRoute(
"Default", "{controller}/{action}",
new { controller = "Home", action = "Index" });
}
In SomePage.cshtml I have, effectively, this:
#{ var name = "Winston S. Churchill"; }
#name
Problem
If I click the link for Winston S. Churchill, I am routed to the URL http://localhost/person/Winston%20S.%20Churchill, which yields the standard 404 page:
HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
This only happens if the name variable contains a . (period). All my code works perfectly fine when the name is, for example, Winston Churchill.
How can I make ASP.NET MVC 3 percent-encode the . (period) in the URL?
Or, how can I make the routing work without . (period) being percent-encoded?
Unacceptable Workaround (if presented without justification)
If I change the route to the following, everything works.
routes.MapRoute(
"Word", "person",
new { controller = "Home", action = "GetPerson" });
However, the URL becomes http://localhost/person?name=Winston%20S.%20Churchill, which isn't what I want. I want the name in the path part of the URL, not the query.
Routes which contain a period and unknown extension are interpreted by IIS as static files and not sent through the .NET pipeline. For example, the URL you cite is interpreted as a static file with a %20Churchill extension.
You can force ASP.NET to handle all requests by adding this to web.config:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
You'll also need this, to handle name values that end with a period (as opposed to just containing one):
<system.web>
<httpRuntime relaxedUrlToFileSystemMapping="true" />
</system.web>
All /person/{name} URLs will then be picked up by your ASP.NET code.
If you would rather not use this setting, the easiest workaround would be to use a custom encoding:
name.Replace(".","--")
Related
I have a requirement in which I need to use a key that will come from the webconfig file which will specify which View to render when the application will start. This is only a one time thing since after the application starts, the other operations work normally. I have tried to look for some filter methods but they work after the application starts. I am looking for a solution that will only check for this key once and render the appropriate View. This is specifically for Mobile Views. I have registered my DisplayModeProvider in Application_Start().
Do I need to do this in RouteConfig.cs or ApplicationStart() method?
It would be great if someone could direct me in the right direction.
This will be achieved by specifying the Default Route in RouteConfig.cs.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
"Default", // Route name
"{" + WebConfigurationManager.AppSettings["DefaultController"] + "}/{" + WebConfigurationManager.AppSettings["DefaultAction"] + "}/{id}", // URL with parameters
new { controller = "Default", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
And in your Web.config file :
<add key="DefaultController" value="Default" />
<add key="DefaultAction" value="Index"/>
So I achieved this functionality by doing the following:
Setup my logic for finding out the device the application is rendered on by using DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("Mobile") in the Application_Start() method
Adding a key called IsOnePageViewEnabled in the web.config
Bind my Landing Page to a View called Index.mobile, since MVC automatically looks for a *.mobile.cshtml when you start the application
When the Index.mobile is rendered on a mobile, I retrieved my key from the web.config: var IsOnePageViewEnabled = #ConfigurationManager.AppSettings["IsOnePageViewEnabled"];
The last step was simply checking this key and then redirecting to the appropirate View:
#if (IsOnePageViewEnabled == "0")
{
<script>
window.location.href = '#Url.Content("~")' + "Home/MindexO";
</script>
}
else
{
<script>
window.location.href = '#Url.Content("~")' + "Home/Mindex";
</script>
}
If there are other and better ways to achieve this functionality, I would really like to know.
I have developed an ASP MVC 5 website with the following route:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{language}",
defaults: new
{
controller = "Member",
action = "Index",
language = UrlParameter.Optional
});
}
I only have that one controller, Member, and everything works running on IISExpress on my local dev machine. But when I try to deploy and access the site on my development server, I get 404 error. The URL I'm passing to it is identical to the one I'm using on the development machine, yet it seems like the routing is not working as expected. Here's a sample URL:
http://myserver:8080/Member/GetCertificate/en-US?mn=MjMzOTA3MDc4MDA=&gn=NjcwNzkz
This is the only route registered on my application, and I've tried to register the wildcard script on IIS, as well as editing my web config with the following entries:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<remove name="UrlRoutingModule-4.0"/>
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition=""/>
</modules>
</system.webServer>
The development server is running IIS 7.5. I have tried to access the page remotely from my development machine as well as locally from the web server, with no luck. Here's what the action method looks like for reference:
[HttpGet]
public FileResult GetCertificate(string language, string mn, string gn)
{
var member = new Member()
{
MemberNumber = Encoding.Default.GetString(
Convert.FromBase64String(mn)),
GroupNumber = Encoding.Default.GetString(
Convert.FromBase64String(gn)),
Language = language
};
var certificate = this.certificateRepository
.GetCertificateDocument(member);
return this.File(certificate, "application/pdf");
}
I have continued debugging it, and I found that the problem seems to be that it's recognizing the action as the controller, so if I use the following URL, it works:
http://myserver:8080/Member/Member/GetCertificate/en-US?mn=MjMzODU1NjE5MDE=&gn=NzkxMjgz
But I end up repeating the controller name, which makes for a not so readable URL. Any way around this, though? Maybe I missed something?
The problem was that my application within IIS had a name conflict with my controller. The structure in my IIS was as follows:
MemberSite
Member
MemberService
And the controller in my MVC application was also called MemberController. This caused confusion, because I thought I was referencing the controller, when I was actually referencing the application itself. So for readability, I renamed the application in IIS to MemberApp, and the final URL looks like this:
http://myserver:8080/MemberApp/Member/GetCertificate/en-US?mn=MjMzODU1NjE5MDE=&gn=NzkxMjgz
I have a controller in an MVC 4 .NET application that receives a string as a parameter from an URL. This comes from an aspx page redirected to the controller in Route.config.
If I send this value for the parameter in the client: fwdgerhb+bhrth+ftrgbhrt
I get the following value at the server: fwdgerhb bhrth ftrgbhrt
The server is interpreting the URL parameter value as an encoded URL and replaces + by . But it has not been URL encoded. This will occur for other combinations of special chars if they appear in the parameter value.
Is there a config parameter in IIS Server to configure the server to not try to URL-decode this value?
Example Request:
mypage.aspx?value=cat+dog (NOT ENCODED)
Route Config
static void RegisterRoutes(RouteCollection routes)
{
routes.MapRouteLowercase(
name: "MyRouter",
url: "mypage.aspx",
defaults: new { controller = "My", action = "DoLog" }
);
}
The controller:
public class MyController : Controller
{
[AllowAnonymous]
public ActionResult DoLog(string value)
{
//Here value has "cat dog"
}
}
You can use the following to grab the query-string manually from the controller:
Request.QueryString.Get("value");
Or, to get it from the view:
Html.ViewContext.HttpContext.Request.QueryString.Get("value");
But honestly, why not just encode the string yourself before you send it through the routing:
HttpUtility.UrlEncode(value);
and then when you get the the value again:
HttpUtility.UrlDecode(value);
So that way you have control of your string
Update
You can also do the following to allow your routeConfig to allow the "+" attribute:
<location path="CustomHttpHandler">
<system.webServer>
<security>
<requestFiltering allowDoubleEscaping="true" />
</security>
</system.webServer>
</location>
Here is a question that tells you the ups and downs of turning this on and off: Is Enabling Double Escaping Dangerous?
Yes, MVC automatically URL decodes action parameters, but you can still access the URL encoded version through a query string. As you can see in this question: Is MVC2 ASP.Net URLDecoding automatically?
You can also try to access a server variable named UNENCODED_URL. More information about this scenario can be found here: URL Rewrite Module Configuration Reference
I'm newbie to MVC. I could integrate MVC 5.2 to my existing web forms Visual Studio 2012 Update 4 project. I created my first controller and all worked as expected. Even I was able to leverage the windows forms authentication from my existing project when accessing the MVC view. But when created my second controller it began messing up.
It is my route mapping:
public static class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.EnableFriendlyUrls();
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
I have two controllers both located in ~/Controllers. My first controller is:
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
//return View();
return Redirect("~/Default.aspx");
}
public ActionResult CloseSession()
{
return Redirect("http://www.yahoo.com");
}
}
The second controller:
public class CajaWebController : Controller
{
//
// GET: /CajaWeb/
public ActionResult Index()
{
return View();
}
public ActionResult CloseSession()
{
return Redirect("http://www.cnn.com");
}
}
I don't know is it relevant to the problem but I'll include how the MVC view is reached. My VS2012 start url is
http://localhost/Fortia/CajaWeb.
Fortia is my app name. Because I declared Web Forms authentication and
<location path="CajaWeb">
<system.web>
<authorization>
<allow roles="Fortia" />
<deny users="*" />
</authorization>
</system.web>
</location>
when starting to debug the old WebForms app authentication mechanism is called, the old WebForms login page invoked and after a successful login finally my CajaWebController, Index() action is called. Before creating CajaWebController it was the HomeController who was called, but I assume MVC now deduces the correct controller is CajaWeb because of the targeted url being
http://localhost/Fortia/CajaWeb.
The invoked view contains the following code:
<a href='#Url.Action("CloseSession", "CajaWeb")'>Close session</a>
The problem is when clicking the generated link the MVC calls HomeController.Index() action despite I explicitly set CajaWebController.CloseSession() in the #Url.Action...
I looked at the generated link and it looks wrong:
<a href='/Fortia/__FriendlyUrls_SwitchView?action=CloseSession&controller=CajaWeb'>
it encoded the parameter separator & into & But anyway I tried handcoding the href as
http://localhost/Fortia/__FriendlyUrls_SwitchView?action=CloseSession&controller=CajaWeb
but the result was the same.
What is wrong?
It would seem the ASP.NET Friendly Urls package you're using is interfering with the urls MVC is generating. The library seems to be meant for WebForms anyway
If it works without, then leave it like that as MVC's urls are already quite SEO-friendly when controller and action names are meaningful to their content.
I think the problem is that the route
http://localhost/Fortia/CajaWeb
doesn't match any routes so it ends up going to the default route specified in RouteConfig. You need to configure a route or create an area in your app called "Fortia".
A specific page in my web application has a URL www.example.com/Test/Index
However, I want to make this URL accessible when the user simply inputs www.example.com/Test instead of the whole thing.
So how can this be done using C# alone? Any help will be highly appreciated!
You can use a redirect. In ASP.NET this is Response.Redirect. In MVC this is RedirectToAction("Index"). This will cause their browser to then request the other URL.
If you want the URL to not be changed/redirected, and show www.example.com/Test, then you can use a server side redirect. ASP.NET: Server.Transfer. In MVC you can just return Index(); but this can be problematic sometimes. A better option is to use a default route:
public class MvcApplication : System.Web.HttpApplication
{
...
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Test", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
You should get this code automatically with any newly created MVC 3 application. you just have to custimize it for the controller you want to respect this default route.