11 Stimmen

Ändern der statischen ASP.NET MVC-Datei Root

Ich möchte in der Lage sein, meine ASP.NET MVC-Site-Struktur zu reorganisieren, um näher an die Art und Weise Rails tut es (Wir tun beide Rails und ASP.net in meinem Unternehmen).

In Rails gibt es einen "public"-Ordner, der sich wie die Wurzel der Website verhält. Zum Beispiel könnte ich eine "test.html" einfügen und auf die Datei mit der Url http://domain.com/test.html die die statische Html-Datei bereitstellen würde.

In asp.net MVC gibt es einen "Content"-Ordner, den ich als Root verhalten möchte. Anstatt also auf den http://domain.com/content/myfile.html Ich möchte in der Lage sein zu tun http://domain.com/myfile.html .

Ich weiß, ich kann einfach die Datei in der Wurzel des Projekts fallen, aber ich muss dies mit vielen Dateien einschließlich css, js, html, Bilder, etc. tun und möchten einige standardisierte Vermögenswerte über Schienen und aspnetmvc teilen.

Gibt es eine Möglichkeit, dies zu tun?

9voto

Nathan Fox Punkte 3973

Es gibt eine weitere mögliche Lösung. Anstatt Code zu verwenden, können Sie eine Rewrite-Regel verwenden, um dies für Sie zu erledigen. Wenn Sie IIS 7 oder höher verwenden, können Sie das URL-Rewrite-Modul von Microsoft einsetzen.

Eine Regel wie die folgende würde wahrscheinlich genügen:

<rule name="Rewrite static files to content" stopProcessing="true">
  <match url="^([^/]+(?:\.css|\.js))$" />
  <conditions>
      <add input="{APPL_PHYSICAL_PATH}content{SCRIPT_NAME}" matchType="IsFile" />
  </conditions>
  <action type="Rewrite" url="/content/{R:1}" />
</rule>

Die Regel prüft, ob eine Anfrage an eine css- oder js-Datei außerhalb des Stammverzeichnisses der Website erfolgt. Dann wird geprüft, ob die Datei im Inhaltsordner existiert. Wenn sie vorhanden ist, wird die Datei im Inhaltsordner wiederhergestellt. Ich habe dies nur ein wenig getestet, aber es scheint zu funktionieren. Es muss auf jeden Fall noch weiter getestet und möglicherweise verfeinert werden.

3voto

NerdFury Punkte 18121

Die einzige Lösung, die mir einfällt, ist die Verwendung eines benutzerdefinierten Controllers und einer Route, die dies für Sie erledigen. Aber es ist nicht eine saubere Lösung.

Zunächst benötigen Sie eine PublicController-Klasse mit einer GetFile-Aktionsmethode. Dabei wird davon ausgegangen, dass sich alle Dateien direkt im Ordner public/content befinden. Die Handhabung von Ordnern macht die Sache komplizierter.

public class PublicController : Controller
{
    private IDictionary<String, String> mimeTypes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
                                                        {{"css", "text/css"}, {"jpg", "image/jpg"}};

    public ActionResult GetFile(string file)
    {
        var path = Path.Combine(Server.MapPath("~/Content"), file);

        if (!System.IO.File.Exists(path)) throw new HttpException(404, "File Not Found");
        var extension = GetExtension(file); // psuedocode
        var mimetype = mimeTypes.ContainsKey(extension) ? mimeTypes[extension] : "text/plain";
        return File(path, mimetype);
    }
}

Jetzt brauchen Sie nur noch eine Route, die am Ende Ihrer Routenliste steht und wie folgt aussieht:

routes.MapRoute("PublicContent", "{file}", new {controller = "Public", action = "GetFile"});

Das Problem ist jetzt, wenn Sie nur in einem Controller-Namen wie "Home" statt standardmäßig auf die Index-Action-Methode auf der HomeController, es nimmt an, Sie wollen eine Datei namens "Home" aus dem Content-Verzeichnis herunterladen. Also, über die Datei-Route, müssten Sie eine Route für jeden Controller hinzufügen, so dass es weiß, um die Index-Aktion stattdessen zu erhalten.

routes.MapRoute("HomeIndex", "Home", new { controller = "Home", action = "Index" });

Eine Möglichkeit, dies zu umgehen, besteht darin, die Route folgendermaßen zu ändern:

routes.MapRoute("PublicContent", "{file}.{extension}", new {controller = "Public", action = "GetFile"});

Und die Aktionsmethode dazu:

    public ActionResult GetFile(string file, string extension)
    {
        var path = Path.Combine(Server.MapPath("~/Content"), file + "." + extension);

        if (!System.IO.File.Exists(path)) throw new HttpException(404, "File Not Found");

        var mimetype = mimeTypes.ContainsKey(extension) ? mimeTypes[extension] : "text/plain";
        return File(path, mimetype);
    }

Wie ich schon sagte, setzt dies voraus, dass sich alle Dateien im Inhaltsverzeichnis und nicht in Unterordnern befinden. Wenn Sie jedoch Unterordner wie Content/css/site.css verwenden möchten, können Sie Ihre Routen wie folgt hinzufügen:

        routes.MapRoute("PublicContent_sub", "{subfolder}/{file}.{extension}", new { controller = "Public", action = "GetFileInFolder" });
        routes.MapRoute("PublicContent", "{file}.{extension}", new { controller = "Public", action = "GetFile"});

Nun muss auch die Aktionsmethode geändert werden.

    public ActionResult GetFile(string file, string extension)
    {
        return GetFileInFolder("", file, extension);
    }

    public ActionResult GetFileInFolder(string subfolder, string file, string extension)
    {
        var path = Path.Combine(Server.MapPath("~/Content"), subfolder, file + "." + extension);

        if (!System.IO.File.Exists(path)) throw new HttpException(404, "File Not Found");

        var mimetype = mimeTypes.ContainsKey(extension) ? mimeTypes[extension] : "text/plain";
        return File(path, mimetype);
    }

Wenn Sie mehrere Ebenen in der Ordnerstruktur erreichen, wird dies immer unschöner. Aber vielleicht klappt es bei Ihnen ja so. Ich bin sicher, dass Sie auf ein Kontrollkästchen in den Projekteigenschaften gehofft haben, aber wenn es eines gibt, weiß ich es nicht.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X