HttpHandler never getting called - asp.net-mvc

I have an MVC application that I'm trying to add the ManagedFusion.Web.Captcha.CaptchaImageHandler into so that I can write the following code :
<label for="captcha">Enter #Html.Raw(Business.Captcha.CaptchaImage(Html, 50, 180)) Below</label>
and have the image appear. The code for that class is just cut and paste from the examples online:
public static string CaptchaImage(this HtmlHelper helper, int height, int width) {
ManagedFusion.Web.Controls.CaptchaImage image = new ManagedFusion.Web.Controls.CaptchaImage {
Height = height,
Width = width,
};
HttpRuntime.Cache.Add(image.UniqueId, image,
null,
DateTime.Now.AddSeconds(ManagedFusion.Web.Controls.CaptchaImage.CacheTimeOut),
Cache.NoSlidingExpiration,
CacheItemPriority.NotRemovable,
null);
StringBuilder stringBuilder = new StringBuilder(256);
stringBuilder.Append("<input type=\"hidden\" name=\"captcha-guid\" value=\"");
stringBuilder.Append(image.UniqueId);
stringBuilder.Append("\" />");
stringBuilder.AppendLine();
stringBuilder.Append("<img src=\"");
stringBuilder.Append("/captcha.ashx?guid=" + image.UniqueId);
stringBuilder.Append("\" alt=\"CAPTCHA\" width=\"");
stringBuilder.Append(width);
stringBuilder.Append("\" height=\"");
stringBuilder.Append(height);
stringBuilder.Append("\" />");
return stringBuilder.ToString();
}
I've added the following to my web.config
<system.web>
<httpHandlers>
<add verb="GET" path="test.sample" type="ManagedFusion.Web.Handlers.CaptchaImageHandler, ManagedFusion.Web.Captcha" validate="false" />
</httpHandlers>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true" >
</modules>
<handlers>
<add name="CaptchaImageHandler" verb="GET" path="captcha.ashx" type="ManagedFusion.Web.Handlers.CaptchaImageHandler, ManagedFusion.Web.Captcha" />
</handlers>
All previous SO questions point to the system.web->httpHandlers getting picked up by Cassini and the system.webServer->handlers getting picked up by IIS 7. But whenever I navigate to the view that has the aforementioned code, I always get a 404 for the /captcha.ashx. There is no route ignore rule in the global.asax. What is going on here? It's like nothing I do will get the handler to fire either on my local machine or on a deployed IIS 7 instance.

In the Global.asax file, I needed to add the ignore route before the default route mapping, so the whole method looks like this:
public static void RegisterRoutes(RouteCollection routes) {
routes.Ignore("captcha.ashx");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}

Related

How to redirect all url which not related to controllers (Asp.Net MVC)

