Jakie jest najlepsze miejsce (w którym folderze itp.) Do umieszczania plików javascript specyficznych dla widoku w aplikacji ASP.NET MVC?
Aby mój projekt był zorganizowany, naprawdę chciałbym móc umieścić je obok plików .aspx widoku, ale nie znalazłem dobrego sposobu na odwołanie się do nich, robiąc to bez ujawniania ~ / Views / Działanie / struktura folderów. Czy naprawdę źle jest pozwolić, aby szczegóły tej struktury folderów wyciekły?
Alternatywą jest umieszczenie ich w folderach ~ / Scripts lub ~ / Content, ale jest to niewielka irytacja, ponieważ teraz muszę się martwić o konflikty nazw plików. Jest to jednak irytacja, z którą mogę sobie poradzić, jeśli to „właściwa rzecz”.
asp.net-mvc
Erv Walter
źródło
źródło
Odpowiedzi:
Stare pytanie, ale chciałem odpowiedzieć na to pytanie, na wypadek gdyby ktoś przyszedł go szukać.
Też chciałem, aby moje pliki js / css specyficzne dla widoku w folderze views, a oto jak to zrobiłem:
W folderze web.config w katalogu głównym / Views musisz zmodyfikować dwie sekcje, aby umożliwić serwerowi WWW obsługę plików:
<system.web> <httpHandlers> <add path="*.js" verb="GET,HEAD" type="System.Web.StaticFileHandler" /> <add path="*.css" verb="GET,HEAD" type="System.Web.StaticFileHandler" /> <add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/> </httpHandlers> <!-- other content here --> </system.web> <system.webServer> <handlers> <remove name="BlockViewHandler"/> <add name="JavaScript" path="*.js" verb="GET,HEAD" type="System.Web.StaticFileHandler" /> <add name="CSS" path="*.css" verb="GET,HEAD" type="System.Web.StaticFileHandler" /> <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" /> </handlers> <!-- other content here --> </system.webServer>
Następnie z pliku widoku możesz odwoływać się do adresów URL zgodnie z oczekiwaniami:
@Url.Content("~/Views/<ControllerName>/somefile.css")
Umożliwi to udostępnianie plików .js i .css oraz zabroni udostępniania czegokolwiek innego.
źródło
Jednym ze sposobów osiągnięcia tego jest dostarczenie własnego
ActionInvoker
. Korzystając z poniższego kodu, możesz dodać do konstruktora kontrolera:ActionInvoker = new JavaScriptActionInvoker();
Teraz za każdym razem, gdy umieścisz
.js
plik obok widoku:Możesz uzyskać do niego bezpośredni dostęp:
http://yourdomain.com/YourController/Index.js
Poniżej źródło:
namespace JavaScriptViews { public class JavaScriptActionDescriptor : ActionDescriptor { private string actionName; private ControllerDescriptor controllerDescriptor; public JavaScriptActionDescriptor(string actionName, ControllerDescriptor controllerDescriptor) { this.actionName = actionName; this.controllerDescriptor = controllerDescriptor; } public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters) { return new ViewResult(); } public override ParameterDescriptor[] GetParameters() { return new ParameterDescriptor[0]; } public override string ActionName { get { return actionName; } } public override ControllerDescriptor ControllerDescriptor { get { return controllerDescriptor; } } } public class JavaScriptActionInvoker : ControllerActionInvoker { protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName) { var action = base.FindAction(controllerContext, controllerDescriptor, actionName); if (action != null) { return action; } if (actionName.EndsWith(".js")) { return new JavaScriptActionDescriptor(actionName, controllerDescriptor); } else return null; } } public class JavaScriptView : IView { private string fileName; public JavaScriptView(string fileName) { this.fileName = fileName; } public void Render(ViewContext viewContext, TextWriter writer) { var file = File.ReadAllText(viewContext.HttpContext.Server.MapPath(fileName)); writer.Write(file); } } public class JavaScriptViewEngine : VirtualPathProviderViewEngine { public JavaScriptViewEngine() : this(null) { } public JavaScriptViewEngine(IViewPageActivator viewPageActivator) : base() { AreaViewLocationFormats = new[] { "~/Areas/{2}/Views/{1}/{0}.js", "~/Areas/{2}/Views/Shared/{0}.js" }; AreaMasterLocationFormats = new[] { "~/Areas/{2}/Views/{1}/{0}.js", "~/Areas/{2}/Views/Shared/{0}.js" }; AreaPartialViewLocationFormats = new [] { "~/Areas/{2}/Views/{1}/{0}.js", "~/Areas/{2}/Views/Shared/{0}.js" }; ViewLocationFormats = new[] { "~/Views/{1}/{0}.js", "~/Views/Shared/{0}.js" }; MasterLocationFormats = new[] { "~/Views/{1}/{0}.js", "~/Views/Shared/{0}.js" }; PartialViewLocationFormats = new[] { "~/Views/{1}/{0}.js", "~/Views/Shared/{0}.js" }; FileExtensions = new[] { "js" }; } public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) { if (viewName.EndsWith(".js")) viewName = viewName.ChopEnd(".js"); return base.FindView(controllerContext, viewName, masterName, useCache); } protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath) { return new JavaScriptView(partialPath); } protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) { return new JavaScriptView(viewPath); } } }
źródło
Możesz odwrócić sugestię Davesw i zablokować tylko plik .cshtml
<httpHandlers> <add path="*.cshtml" verb="*" type="System.Web.HttpNotFoundHandler"/> </httpHandlers>
źródło
Site.Master
. BiałaWiem, że to dość stary temat, ale chciałbym dodać kilka rzeczy. Wypróbowałem odpowiedź davesw, ale podczas próby załadowania plików skryptów wyrzucał błąd 500, więc musiałem dodać to do web.config:
<validation validateIntegratedModeConfiguration="false" />
do system.webServer. Oto, co mam i udało mi się to uruchomić:
<system.webServer> <handlers> <remove name="BlockViewHandler"/> <add name="JavaScript" path="*.js" verb="GET,HEAD" type="System.Web.StaticFileHandler" /> <add name="CSS" path="*.css" verb="GET,HEAD" type="System.Web.StaticFileHandler" /> <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" /> </handlers> <validation validateIntegratedModeConfiguration="false" /> </system.webServer> <system.web> <compilation> <assemblies> <add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> </assemblies> </compilation> <httpHandlers> <add path="*.js" verb="GET,HEAD" type="System.Web.StaticFileHandler" /> <add path="*.css" verb="GET,HEAD" type="System.Web.StaticFileHandler" /> <add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/> </httpHandlers> </system.web>
Oto więcej informacji na temat walidacji: https://www.iis.net/configreference/system.webserver/validation
źródło
dodaj ten kod w pliku web.config wewnątrz tagu system.web
<handlers> <remove name="BlockViewHandler"/> <add name="JavaScript" path="*.js" verb="GET,HEAD" type="System.Web.StaticFileHandler" /> <add name="CSS" path="*.css" verb="GET,HEAD" type="System.Web.StaticFileHandler" /> <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" /> </handlers>
źródło
Chciałem również umieścić pliki js związane z widokiem w tym samym folderze co widok.
Nie byłem w stanie uruchomić innych rozwiązań w tym wątku, nie dlatego, że są zepsute, ale jestem zbyt nowy w MVC, aby je uruchomić.
Korzystając z informacji podanych tutaj i kilku innych stosów, opracowałem rozwiązanie, które:
Uwaga: używam również routingu atrybutów HTTP. Możliwe, że trasa używana w mojej opinii może zostać zmodyfikowana, aby działała bez włączania tego.
Biorąc pod uwagę następującą przykładową strukturę katalogów / plików:
Controllers -- Example -- ExampleController.vb Views -- Example -- Test.vbhtml -- Test.js
Korzystając z kroków konfiguracyjnych podanych poniżej, w połączeniu z powyższą przykładową strukturą, dostęp do adresu URL widoku testowego można uzyskać za pośrednictwem:,
/Example/Test
a odwołanie do pliku javascript byłoby dostępne za pośrednictwem:/Example/Scripts/test.js
Krok 1 - Włącz routing atrybutów:
Edytuj swój plik /App_start/RouteConfig.vb i dodaj
routes.MapMvcAttributeRoutes()
tuż nad istniejącymi trasami.Imports System Imports System.Collections.Generic Imports System.Linq Imports System.Web Imports System.Web.Mvc Imports System.Web.Routing Public Module RouteConfig Public Sub RegisterRoutes(ByVal routes As RouteCollection) routes.IgnoreRoute("{resource}.axd/{*pathInfo}") ' Enable HTTP atribute routing routes.MapMvcAttributeRoutes() routes.MapRoute( name:="Default", url:="{controller}/{action}/{id}", defaults:=New With {.controller = "Home", .action = "Index", .id = UrlParameter.Optional} ) End Sub End Module
Krok 2 - Skonfiguruj witrynę tak, aby traktowała i przetwarzała /{controller}/Scripts/*.js jako ścieżkę MVC, a nie zasób statyczny
Edytuj swój plik /Web.config, dodając następujące elementy do sekcji system.webServer -> handlers pliku:
<add name="ApiURIs-ISAPI-Integrated-4.0" path="*/scripts/*.js" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
Oto znowu z kontekstem:
<system.webServer> <modules> <remove name="TelemetryCorrelationHttpModule"/> <add name="TelemetryCorrelationHttpModule" type="Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule, Microsoft.AspNet.TelemetryCorrelation" preCondition="managedHandler"/> <remove name="ApplicationInsightsWebTracking"/> <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler"/> </modules> <validation validateIntegratedModeConfiguration="false"/> <handlers> <remove name="ExtensionlessUrlHandler-Integrated-4.0"/> <remove name="OPTIONSVerbHandler"/> <remove name="TRACEVerbHandler"/> <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/> <add name="ApiURIs-ISAPI-Integrated-4.0" path="*/scripts/*.js" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /> </handlers> </system.webServer>
Krok 3 - Dodaj wynik działania następującego skryptu do pliku kontrolera
Będziesz musiał skopiować to do każdego z plików kontrolera. Jeśli chcesz, prawdopodobnie jest sposób na zrobienie tego jako pojedynczej, jednorazowej konfiguracji trasy.
' /Example/Scripts/*.js <Route("Example/Scripts/{filename}")> Function Scripts(filename As String) As ActionResult ' ControllerName could be hardcoded but doing it this way allows for copy/pasting this code block into other controllers without having to edit Dim ControllerName As String = System.Web.HttpContext.Current.Request.RequestContext.RouteData.Values("controller").ToString() ' the real file path Dim filePath As String = Server.MapPath("~/Views/" & ControllerName & "/" & filename) ' send the file contents back Return Content(System.IO.File.ReadAllText(filePath), "text/javascript") End Function
W kontekście jest to mój plik ExampleController.vb:
Imports System.Web.Mvc Namespace myAppName Public Class ExampleController Inherits Controller ' /Example/Test Function Test() As ActionResult Return View() End Function ' /Example/Scripts/*.js <Route("Example/Scripts/{filename}")> Function Scripts(filename As String) As ActionResult ' ControllerName could be hardcoded but doing it this way allows for copy/pasting this code block into other controllers without having to edit Dim ControllerName As String = System.Web.HttpContext.Current.Request.RequestContext.RouteData.Values("controller").ToString() ' the real file path Dim filePath As String = Server.MapPath("~/Views/" & ControllerName & "/" & filename) ' send the file contents back Return Content(System.IO.File.ReadAllText(filePath), "text/javascript") End Function End Class End Namespace
Uwagi końcowe Nie ma nic specjalnego w plikach javascript test.vbhtml view / test.js i nie są one tutaj pokazane.
Trzymam mój CSS w pliku widoku, ale możesz łatwo dodać to rozwiązanie, abyś mógł odwoływać się do swoich plików CSS w podobny sposób.
źródło