2009-07-19 2 views
61

Может ли использоваться трафик ASP.Net (а не MVC) для обслуживания статических файлов?Использование ASP.NET-маршрутизации для обслуживания статических файлов

Скажем, я хочу, чтобы маршрут

http://domain.tld/static/picture.jpg 

в

http://domain.tld/a/b/c/picture.jpg 

, и я хочу сделать это динамически в том смысле, что переписаны URL вычисляется на лету. Я не могу настроить статический маршрут раз и навсегда.

Во всяком случае, я могу создать маршрут, как это:

routes.Add(
    "StaticRoute", new Route("static/{file}", new FileRouteHandler()) 
); 

В методе FileRouteHandler.ProcessRequest я могу переписать путь от /static/picture.jpg к /a/b/c/picture.jpg. Затем я хочу создать обработчик для статических файлов. Для этой цели ASP.NET использует StaticFileHandler. К сожалению, этот класс является внутренним. Я попытался создать обработчик с помощью отражения и он действительно работает:

Assembly assembly = Assembly.GetAssembly(typeof(IHttpHandler)); 
Type staticFileHandlerType = assembly.GetType("System.Web.StaticFileHandler"); 
ConstructorInfo constructorInfo = staticFileHandlerType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null); 
return (IHttpHandler) constructorInfo.Invoke(null); 

Но использование внутренних типов, кажется, не будет правильным решением. Другим вариантом является реализация моего собственного StaticFileHandler, но выполнение этого правильно (поддержка HTTP-материалов, таких как диапазоны и etags) является нетривиальным.

Как я должен подходить к маршрутизации статических файлов в ASP.NET?

ответ

37

После прохождения этой проблемы в течение нескольких часов я обнаружил, что просто добавление правил игнорирования приведет к тому, что ваши статические файлы будут обслуживаться.

В RegisterRoutes (RouteCollection маршруты), добавьте следующие игнорировать правила:

routes.IgnoreRoute("{file}.js"); 
routes.IgnoreRoute("{file}.html"); 
+0

Для меня это работает, но я не могу разобрать JS-файл в View Folder of Area, Чтобы исправить это, я использую вместо него другую папку в базовой папке области, например /Areas/MyArea/ClientScripts/foo.js – eka808

+20

Как-то я, кажется, пропустил кусок в головоломке ... как игнорирование маршрутов к вашим статическим файлам помогает с маршрутизацией из '/ static' в'/a/b/c' (что запросил OP)? Не могли бы вы пролить немного света на свой ответ, я бы очень хотел понять это решение. – Oliver

+17

Согласитесь с Оливером, что это НЕ отвечает OP и не должно приниматься в качестве решения. – dhochee

48

Почему бы не использовать IIS для этого? Вы можете просто создать правило перенаправления, чтобы указать любые запросы с первого маршрута на второй, прежде чем запрос даже попадет в ваше приложение. Из-за этого это был бы более быстрый способ перенаправления запросов.

Предполагая, что вы есть IIS7 +, вы делаете что-то вроде ...

<rule name="Redirect Static Images" stopProcessing="true"> 
    <match url="^static/?(.*)$" /> 
    <action type="Redirect" url="https://stackoverflow.com/a/b/c/{R:1}" redirectType="Permanent" /> 
</rule> 

Или, если вам не нужно перенаправлять, как это было предложено @ ni5ni6:

<rule name="Rewrite Static Images" stopProcessing="true"> 
    <match url="^static/?(.*)$" /> 
    <action type="Rewrite" url="https://stackoverflow.com/a/b/c/{R:1}" /> 
</rule> 

Редактировать 2015-06-17 для @RyanDawkins:

И если вам интересно, где находится правило перезаписи, карту его местоположения в файле web.config.

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.webServer> 
    <rewrite> 
     <rules> 
     <!-- rules go below --> 
     <rule name="Redirect Static Images" stopProcessing="true"> 
      <match url="^static/?(.*)$" /> 
      <action type="Redirect" url="https://stackoverflow.com/a/b/c/{R:1}" redirectType="Permanent" /> 
     </rule> 
     </rules> 
    </rewrite> 
    </system.webServer> 