I want to always redirect to my home page if someone puts something like www.example/bla/qwerty.hm (it doesnt have controller and it doesnt exist) to www.example.com.
I want to redirect all urls, which have not controller, to my home page and not show error. For example: www.example.com/auto (auto is not controller) and it will be redirect to my home page. How do I do that?
I tried Route configuration
routes.MapRoute(
name: "MyRedirect"
, url: "{contextRedirect}/{*tasks}"
, defaults: new { controller = "Redirect", action = "TotalRedirect", contextRedirect = "" }
);
...
public ActionResult TotalRedirect(string contextRedirect)
{
return RedirectToAction("Index", "Home");
}
but this is called every time and it makes an infinity loop (it is called every time when redirectToAction is called)
The problem disappears if I write all RouteMaps for all existing controllers before this MapRoute, but I have lot of controllers, and I want avoid writing RouteMaps for all controllers.
Instead of MapRoute I tried Web.config and change errors
<customErrors mode="On">
<error redirect="/Error" statusCode="404" />
<error redirect="/Error" statusCode="500" />
</customErrors>
Error is controller which return RedirectToAction and I got same result as point 1 (infinity loop). But when I change /Error to /Home it is working (because Home return View), but on Url path is saved error text Home?aspxerrorpath=/auto. After redirect I do not want show text, that means if page will be redirected in to www.example.com, it not show www.example/Home?aspxerrorpath=/auto.
I am new to Asp.net MVC, and I don't know proper way how to do it.
Update
After some research I think there are two ways how to do it.
(Thanks to KevinLamb) Redirect from error with Application_Error and Web.Confing httpError. This is working for me:
This settings is put in Web.Confing on Project level, that means first Web.Config you see in Project Explorer (there is second Web.Config on View folder). Then you must create Controller named Error with ActionResult ErrorHandle
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404"/>
<error statusCode="404" responseMode="ExecuteURL" path="/Error/ErrorHandle"/>
<remove statusCode="400"/>
<error statusCode="400" responseMode="ExecuteURL" path="/Error/ErrorHandle"/>
<remove statusCode="500"/>
<error statusCode="500" responseMode="ExecuteURL" path="/Error/ErrorHandle"/>
</httpErrors>
...
// Error Controller .cs
namespace MyWebApp.Controllers
{
public class ErrorController : Controller
{
// GET: Error
public ActionResult Index()
{
return RedirectToAction("Home", "Index");
}
public ActionResult ErrorHandle()
{
return RedirectToAction("Index", "Home");
}
}
}
...
// code inside Global.asax.cs MvcApplication class
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
//Add some logging here
if(ex.GetType().IsAssignableFrom(typeof(HttpException)))
{
//Possibly log that you're redirecting the user
Response.Clear();
Response.Redirect("~/");
}
}
This is easy part.
Another way I discover is create HttpHandler or HttpModule. I am new in MVC and Asp.Net world and HttpHandler is not working allways for me, because it works only once, then only when application change page, but it not detect Url created by user (only first time). HttpModule work allways for me, but I don't know if it is good or bad. It is little harder then 1. point but you don't need Application_Error and httpErrors in Web.Config.
If you have httpErrors and Application_Error, delete it and create Module (Right click on Project > Add new Item > In search put "module" > and select Asp.Net Module. It create module class with Init and Dispose methods. Then create your own method and register it to BeginRequest.
And here is code for my HttpModule
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Reflection;
using System.Linq;
namespace MyWebApp
{
public class ErrorHttpModule : IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
//clean-up code here.
}
public void Init(HttpApplication context)
{
// Below is an example of how you can handle LogRequest event and provide
// custom logging implementation for it
// context.LogRequest += new EventHandler(OnLogRequest);
context.BeginRequest += new EventHandler(BR); // register your own method in to Event where you check Url
}
#endregion
private HttpContext context = null;
public void BR(Object source, EventArgs e)
{
context = System.Web.HttpContext.Current;
// collect all controllers in web application
Assembly asm = Assembly.GetAssembly(typeof(MyWebApp.MvcApplication)); // need using System.Reflection;
var controlleractionlist = asm.GetTypes()
.Where(type => typeof(System.Web.Mvc.Controller).IsAssignableFrom(type)) // need using System.Linq;
.SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
.Where(m => !m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), true).Any())
.Select(x => new { Controller = x.DeclaringType.Name, Action = x.Name, ReturnType = x.ReturnType.Name, Attributes = String.Join(",", x.GetCustomAttributes().Select(a => a.GetType().Name.Replace("Attribute", ""))) })
.OrderBy(x => x.Controller).ThenBy(x => x.Action).ToList();
// Get Url
string page = "";
if (context != null)
{
page = context.Request.Url.PathAndQuery;
}
string newUrl;
if (!String.IsNullOrEmpty(page))
{
bool continute = true;
// does url contain controller or action?
foreach (var controller in controlleractionlist)
{
string cpath = "/" + controller.Controller.Replace("Controller", "") + (controller.Action == "Index" ? "" : "/" + controller.Action);
if (cpath == page)
{
// Yes, don't continue to redirect
continute = false;
break;
}
else if (page == ("/" + controller.Action))
{
// Yes, don't continue to redirect
continute = false;
break;
}
}
// does page load your content, script etc.. ?
if (page.Contains("Content/") == true
|| page.Contains("Scripts/") == true
|| page.Contains(".ico") == true
|| page == "/"
)
{
// Yes, don't redirect.
continute = false;
}
if (continute)
{
// anything else will redirect to Home page
var urlHelper = new UrlHelper(context.Request.RequestContext); // nned using System.Web.Mvc;
newUrl = urlHelper.Action("About", "Home");
context.Response.Status = "301 Moved Permanently";
context.Response.AddHeader("Location", newUrl);
context.Response.End();
}
}
}
public void OnLogRequest(Object source, EventArgs e)
{
//custom logging logic can go here
}
}
}
And finnaly add module in to Web.Config (on Project level (ProjectName > Web.Config), not inside folder under Project (ProjectName > View > Web.Config))
<system.webServer>
<modules>
<add name="MyHttpErrorModule" type="MyWebApp.ErrorHttpModule, MyWebApp"/>
</modules>
</system.webServer>
Extended question
Either first or second point, I have problem with both, when in url is put characters like that /abc=45%$#r. It leads to Bad Request - Invalid URL HTTP Error 400. The request URL is invalid. and this don't detect Application_Error, httpErrors in Web.Config or my HttpModule with BeginRequest. Therefore I think this is on IIS settings but what I need to set up? It looks like those characters make IIS mess %$.
First you'll need to set errors to pass through in IIS so that your application can handle the file/parameter links instead of IIS. Add the below to your Web.config:
<system.webServer>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
If you want to redirect to your home page (without any extra parameters in the URL) when you get an issue with a user going to the wrong controller/action, add the following code to your Global.asax.cs.
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
//Add some logging here
if(ex.GetType().IsAssignableFrom(typeof(HttpException)))
{
//Possibly log that you're redirecting the user
Response.Clear();
Response.Redirect("~/");
}
}
Basically, what this is is doing is making all errors in your ASP.NET MVC website go through this method. Then it checks to see if the exception is a HttpException. If it is, it will redirect to your home controller and action. If it is not a HttpException it will continue doing the error handling process. This way you can keep handling the important errors properly.

