2011-06-14 8 views
9

Chcę móc zreorganizować moją strukturę witryny ASP.NET MVC, aby lepiej pasowała do sposobu, w jaki Railsy to robią (robimy obie szyny i ASP.net w mojej firmie).Jak zmodyfikować korzeń pliku statycznego ASP.NET MVC

W Railsach istnieje folder "publiczny", który zachowuje się jako katalog główny witryny. Mogę na przykład wstawić plik "test.html" i uzyskać dostęp do pliku z adresem URL http://domain.com/test.html, który posłuży do statycznego pliku html.

W asp.net MVC istnieje folder "Content", który chcę zachować jako root. Dlatego zamiast dostępu do http://domain.com/content/myfile.html, chcę móc wykonać http://domain.com/myfile.html.

Wiem, że mogę po prostu upuścić plik w katalogu głównym projektu, ale muszę to zrobić z wieloma plikami, w tym css, js, html, obrazkami, itp. I chcę udostępniać niektóre standardowe zasoby za pośrednictwem szyn i aspnetmvc.

Czy istnieje sposób, aby to zrobić?

Odpowiedz

8

Istnieje inne możliwe rozwiązanie. Zamiast używać kodu, możesz użyć reguły przepisywania, aby zająć się tym za Ciebie. Jeśli korzystasz z IIS 7 lub nowszego, możesz użyć modułu URL Rewrite URL.

Reguła jak poniżej pewnie zrobić:

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

Kontrole regułę dotyczącą wniosku do CSS lub JS spiłować korzeń serwisu. Następnie sprawdza, czy plik istnieje w folderze treści. Jeśli istnieje, to przepisanie spowoduje zwrócenie pliku w folderze treści. Testowałem to tylko trochę, ale wygląda na to, że działa. To z pewnością wymaga więcej testów i możliwego udoskonalenia.

+0

To dobry pomysł. Bardzo mądre myślenie. – NerdFury

+0

Wydaje się, że jest to najskuteczniejszy sposób na wykonanie tego zadania, zarówno pod względem wysiłku, jak i wydajności. Spróbuję tego. Dzięki! – AlbertVo

2

Jedyne rozwiązanie, jakie mogę wymyślić, to użycie niestandardowego kontrolera i trasy, aby zrobić to za Ciebie. Ale to nie jest czyste rozwiązanie.

Najpierw potrzebna jest klasa PublicController z metodą akcji GetFile. Zakłada to, że wszystkie pliki znajdują się bezpośrednio w folderze public/content. Obsługa folderów sprawia, że ​​rzeczy są bardziej skomplikowane.

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

Teraz wystarczy trasy u dołu listy tras, które wygląda następująco:

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

Problem polega na tym, teraz, kiedy po prostu umieścić w nazwie kontrolera jak „Home zamiast domyślnej metody akcji Index na kontrolerze HomeController zakłada się, że chcesz pobrać plik o nazwie "Home" z katalogu zawartości. Tak więc, powyżej trasy pliku, musisz dodać trasę dla każdego kontrolera, aby wiedział, jak uzyskać działanie Index.

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

Więc jeden sposób wokół to zmienić trasę tak:

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

i sposobu działania w tym:

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

Tak jak mówiłem, to zakłada się, że wszystkie pliki znajdują się w katalogu zawartości, a nie w podfolderach. Ale jeśli chcesz zrobić podfoldery jak Treści/css/site.css można dodać swoje trasy tak:

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

Teraz metoda działania musi się zmienić też.

Jeśli zaczniesz umieszczać wiele poziomów w strukturze folderów, stanie się to coraz brzydsze i brzydsze. Ale może to zadziała dla ciebie. Jestem pewien, że liczyłeś na pole wyboru we właściwościach projektu, ale jeśli istnieje, nie wiem o tym.

+0

Dzięki za poświęcenie czasu na wyjaśnienie tego wszystkiego. Tak, to trochę bardziej zaangażowane, niż miałem nadzieję. Miałem nadzieję, że istnieje sposób, aby zastąpić zachowanie podobne do sposobu, w jaki można utworzyć własny viewEngine, aby zastąpić ViewPathLocations. – AlbertVo

+0

@AlbertVo - Tak, nic takiego, o ile wiem. Konwencja dotycząca konfiguracji czasami oznacza, że ​​rzeczy nie działają tak, jak chcesz. Ale na pewno jest możliwe, że też czegoś nie wiem. – NerdFury

+0

To będzie pewnie działać, ale nie podoba mi się ten pomysł, ponieważ zmusza każde żądanie statycznych plików do przejścia przez cały rurociąg. IIS7 będzie obsługiwał pliki statyczne ** znacznie ** szybciej bezpośrednio. Reguła przepisywania adresu URL powinna zapewniać lepszą wydajność. –