</configuration> 
+0

Я предпочел бы этот подход, а также. Перемещая его в конвейер, и пусть рабочий процесс IIS обрабатывает перенаправление, более эффективен, чем циклы вращения, фактически обрабатывающие маршрут через среду выполнения, я бы предположил. Даже если количество оттока на сервере примерно одинаково, я бы отправил маршрут (каламбур) не используя маршруты и сохранил перенаправление вне самого приложения. –

+0

Непонятная из моей первоначальной версии вопроса заключалась в том, что переписанный URL-адрес вычисляется «на лету» (я не беспокоюсь о производительности здесь). Я уточнил вопрос, чтобы уточнить это. В любом случае, спасибо за ответ. –

+0

(удалил мой предыдущий комментарий и повторно добавил его с не укороченным URL-адресом). Мартин, Проблемы с производительностью в стороне, почему вы хотите обрабатывать этот URL-адрес в приложении, когда обработка его снаружи будет лучше? Я предполагаю, что вы можете создать действие контроллера, которое обрабатывает это, но вот что-то, на что вы могли бы взглянуть: - http://geekswithblogs.net/sankarsan/archive/2009/01/18/developing-custom-routehandler.aspx –

5

Я придумал альтернативу использованию внутреннего StaticFileHandler. В IRouteHandler я называю HttpServerUtility.Transfer:

public class FileRouteHandler : IRouteHandler { 

    public IHttpHandler GetHttpHandler(RequestContext requestContext) { 
    String fileName = (String) requestContext.RouteData.Values["file"]; 
    // Contrived example of mapping. 
    String routedPath = String.Format("https://stackoverflow.com/a/b/c/{0}", fileName); 
    HttpContext.Current.Server.Transfer(routedPath); 
    return null; // Never reached. 
    } 

} 

Это хак. Предполагается, что IRouteHandler должен вернуть IHttpHandler и не прерывать и передавать текущий запрос. Тем не менее, он действительно достигает того, чего я хочу.

Использование внутреннего StaticFileHandler также является чем-то вроде взлома, так как мне нужно отражение, чтобы получить к нему доступ, но по крайней мере есть documentation on StaticFileHandler on MSDN, что делает его немного более «официальным» классом. К сожалению, я не думаю, что можно подумать о внутренних классах в частичной среде доверия.

Я буду придерживаться использования StaticFileHandler, так как я не думаю, что он удалит его из ASP.NET в обозримом будущем.

9

У меня была аналогичная проблема. Я закончил с использованием HttpContext.RewritePath:

public class MyApplication : HttpApplication 
{ 
    private readonly Regex r = new Regex("^/static/(.*)$", RegexOptions.IgnoreCase); 

    public override void Init() 
    { 
     BeginRequest += OnBeginRequest; 
    } 

    protected void OnBeginRequest(object sender, EventArgs e) 
    { 
     var match = r.Match(Request.Url.AbsolutePath); 
     if (match.Success) 
     { 
      var fileName = match.Groups[1].Value; 
      Context.RewritePath(string.Format("https://stackoverflow.com/a/b/c/{0}", fileName)); 
     } 
    } 
} 
+1

Большое спасибо за это. Пробег через это, ища решение для URL Rewrite во время локальной разработки, и понял, что я могу сделать это везде. Я использую его не для синтаксического анализа ввода, а для управления версиями файлов JS и CSS. –

+0

Для всех, кого интересует, для управления файлами формы 'filename.v1234.js', я использую' private readonly Regex regJS = new Regex ("^ (. *) ([.] V [0-9] +) ([.] (js | css)) $ ", RegexOptions.IgnoreCase);' и затем по совпадениям я делаю 'Context.RewritePath (string.Format (" {0} {1} ", matchJS.Groups [1 ] .Value, matchJS.Groups [3] .Value)); ' –

3

Вам нужно добавить TransferRequestHandler для обработки статичного files.Please см следующего ответа https://stackoverflow.com/a/21724783/22858

+0

Для справки это работает и для приложений, отличных от MVC. – Ian

Смежные вопросы