Error The path in 'value' must start with '/' in ASP.NET Core 2 in application deploy

I'm trying to deploy an asp net core 2 application, all seems to be ok, I'm using deploy Files option in VS2017, to my path inetpub\wwwroot\App1 folder, I add the application.
I browse to the path http://localhost:8088/App1/Home/Index/
then I see :
ArgumentException: The path in 'value' must start with '/'.
Nombre del parámetro: value
Microsoft.AspNetCore.Http.PathString..ctor(string value)
Microsoft.AspNetCore.Builder.ExceptionHandlerExtensions.UseExceptionHandler(IApplicationBuilder
app, string errorHandlingPath)
OCIndicadoresOperativoClientes.Startup.Configure(IApplicationBuilder
app, IHostingEnvironment env) in Startup.cs
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Hosting.ConventionBasedStartup.Configure(IApplicationBuilder
app)
Microsoft.AspNetCore.Server.IISIntegration.IISSetupFilter+<>c__DisplayClass3_0.b__0(IApplicationBuilder
app)
Microsoft.AspNetCore.Hosting.Internal.AutoRequestServicesStartupFilter+<>c__DisplayClass0_0.b__0(IApplicationBuilder
builder)
Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
below you can see the code of Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SpaServices.Webpack;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace App1
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDistributedMemoryCache();
services.AddMvc().AddSessionStateTempDataProvider();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(25);
options.Cookie.HttpOnly = true;
});
services.AddAuthenticationCore();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseExceptionHandler("App1/Home/Error");
app.UseStaticFiles();
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "Home",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "Shippers",
template: "{controller=ControllerB}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
routes.MapSpaFallbackRoute(
name: "ControllerB",
defaults: new { controller = "ControllerB", action = "Index" });
});
}
}
}
also, I will include the webconfig details:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath=".\App1.exe" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
</system.webServer>
</configuration>
Do you see any error? i would appreciate your help!
Based from stack trace, the error occurred in this line:
app.UseExceptionHandler("App1/Home/Error");
Currently you're using this overload of UseExceptionHandler which expects URL path:
public static Microsoft.AspNetCore.Builder.IApplicationBuilder UseExceptionHandler (
this Microsoft.AspNetCore.Builder.IApplicationBuilder app,
string errorHandlingPath);
Note that errorHandlingPath parameter requires proper URL format because it will be used to call PathString constructor, hence you should add slash on the beginning of URL:
app.UseExceptionHandler("/App1/Home/Error");
Similar issue: Startup.cs - The path in 'value' must start with '/'
I also had this issue. It was coming because the exception handling path is expected to start with a "/"
The error was:
ArgumentException: The path in 'value' must start with '/'. Nombre del parámetro: value Microsoft.AspNetCore.Http.PathString..ctor(string value) Microsoft.AspNetCore.Builder.ExceptionHandlerExtensions.UseExceptionHandler(IApplicationBuilder app, string errorHandlingPath)
Fixed by replacing
app.UseExceptionHandler("Home/Error");
with
app.UseExceptionHandler("/Home/Error");
Also you can try deploying with
app.UseDeveloperExceptionPage();
and find the error if any.

