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

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

Скажем, я хочу проложить маршрут

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

to

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?


person Martin Liversage    schedule 19.07.2009    source источник


Ответы (5)


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

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

routes.IgnoreRoute("{file}.js");
routes.IgnoreRoute("{file}.html");
person Robert Mao    schedule 24.06.2010
comment
Для меня это работает, но я не могу разобрать файл JS в папке просмотра области. Чтобы исправить это, я использую вместо этого другую папку в базовой папке области, например /Areas/MyArea/ClientScripts/foo.js - person eka808; 30.01.2012
comment
Почему-то мне кажется, что я упустил часть головоломки ... как игнорирование маршрутов к вашим статическим файлам помогает с маршрутизацией от /static к /a/b/c (о чем просил OP)? Не могли бы вы пролить свет на свой ответ, я бы очень хотел понять это решение. - person Oliver; 13.02.2013
comment
Согласитесь с Оливером, что это НЕ отвечает на OP и не должно приниматься как решение. - person dhochee; 13.03.2013
comment
Что делать, если вам нужно, чтобы ваш контроллер MVC сначала проверял, вошел ли пользователь в систему, прежде чем выполнять маршрутизацию туда? Игнорирование маршрута - это не то же самое, что перенаправление на статическую структуру папок. - person pilavdzice; 18.09.2014
comment
самый простой способ добавить свой robots.txt - person joverall22; 03.10.2015

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

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

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

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

<rule name="Rewrite Static Images" stopProcessing="true">
  <match url="^static/?(.*)$" />
  <action type="Rewrite" url="/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="/a/b/c/{R:1}" redirectType="Permanent" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>
person Dan Atkinson    schedule 26.07.2009
comment
Я бы тоже предпочел этот подход. Я полагаю, что перемещение его в конвейер и предоставление рабочему процессу IIS возможности обрабатывать перенаправление более эффективно, чем вращение циклов, фактически обрабатывающих маршрут через среду выполнения. Даже если количество оттока на сервере примерно такое же, я бы пошел по маршруту (каламбур) не использовать маршруты и сохранил перенаправление за пределами самого приложения. - person Joseph Ferris; 26.07.2009
comment
Что не было ясно из моей первоначальной версии вопроса, так это то, что перезаписанный URL-адрес вычисляется на лету (меня здесь не беспокоит производительность). Я обновил вопрос, чтобы прояснить это. В любом случае, спасибо за ответ. - person Martin Liversage; 27.07.2009
comment
(удалил мой предыдущий комментарий и повторно добавил его с неукороченным URL-адресом). Мартин, помимо проблем с производительностью, зачем вам обрабатывать этот URL-адрес в приложении, когда обработка его снаружи была бы лучше? Я предполагаю, что вы могли бы создать действие контроллера, которое обрабатывает это, но вот что вы можете посмотреть: - geekswithblogs.net/sankarsan/archive/2009/01/18/ - person Dan Atkinson; 20.07.2011
comment
Я только что изменил type = Redirect на Rewrite, и он отлично работает, если вам не нужно динамическое создание перезаписываемого URL - person ni5ni6; 21.06.2012
comment
@RyanDawkins В файле web.config. Пожалуйста, просмотрите мою правку для получения дополнительной информации о его точном местонахождении. - person Dan Atkinson; 17.06.2015
comment
Отличный ответ, сработало с первого раза. Теперь это случается нечасто! - person dahui; 10.01.2018
comment
Извините за оффтоп, а вот этот вопрос можно посмотреть? stackoverflow.com/questions/55488381/wwwroot-in-mvc5 - person Troll the Legacy; 03.04.2019

У меня была похожая проблема. В итоге я использовал 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("/a/b/c/{0}", fileName));
        }
    }
}
person sheikhomar    schedule 17.10.2010
comment
Большое спасибо за то, что поделились этим. Пробежался через это в поисках решения для перезаписи URL во время локальной разработки и понял, что вместо этого я могу делать это везде. Я использую его не для синтаксического анализа ввода, а для управления версиями файлов JS и CSS. - person Brendan Moore; 18.12.2013
comment
Для всех, кто интересуется, чтобы управлять файлами формы 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)); - person Brendan Moore; 18.12.2013

Я придумал альтернативу использованию внутреннего 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("/a/b/c/{0}", fileName);
    HttpContext.Current.Server.Transfer(routedPath);
    return null; // Never reached.
  }

}

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

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

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

person Martin Liversage    schedule 24.08.2009

Вам необходимо добавить TransferRequestHandler для обработки ваших статических файлов. См. Следующий ответ https://stackoverflow.com/a/21724783/22858

person Prerak K    schedule 12.02.2014