Using dot in URL - asp.net-mvc

I have the following route in RouteConfig.cs:
routes.MapRoute(
"MyLegacyRoute",
"Content/bootstrap.css",
new { controller = "Legacy", action = "GetLegacyUrl", legacyUrl = "someUrl" });
~/Content/bootstrap.css exists and rather than display its content when I navigate to http://localhost:27541/Content/bootstrap.css, I want to hit the GetLegacyUrl action in the Legacy controller.
I have added this to Web.config:
<system.webServer>
<handlers>
<add name="UrlRoutingHandler" path="/Content/*" verb="GET" type="System.Web.Routing.UrlRoutingHandler" />
...
and
<system.web>
<httpRuntime targetFramework="4.5" relaxedUrlToFileSystemMapping="true"/>
...
However when I access http://localhost:27541/Content/bootstrap.css I get this error:
Server Error in '/' Application.
Cannot create an abstract class.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.MissingMethodException: Cannot create an abstract class.
My controller looks like this:
public class LegacyController : Controller
{
public ActionResult GetLegacyUrl(string legacyUrl)
{
return View((object)legacyUrl);
}
}
My view (GetLegacyUrl.cshtml) looks like this:
#model string
#{
ViewBag.Title = "GetLegacyUrl";
Layout = null;
}
<h2>GetLegacyUrl</h2>
The URL requested was #Model
I am trying to do this just so I can learn more about routing.
What can I do to successfully use this route?

I got it to work by putting this in RouteConfig.cs:
routes.RouteExistingFiles = true;
And by making the preCondition value an empty string:
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
in this file: C:\Users\user.name\Documents\IISExpress\config\applicationhost.config
I found the answer on pg 99/115 chapter 16 in Adam Freeman's Pro ASP.NET MVC5 book.
I also removed the handler I added in the Web.config and removed the relaxedUrlToFileSystemMapping="true" since that doesn't work in MVC5.

Related

Using a route to return 408 on a specific file name request

We have an issue whereby Outlook is misbehaving because it is attempting to read an autodiscover.xml on our domain, specifically https://example.com/autodiscover/autodiscover.xml.
The email host says that we should configure the websitefirewall to return a timeout error. However, the site is hosted on Azure, and I don't see any option to do that.
Therefore, I was wondering if this could be done in MVC? I tried the following:
public class AutoDiscoverController : Controller
{
[Route("autodiscover/autodiscover.xml")]
public ActionResult Index()
{
return new HttpStatusCodeResult(HttpStatusCode.RequestTimeout);
}
}
...but it doesn't work; I see a 404 page instead. A breakpoint on the method also never gets hit.
Is it possible to create a route that mimics a non-existent file to return the timeout error?
Duplicate question update
There is a similar question at Dots in URL causes 404 with ASP.NET mvc and IIS. However, this question differs in that:
The answer doesn't work in MVC5
I cannot create a rule to recognise a trailing slash in the URL, because Outlook is generating the URL and I have no control over that
What else I've tried...
In RouteConfig, I defined a custom route. It doesn't work; the route never gets hit.
routes.MapRoute(
name: "AutoDiscover",
url: "autodiscover/autodiscover.xml",
defaults: new { controller = "AutoDiscover", action = "Index" });
As above, but using url: "autodiscover/*"
routes.IgnoreRoute("autodiscover.xml");
Defined a Route attribute on the controller itself, then enable routes.MapMvcAttributeRoutes();
I found an answer, thanks to Rick Strahl's answer here, and related blog post.
For some reason, defining a route in the RouteConfig never hits, but doing it at controller level does work. However, an additional step is needed, as pointed out by Nkosi to get it to work.
1. Enable MVC Attribute Routing
This wires up the routing attributes at controller-level (done in the next step)
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes(); // <-- Added this
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
2. Add the Route as an attribute
public class AutoDiscoverController : Controller
{
[Route("autodiscover/autodiscover.xml")]
public ActionResult Index()
{
return new HttpStatusCodeResult(HttpStatusCode.RequestTimeout);
}
}
3. Configure a route based on specific files in web.config
I believe this forces MVC to take over what IIS would usually handle (as XML is considered a "static" file).
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<add name="dotless" path="*.less" verb="GET" type="dotless.Core.LessCssHttpHandler,dotless.Core" resourceType="File" preCondition="" />
<!-- Added this line -->
<add name="AutoDiscoverXmlFileHandler" path="autodiscover.xml" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" responseBufferLimit="0" />
</handlers>
</system.webServer>
Result

Why might I not be getting any results from MiniProfiler?

