Verwenden des ASP.NET-Routings zum Bereitstellen statischer Dateien


73

Kann ASP.Net-Routing (nicht MVC) zum Bereitstellen statischer Dateien verwendet werden?

Angenommen, ich möchte routen

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

zu

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

und ich möchte es dynamisch in dem Sinne tun, dass die neu geschriebene URL im laufenden Betrieb berechnet wird. Ich kann keine statische Route ein für alle Mal einrichten.

Wie auch immer, ich kann eine Route wie diese erstellen:

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

In der FileRouteHandler.ProcessRequestMethode kann ich den Pfad von /static/picture.jpgnach umschreiben /a/b/c/picture.jpg. Ich möchte dann einen Handler für statische Dateien erstellen. ASP.NET verwendet das StaticFileHandlerzu diesem Zweck. Leider ist diese Klasse intern. Ich habe versucht, den Handler mithilfe von Reflection zu erstellen, und es funktioniert tatsächlich:

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);

Die Verwendung interner Typen scheint jedoch nicht die richtige Lösung zu sein. Eine andere Möglichkeit besteht darin, meine eigenen zu implementieren StaticFileHandler, aber dies richtig zu tun (HTTP-Inhalte wie Bereiche und Etags zu unterstützen) ist nicht trivial.

Wie gehe ich beim Routing statischer Dateien in ASP.NET vor?

Antworten:


40

Nachdem ich dieses Problem einige Stunden lang durchgearbeitet hatte, stellte ich fest, dass durch einfaches Hinzufügen von Ignorierregeln Ihre statischen Dateien bereitgestellt werden.

Fügen Sie in RegisterRoutes (RouteCollection-Routen) die folgenden Ignorierregeln hinzu:

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

Für mich funktioniert es, aber ich kann eine JS-Datei nicht in einem Ansichtsordner eines Bereichs analysieren. Um dies zu beheben, verwende ich stattdessen einen anderen Ordner im Basisordner des Bereichs wie /Areas/MyArea/ClientScripts/foo.js
eka808

26
Irgendwie scheint mir ein Teil des Puzzles zu fehlen ... Wie hilft das Ignorieren von Routen zu Ihren statischen Dateien beim Weiterleiten von /staticnach /a/b/c(was das OP verlangt hat)? Könnten Sie bitte etwas mehr Licht auf Ihre Antwort werfen, ich würde diese Lösung wirklich gerne verstehen.
Oliver

20
Stimmen Sie mit Oliver überein, dass dies NICHT das OP beantwortet und nicht als Lösung akzeptiert werden sollte.
Dhochee

Was ist, wenn Ihr MVC-Controller zuerst prüfen muss, ob sich ein Benutzer angemeldet hat, bevor er dorthin weitergeleitet wird? Das Ignorieren einer Route ist nicht dasselbe wie das Umleiten zu einer statischen Ordnerstruktur.
Pilavdzice

einfachster Weg, um Ihre robots.txt hinzuzufügen
joverall22

57

Warum nicht IIS verwenden, um dies zu tun? Sie können einfach eine Umleitungsregel erstellen, um alle Anforderungen von der ersten auf die zweite Route zu verweisen, bevor die Anforderung überhaupt in Ihre Anwendung gelangt. Aus diesem Grund wäre dies eine schnellere Methode zum Umleiten von Anforderungen.

Angenommen, Sie haben IIS7 +, dann tun Sie so etwas wie ...

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

Oder , wenn Sie nicht umleiten müssen, wie von @ ni5ni6 vorgeschlagen:

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

Edit 2015-06-17 für @RyanDawkins :

Und wenn Sie sich fragen, wohin die Umschreiberegel führt, finden Sie hier eine Karte ihres Speicherorts in der web.configDatei.

<?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>

Ich würde diesen Ansatz auch bevorzugen. Ich würde davon ausgehen, dass es effizienter ist, es in die Pipeline zu verschieben und den IIS-Worker-Prozess die Umleitung abwickeln zu lassen, als Drehzyklen, die die Route tatsächlich über die Laufzeit verarbeiten. Selbst wenn die Anzahl der Abwanderungen auf dem Server ungefähr gleich ist, würde ich den Weg (Wortspiel beabsichtigt) gehen, die Routen nicht zu verwenden, und die Umleitung außerhalb der Anwendung selbst halten.
Joseph Ferris

Aus meiner ursprünglichen Version der Frage ging nicht hervor, dass die umgeschriebene URL im laufenden Betrieb berechnet wird (ich mache mir hier keine Sorgen um die Leistung). Ich habe die Frage aktualisiert, um dies zu klären. Trotzdem danke für die Antwort.
Martin Liversage

(löschte meinen vorherigen Kommentar und fügte ihn mit einer nicht verkürzten URL hinzu). Martin, abgesehen von Leistungsproblemen, warum sollten Sie diese URL in der Anwendung behandeln, wenn es besser wäre, sie außerhalb zu handhaben? Ich nehme an, Sie könnten eine Controller-Aktion erstellen, die dies handhabt, aber hier ist etwas, das Sie sich ansehen könnten: - geekswithblogs.net/sankarsan/archive/2009/01/18/…
Dan Atkinson

1
@ RyanDawkins In der web.config. Weitere Informationen zum genauen Standort finden Sie in meiner Bearbeitung.
Dan Atkinson

1
Tolle Antwort, hat beim ersten Mal funktioniert. Das kommt jetzt nicht oft vor!
Dahui

13

Ich hatte ein ähnliches Problem. Am Ende habe ich HttpContext.RewritePath verwendet :

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));
        }
    }
}

1
Vielen Dank für das Teilen. Ich bin während der lokalen Entwicklung auf die Suche nach einer Lösung für URL Rewrite gestoßen und habe festgestellt, dass ich dies stattdessen überall tun kann. Ich verwende es nicht für die Analyse von Eingaben, sondern für die Verwaltung von JS- und CSS-Dateiversionen.
Brendan Moore

Für alle Interessierten, um Dateien des Formulars zu verwalten filename.v1234.js, verwende ich private readonly Regex regJS = new Regex("^(.*)([.]v[0-9]+)([.](js|css))$", RegexOptions.IgnoreCase);und dann auf Übereinstimmungen, die ich macheContext.RewritePath(string.Format("{0}{1}", matchJS.Groups[1].Value, matchJS.Groups[3].Value));
Brendan Moore

7

Ich habe mir eine Alternative zur internen Verwendung ausgedacht StaticFileHandler. In der IRouteHandlerrufe ich an 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.
  }

}

Das ist ein Hack. Der IRouteHandlersoll eine zurückgeben IHttpHandlerund die aktuelle Anfrage nicht abbrechen und übertragen. Es erreicht jedoch tatsächlich das, was ich will.

Das interne zu verwenden StaticFileHandlerist auch ein Hack, da ich Reflexion brauche, um Zugriff darauf zu erhalten, aber zumindest gibt es einige Dokumentationen StaticFileHandlerzu MSDN , die es zu einer etwas "offizielleren" Klasse machen. Leider glaube ich nicht, dass es möglich ist, interne Klassen in einer partiellen Vertrauensumgebung zu reflektieren.

Ich werde mich an die Verwendung halten, StaticFileHandlerda ich nicht glaube, dass sie in absehbarer Zeit aus ASP.NET entfernt wird.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.