How to configure HTML Minification in ASP.NET MVC

I would like to configure HTML minification to my ASP>NET MVC5 web application.
I installed Nuget
Install-Package WebMarkupMin.Mvc
Then I add Filter Attributte:
[MinifyHtmlAttribute]
public ActionResult Index()
{
return View();
}
But the HTML minification does not work.
Nuget Installation add few lines to the web.config:
<sectionGroup name="webMarkupMin">
<section name="core" type="WebMarkupMin.Core.Configuration.CoreConfiguration, WebMarkupMin.Core" />
<section name="webExtensions" type="WebMarkupMin.Web.Configuration.WebExtensionsConfiguration, WebMarkupMin.Web" />
</sectionGroup>
<webMarkupMin xmlns="http://tempuri.org/WebMarkupMin.Configuration.xsd">
<core>
<css>
<minifiers>
<add name="NullCssMinifier" displayName="Null CSS Minifier" type="WebMarkupMin.Core.Minifiers.NullCssMinifier, WebMarkupMin.Core" />
<add name="KristensenCssMinifier" displayName="Mads Kristensen's CSS minifier" type="WebMarkupMin.Core.Minifiers.KristensenCssMinifier, WebMarkupMin.Core" />
</minifiers>
</css>
<js>
<minifiers>
<add name="NullJsMinifier" displayName="Null JS Minifier" type="WebMarkupMin.Core.Minifiers.NullJsMinifier, WebMarkupMin.Core" />
<add name="CrockfordJsMinifier" displayName="Douglas Crockford's JS Minifier" type="WebMarkupMin.Core.Minifiers.CrockfordJsMinifier, WebMarkupMin.Core" />
</minifiers>
</js>
<html whitespaceMinificationMode="Medium" removeHtmlComments="true"
removeHtmlCommentsFromScriptsAndStyles="true"
removeCdataSectionsFromScriptsAndStyles="true"
useShortDoctype="true" useMetaCharsetTag="true"
emptyTagRenderMode="NoSlash" removeOptionalEndTags="true"
removeTagsWithoutContent="false" collapseBooleanAttributes="true"
removeEmptyAttributes="true" attributeQuotesRemovalMode="Html5"
removeRedundantAttributes="true"
removeJsTypeAttributes="true" removeCssTypeAttributes="true"
removeHttpProtocolFromAttributes="false"
removeHttpsProtocolFromAttributes="false"
removeJsProtocolFromAttributes="true"
minifyEmbeddedCssCode="true" minifyInlineCssCode="true"
minifyEmbeddedJsCode="true" minifyInlineJsCode="true"
processableScriptTypeList="" minifyKnockoutBindingExpressions="false"
minifyAngularBindingExpressions="false" customAngularDirectiveList="" />
<logging>
<loggers>
<add name="NullLogger" displayName="Null Logger" type="WebMarkupMin.Core.Loggers.NullLogger, WebMarkupMin.Core" />
<add name="ThrowExceptionLogger" displayName="Throw exception logger" type="WebMarkupMin.Core.Loggers.ThrowExceptionLogger, WebMarkupMin.Core" />
</loggers>
</logging>
</core>
</webMarkupMin>
The html element was added by me manually according to documentation.
Am I missing something?
Web application may be in debug mode. In order to switch it to release mode you need to edit the Web.config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
...
<system.web>
<compilation debug="false" ... />
...
</system.web>
...
</configuration>
In addition, you can disable dependence on web application mode. Using the following settings:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
...
<webMarkupMin xmlns="http://tempuri.org/WebMarkupMin.Configuration.xsd">
<webExtensions disableMinificationInDebugMode="false"
disableCompressionInDebugMode="false" />
...
</webMarkupMin>
...
</configuration>
So large library with so difficult usage and configuration... Are you sure need all this for just the HTML minification?
Create a new filter under the Filters subfolder of your project and call it CompactHtmlFilterAttribute Use the following code:
public class CompactHtmlFilterAttribute : ActionFilterAttribute
{
public class WhitespaceFilter : MemoryStream
{
private string Source = string.Empty;
private Stream Filter = null;
public WhitespaceFilter(HttpResponseBase HttpResponseBase)
{
Filter = HttpResponseBase.Filter;
}
public override void Write(byte[] buffer, int offset, int count)
{
Source = UTF8Encoding.UTF8.GetString(buffer).Replace("\r", "").Replace("\n", "").Replace("\t", "");
Filter.Write(UTF8Encoding.UTF8.GetBytes(Source), offset, UTF8Encoding.UTF8.GetByteCount(Source));
}
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
#if DEBUG
base.OnActionExecuting(filterContext);
#else
try
{
filterContext.HttpContext.Response.Filter = new WhitespaceFilter(filterContext.HttpContext.Response);
}
catch (Exception) { }
#endif
}
}
Pay atention on the #if DEBUG dirrective. HTML will be minified only in release configuration, while on debug the original code will be kept for the better readability.
Add this attribute to the controller methods
[CompactHtmlFilter]
public ActionResult Index()
{
return View();
}
and we're done.
You need to add the following to enable the webextensions (from the doc):
<webMarkupMin xmlns="http://tempuri.org/WebMarkupMin.Configuration.xsd">
…
<webExtensions enableMinification="true" disableMinificationInDebugMode="true"
enableCompression="true" disableCompressionInDebugMode="true"
maxResponseSize="100000" disableCopyrightHttpHeaders="false" />
…
</webMarkupMin>
Note that it's outside the <core> element.
also in your view markup you should have the attribute as:
[MinifyHtml]
Itshouldn't have the ..Attribute at the end of it.