I can't seem to get any results from MiniProfiler.
I can see the XHR POST to /mini-profiler-resources/results returning a 404. The chrome request inspector gives me a standard server 404 page.
A GET on the same URL also returns a 404, but there is a message saying that "no results were found for the specified id" (I did add the id in the querystring).
When I look at /mini-profiler-resources/results-index it just gives me an empty table with the field headings in - name, started, sql, duration, etc.
I've tried a few things - details below - at this stage I am at a loss as to what I can try next. Any pointers or suggestions for debugging this problem would be much appreciated.
Installed Packages:
MiniProfiler (v3.2.0.157)
MiniProfiler.EF6 (v3.0.11)
MiniProfiler.MVC4 (v3.0.11)
Where MVC4 also caters for MVC5. Which this project is.
Relevant Code:
protected void Application_Start()
{
MiniProfilerEF6.Initialize();
MiniProfiler.Settings.Results_List_Authorize = IsUserAllowedToSeeMiniProfilerUI;
MiniProfiler.Settings.MaxJsonResponseSize = int.MaxValue;
Database.SetInitializer<ApplicationDbContext>(null);
GlobalFilters.Filters.Add(new ProfilingActionFilter());
var copy = ViewEngines.Engines.ToList();
ViewEngines.Engines.Clear();
foreach (var item in copy)
{
ViewEngines.Engines.Add(new ProfilingViewEngine(item));
}
}
protected void Application_BeginRequest(Object source, EventArgs e)
{
if (Request.IsLocal)
{
// this IS being hit
MiniProfiler.Start();
}
}
protected void Applicaton_EndRequest()
{
MiniProfiler.Stop(discardResults: false);
}
private bool IsUserAllowedToSeeMiniProfilerUI(HttpRequest httpRequest)
{
return true;
}
In HomeController.cs:
[AllowAnonymous]
public ActionResult Index()
{
var profiler = MiniProfiler.Current;
using (profiler.Step("Doing complex stuff"))
{
using (profiler.Step("Step A"))
{
ViewBag.Title = "Home Page";
}
using (profiler.Step("Step B"))
{
Thread.Sleep(250);
}
}
return View();
}
And in MasterLayout.cshtml:
#using StackExchange.Profiling;
...
#MiniProfiler.RenderIncludes()
I've Tried:
I have set discardResults to false, like this:
protected void Applicaton_EndRequest()
{
MiniProfiler.Stop(discardResults: false);
}
I can confirm that MiniProfiler.Start() IS getting hit when the page loads.
I can also confirm that the mini-profiler-resources/ route IS being found (using Haack's Route Debugger)
I have the following item in the <handlers> section of web.config, and it is in the correct section (e.g. this guy mistakenly put it in the ELMAH config ).
<add name="MiniProfiler" path="mini-profiler-resources/*" verb="*" type="System.Web.Routing.UrlRoutingModule" resourceType="Unspecified" preCondition="integratedMode" />
I have set all my output caching to 1 second.
I was using a custom applicationhost.config file to test on a custom url.
I tried removing the custom url bindings and just using the standard localhost:51347.
I also tried putting the snippet below into applicationhost.config instead of the standard web.config.
<add name="MiniProfiler" path="mini-profiler-resources/*" verb="*" type="System.Web.Routing.UrlRoutingModule" resourceType="Unspecified" preCondition="integratedMode" />
In applicationhost.config I tried changing
<section name="handlers" overrideModeDefault="Deny" />
to
<section name="handlers" overrideModeDefault="Allow" />
I've added the following into application_start:
MiniProfiler.Settings.MaxJsonResponseSize = int.MaxValue;
As recommended in this answer, I have tried uninstalling all related packages and reinstalling them in this order:
MiniProfiler
MiniProfiler.MVC4
MiniProfiler.EF6
Update
9 days on, the bounty expired and still no joy :(
If anybody reading this in the future has ideas / suggestions, I'd really like to hear them. MiniProfiler is such a great tool and I'm disappointed that I haven't been able to get it working on this occasion.
If I do find the answer myself, I'll post it.
After running into the same issue I found the answer here which worked fine.
http://www.mukeshkumar.net/articles/mvc/performance-test-with-miniprofiler-in-asp-net-mvc
If you get an error after running application with MiniProfiler.Mvc4 or MiniProfiler.Mvc3 which state “/mini-profiler-resources/includes.js 404 not found” then simply add the following line of code in Web.Config inside web server section.
<system.webServer>
<handlers>
<add name="MiniProfiler" path="mini-profiler-resources/*"
verb="*" type="System.Web.Routing.UrlRoutingModule"
resourceType="Unspecified" preCondition="integratedMode" />
</handlers>
</system.webServer>

Session Variable not accessible in a partial class

I have a asp.net mvc application and everything seems to be working fine on my Development machine however when I try to deploy and run the application on a server it gives me the following error:
System.NullReferenceException: Object reference not set to an instance of an object.
This happens on this line of code. All I am trying to do is set a value in the session.
I have this code inside a partial class of the Controller.
public partial class HomeController : BaseController
{
public ActionResult Index(string Value)
{
System.Web.HttpContext.Current.Session["Test"] = "world";
return View();
}
}
Thanks that led me to find solution here:
Solution 1 from ASP.NET MVC - Session is null worked for me.
"
Solution 1:
Link: HttpContext.Current.Session is null when routing requests
Got it. Quite stupid, actually. It worked after I removed & added the SessionStateModule like so:
<configuration>
...
<system.webServer>
...
<modules>
<remove name="Session" />
<add name="Session" type="System.Web.SessionState.SessionStateModule"/>
...
</modules>
</system.webServer>
</configuration>
Simply adding it won't work since "Session" should have already been defined in the machine.config.
Now, I wonder if that is the usual thing to do. It surely doesn't seem so since it seems so crude..."

Getting "A potentially dangerous Request.Path value was detected from the client (&)"

I've got a legacy code issue that requires that I support random URLs as if they were requests for the home page. Some of the URLs have characters in them that generate the error "A potentially dangerous Request.Path value was detected from the client (&)". The site is written with ASP.Net MVC 3 (in C#) and is running on IIS 7.5.
Here's an example URL...
http://mywebsite.example/Test123/This_&_That
Here's how I have my catch-all route setup (I have other routes to catch specific pages)...
routes.MapRoute(
"Default", // Route name
"{garb1}/{garb2}", // URL with parameters
new { controller = "Website", action = "Home", garb1 = UrlParameter.Optional, garb2 = UrlParameter.Optional } // Parameter defaults
);
I've added the following things to my web.config file...
<configuration>
<system.web>
<pages validateRequest="false" />
<httpRuntime requestValidationMode="2.0" />
</system.web>
<configuration>
I've also Added the ValidateInput attribute to the action that should be catching the urls...
public class WebsiteController : Controller
{
[ValidateInput(false)]
public ActionResult Home()
{
return View();
}
}
But I'm still getting the error. Any ideas why? Did I miss something? Right now I'm just running on my local dev server (I haven't tried these fixes in production yet).
While you could try these settings in config file
<system.web>
<httpRuntime requestPathInvalidCharacters="" requestValidationMode="2.0" />
<pages validateRequest="false" />
</system.web>
I would avoid using characters like '&' in URL path replacing them with underscores.
I have faced this type of error.
to call a function from the razor.
public ActionResult EditorAjax(int id, int? jobId, string type = ""){}
solved that by changing the line
from
<a href="/ScreeningQuestion/EditorAjax/5&jobId=2&type=additional" />
to
<a href="/ScreeningQuestion/EditorAjax/?id=5&jobId=2&type=additional" />
where my route.config is
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new string[] { "RPMS.Controllers" } // Parameter defaults
);
If you want to allow Html tags only for few textbox in mvc
You can do one thing
in controller
[ValidateInput(false)]
public ActionResult CreateNewHtml() //view
{
return View();
}
[ValidateInput(false)]
[HttpPost]
public ActionResult CreateNewHtml(cbs obj)//view cbs is database class
{
repo.AddHtml(obj);
return View();
}
We were getting this same error in Fiddler when trying to figure out why our Silverlight ArcGIS map viewer wasn't loading the map.
In our case it was a typo in the URL in the code. There was an equal sign in there for some reason.
http:=//someurltosome/awesome/place
instead of
http://someurltosome/awesome/place
After taking out that equal sign it worked great (of course).
Check the below lines are present in your web.config file
<system.web>
<httpRuntime requestPathInvalidCharacters="" />
</system.web>

ASP.NET MVC 404 Error Handling [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I properly handle 404 in ASP.NET MVC?
I've made the changes outlined at 404 Http error handler in Asp.Net MVC (RC 5) and I'm still getting the standard 404 error page. Do I need to change something in IIS?
I've investigated A LOT on how to properly manage 404s in MVC (specifically MVC3), and this, IMHO is the best solution I've come up with:
In global.asax:
public class MvcApplication : HttpApplication
{
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
Response.Clear();
var rd = new RouteData();
rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
rd.Values["controller"] = "Errors";
rd.Values["action"] = "NotFound";
IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
}
}
}
ErrorsController:
public sealed class ErrorsController : Controller
{
public ActionResult NotFound()
{
ActionResult result;
object model = Request.Url.PathAndQuery;
if (!Request.IsAjaxRequest())
result = View(model);
else
result = PartialView("_NotFound", model);
return result;
}
}
Edit:
If you're using IoC (e.g. AutoFac), you should create your controller using:
var rc = new RequestContext(new HttpContextWrapper(Context), rd);
var c = ControllerBuilder.Current.GetControllerFactory().CreateController(rc, "Errors");
c.Execute(rc);
Instead of
IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
(Optional)
Explanation:
There are 6 scenarios that I can think of where an ASP.NET MVC3 apps can generate 404s.
Generated by ASP.NET:
Scenario 1: URL does not match a route in the route table.
Generated by ASP.NET MVC:
Scenario 2: URL matches a route, but specifies a controller that doesn't exist.
Scenario 3: URL matches a route, but specifies an action that doesn't exist.
Manually generated:
Scenario 4: An action returns an HttpNotFoundResult by using the method HttpNotFound().
Scenario 5: An action throws an HttpException with the status code 404.
Scenario 6: An actions manually modifies the Response.StatusCode property to 404.
Objectives
(A) Show a custom 404 error page to the user.
(B) Maintain the 404 status code on the client response (specially important for SEO).
(C) Send the response directly, without involving a 302 redirection.
Solution Attempt: Custom Errors
<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Errors/NotFound"/>
</customErrors>
</system.web>
Problems with this solution:
Does not comply with objective (A) in scenarios (1), (4), (6).
Does not comply with objective (B) automatically. It must be programmed manually.
Does not comply with objective (C).
Solution Attempt: HTTP Errors
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problems with this solution:
Only works on IIS 7+.
Does not comply with objective (A) in scenarios (2), (3), (5).
Does not comply with objective (B) automatically. It must be programmed manually.
Solution Attempt: HTTP Errors with Replace
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problems with this solution:
Only works on IIS 7+.
Does not comply with objective (B) automatically. It must be programmed manually.
It obscures application level http exceptions. E.g. can't use customErrors section, System.Web.Mvc.HandleErrorAttribute, etc. It can't only show generic error pages.
Solution Attempt customErrors and HTTP Errors
<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Errors/NotFound"/>
</customError>
</system.web>
and
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problems with this solution:
Only works on IIS 7+.
Does not comply with objective (B) automatically. It must be programmed manually.
Does not comply with objective (C) in scenarios (2), (3), (5).
People that have troubled with this before even tried to create their own libraries (see http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html). But the previous solution seems to cover all the scenarios without the complexity of using an external library.
Yet another solution.
Add ErrorControllers or static page to with 404 error information.
Modify your web.config (in case of controller).
<system.web>
<customErrors mode="On" >
<error statusCode="404" redirect="~/Errors/Error404" />
</customErrors>
</system.web>
Or in case of static page
<system.web>
<customErrors mode="On" >
<error statusCode="404" redirect="~/Static404.html" />
</customErrors>
</system.web>
This will handle both missed routes and missed actions.
The response from Marco is the BEST solution. I needed to control my error handling, and I mean really CONTROL it. Of course, I have extended the solution a little and created a full error management system that manages everything. I have also read about this solution in other blogs and it seems very acceptable by most of the advanced developers.
Here is the final code that I am using:
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "ErrorManager";
routeData.Values["action"] = "Fire404Error";
routeData.Values["exception"] = exception;
Response.StatusCode = 500;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (Response.StatusCode)
{
case 404:
routeData.Values["action"] = "Fire404Error";
break;
}
}
// Avoid IIS7 getting in the middle
Response.TrySkipIisCustomErrors = true;
IController errormanagerController = new ErrorManagerController();
HttpContextWrapper wrapper = new HttpContextWrapper(Context);
var rc = new RequestContext(wrapper, routeData);
errormanagerController.Execute(rc);
}
}
and inside my ErrorManagerController :
public void Fire404Error(HttpException exception)
{
//you can place any other error handling code here
throw new PageNotFoundException("page or resource");
}
Now, in my Action, I am throwing a Custom Exception that I have created. And my Controller is inheriting from a custom Controller Based class that I have created. The Custom Base Controller was created to override error handling. Here is my custom Base Controller class:
public class MyBasePageController : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
filterContext.GetType();
filterContext.ExceptionHandled = true;
this.View("ErrorManager", filterContext).ExecuteResult(this.ControllerContext);
base.OnException(filterContext);
}
}
The "ErrorManager" in the above code is just a view that is using a Model based on ExceptionContext
My solution works perfectly and I am able to handle ANY error on my website and display different messages based on ANY exception type.
Looks like this is the best way to catch everything.
How can I properly handle 404 in ASP.NET MVC?
In IIS, you can specify a redirect to "certain" page based on error code. In you example, you can configure 404 - > Your customized 404 error page.
What I can recomend is to look on FilterAttribute. For example MVC already has HandleErrorAttribute. You can customize it to handle only 404. Reply if you are interesed I will look example.
BTW
Solution(with last route) that you have accepted in previous question does not work in much of the situations. Second solution with HandleUnknownAction will work but require to make this change in each controller or to have single base controller.
My choice is a solution with HandleUnknownAction.

Resources