ASP.NET MVC 5 - (HTTP Error 404.0 - Not Found) with long non-existing URL

I created a new project in Microsoft Visual Studio Express 2013 for Web.
It is an ASP.NET MVC 5 - .NET Framework 4.5 project.
I wanted to handle (The resource cannot be found):
I did handle it using the code below.
This code will work if I do something like (/Home/kddiede/ddiij) or (/djdied/djie/djs), this will result in showing my custom Error page.
However, when I try to do something like (/Home/kddiede/ddiij/dfd/sdfds/dsf/dsfds/fd), or any long non-existing URL, It will show me this:
Code from: http://www.codeproject.com/Articles/635324/Another-set-of-ASP-NET-MVC-4-tips
Tip 16: Customizing error screens
Error Page is in the /View/Shared/Error.cshtml
Web.config
<system.web>
<customErrors mode="RemoteOnly" />
</system.web>
Global.asax
protected void Application_EndRequest(Object sender, EventArgs e)
{
ErrorConfig.Handle(Context);
}
ErrorConfig Class
public class ErrorConfig
{
public static void Handle(HttpContext context)
{
switch (context.Response.StatusCode)
{
//Not authorized
case 401:
Show(context, 401);
break;
//Not found
case 404:
Show(context, 404);
break;
}
}
static void Show(HttpContext context, Int32 code)
{
context.Response.Clear();
var w = new HttpContextWrapper(context);
var c = new ErrorController() as IController;
var rd = new RouteData();
rd.Values["controller"] = "Error";
rd.Values["action"] = "Index";
rd.Values["id"] = code.ToString();
c.Execute(new RequestContext(w, rd));
}
}
ErrorController
internal class ErrorController : Controller
{
[HttpGet]
public ViewResult Index(Int32? id)
{
var statusCode = id.HasValue ? id.Value : 500;
var error = new HandleErrorInfo(new Exception("An exception with error " + statusCode + " occurred!"), "Error", "Index");
return View("Error", error);
}
}
This last bit of code from the website I mentioned above was not added in Global.asax because It is already in FilterConfig.cs
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
Anyone knows how to fix it?
Thanks in advance.
Solved. To point all non-existing urls to your error page, do the following:
Add the code below at the end of your RouteConfig.cs file:
public static void RegisterRoutes(RouteCollection routes)
{
// Default
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
// Add this code to handle non-existing urls
routes.MapRoute(
name: "404-PageNotFound",
// This will handle any non-existing urls
url: "{*url}",
// "Shared" is the name of your error controller, and "Error" is the action/page
// that handles all your custom errors
defaults: new { controller = "Shared", action = "Error" }
);
}
Add the code below to your Web.config file:
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"></modules>
</system.webServer>
<system.web>
<httpRuntime relaxedUrlToFileSystemMapping="true" />
</system.web>
</configuration>
That should point all the non-existing urls such as (/ad/asd/sa/das,d/asd,asd.asd+dpwd'=12=2e-21) to your error page.
Another approach would be to add this to your web.config inside of the system.web element
<system.web>
<!-- ... -->
<!--Handle application exceptions-->
<customErrors mode="On">
<!--Avoid YSOD on 404/403 errors like this because [HandleErrors] does not catch them-->
<error statusCode="404" redirect="Error/Index" />
<error statusCode="403" redirect="Error/Index" />
</customErrors>
</system.web>

Catch request to a file in content folder to handle with controller action

I got a third party widget library I have to use. This library has a hardcoded string to a file. Is it possible to intercept this request with routes? My try looked like this:
routes.MapRoute(name: "ribbonbar",
url: "Content/Ribbon/Scripts/Ribbon.Tabs.foo",
defaults: new { controller = "Ribbon", action = "Index" });
But I only got a 404. Is it impossible or do I have mixed something up?
Yes, this is possible. You will need to add the following handler to your web.config in order to ensure that this request goes through the managed pipeline and your routes:
<system.webServer>
<handlers>
...
<add
name="MyCustomhandler"
path="Content/Ribbon/Scripts/Ribbon.Tabs.foo"
verb="GET"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
and then you could have the following controller action to serve this request:
public class RibbonController
{
// GET Content/Ribbon/Scripts/Ribbon.Tabs.foo
public ActionResult Index()
{
var file = Server.MapPath("~/App_Data/foo.bar");
return File(file, "application/foo-bar");
}
}
You could also serve all requests to Content/Ribbon/Scripts/* from the same controller action:
<system.webServer>
<handlers>
...
<add
name="MyCustomhandler"
path="Content/Ribbon/Scripts/*"
verb="GET"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
and a route like that:
routes.MapRoute(
name: "ribbonbar",
url: "Content/Ribbon/Scripts/{name}",
defaults: new { controller = "Ribbon", action = "Index" }
);
with an action like that:
public class RibbonController
{
// GET Content/Ribbon/Scripts/*
public ActionResult Index(string name)
{
...
}
}
Alternatively to using a specific handler you could have enabled managed modules for all requests like that:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
...
</system.webServer>
But I wouldn't recommend you enabling this option because now all requests will go through the managed pipeline, even those from for static resources which might have a negative impact on the performance of your application. It's much better to selectively enable this only for selected urls.

Resources