2009-03-03 12 views
84

Jakie jest najlepsze miejsce (który folder, itp.) Do umieszczania specyficznych dla widoku plików javascript w aplikacji ASP.NET MVC?Gdzie umieścić pliki JavaScript javascript specyficzne dla widoku w aplikacji ASP.NET MVC?

Aby mój projekt był zorganizowany, bardzo chciałbym móc umieścić je obok siebie w plikach .aspx widoku, ale nie znalazłem dobrego sposobu na odniesienie ich podczas robienia tego bez wystawiania strukturę folderów ~/Views/Action /. Czy to naprawdę złe, aby nie dopuścić do ujawnienia szczegółów tej struktury folderów?

Alternatywą jest umieszczenie ich w folderach ~/Scripts lub ~/Content, ale jest to drobna irytacja, ponieważ teraz muszę się martwić o starcia nazw plików. To irytacja, którą mogę pokonać, jeśli jest to "właściwa rzecz".

+2

Znalazłem sekcje przydatne do tego. Zobacz: http://stackoverflow.com/questions/4311783/asp-net-mvc-3-razor-include-js-file-in-head-tag –

+1

To brzmi jak szalone pytanie, ale niezwykle przydatnym scenariuszem jest zagnieżdżasz plik javascript strony pod .cshtml. (Na przykład z [NestIn] (http://visualstudiogallery.msdn.microsoft.com/9d6ef0ce-2bef-4a82-9a84-7718caa5bb45)). Pomaga uniknąć odbijania się po eksploratorze rozwiązań. –

Odpowiedz

114

Stare pytanie, ale chciałem postawić moją odpowiedź na kogoś innego, kto jej szuka.

ja też chciałem moim zdaniem specyficzne js/css w folderze poglądów, a oto jak to zrobiłem:

W folderze web.config w katalogu głównym/Wyświetleń trzeba zmodyfikować dwie sekcje w celu umożliwienia serwer WWW do obsługi 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żna odwoływać się do URL-jak można się spodziewać:

@Url.Content("~/Views/<ControllerName>/somefile.css") 

pozwoli porcja .js i .css plików i zabroni podawania czegokolwiek innego.

+0

Dzięki, Davesw. Dokładnie to, czego szukałem –

+1

Kiedy to robię, pojawia się błąd, że httpHandlers nie może być używany w trybie potokowym. Chce, abym przeszedł do trybu klasycznego na serwerze. Jaki jest właściwy sposób robienia tego, gdy nie chcemy, aby serwer korzystał z trybu klasycznego? –

+1

@ BjørnØyvindHalvorsen Możesz usunąć jedną lub drugą sekcję obsługi lub wyłączyć sprawdzanie poprawności konfiguracji w swoim pliku web.config. [Zobacz tutaj] (http://stackoverflow.com/questions/4209999/an-asp-net-setting-has-been-detected-that-does-not-apply-inintegrated-managed-p) – davesw

5

Jednym ze sposobów osiągnięcia tego jest dostarczenie własnego ActionInvoker. Korzystanie kod zawarte poniżej, można dodać do konstruktora Twojego kontrolera:

ActionInvoker = new JavaScriptActionInvoker(); 

Teraz, kiedy tylko umieścić plik .js obok widoku:

enter image description here

Można go uzyskać dostęp bezpośrednio:

http://yourdomain.com/YourController/Index.js 

Poniżej znajduje się ź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); 
     } 
    } 
} 
+0

Wydaje się to jednak dobrym rozwiązaniem, ale czy ma to wpływ na czas połączenia z działaniami? –

+0

To może dobrze działać, ale co? Chcę napisać mniej kodu, a nie więcej. – joedotnot

+0

@joedotnot pisać więcej kodu raz, a mniej kodu na zawsze. Mantra programisty, nie? :) –

4

można odwrócić sugestię davesw i blokować tylko .cshtml

<httpHandlers> 
    <add path="*.cshtml" verb="*" type="System.Web.HttpNotFoundHandler"/> 
</httpHandlers> 
+0

Idealnie! :) Ładne, krótkie rozwiązanie! I to działa! :) Nie mam pojęcia, dlaczego nie jest to ustawienie domyślne, ponieważ znacznie lepiej jest zachować skrypty odnoszące się do widoków wraz z rzeczywistymi widokami. Dzięki, Vadym. – BruceHill

+21

Byłbym ostrożny z takim podejściem, nawet jeśli wydaje się ładny i czysty. Jeśli w przyszłości ta aplikacja będzie zawierała silniki widokowe inne niż Razor (z WebForms, Spark itp.), Będą one po cichu upubliczniane. Dotyczy również plików takich jak 'Site.Master'. Biała lista wydaje się bezpieczniejsza. – arserbin3

+0

Zgadzam się z @ arserbin3, że białe listy wydają się bezpieczniejsze; w tym samym czasie nie mogę przewidzieć zmiany mechanizmu wyświetlania aplikacji w aplikacji korporacyjnej. Nie ma na to idealnego narzędzia do automatyzacji. Konwersję należy wykonać ręcznie. Kiedyś zrobiłem to dla dużej aplikacji internetowej; przekonwertowany mechanizm wyświetlania WebForm na Razor, i pamiętam dni koszmaru, przez kilka miesięcy, rzeczy nie działały tu i tam ... Nie myśl o robieniu takich rzeczy jeszcze raz :). Jeśli i tak będę musiał dokonać tak gigantycznej zmiany, to wierzę, że taka zmiana ustawień web.config nie zostanie zapomniana. –

1

Wiem, że to dość stary temat, ale mam kilka rzeczy chciałbym dodać. Próbowałem odpowiedź davesw, ale to było rzucanie błąd 500 podczas próby załadowania plików skryptów, więc musiałem dodać do pliku web.config:

<validation validateIntegratedModeConfiguration="false" /> 

do system.webServer. Oto co mam, i udało mi się zmusić go do pracy:

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

tutaj jest więcej informacji na temat walidacji https://www.iis.net/configreference/system.webserver/validation

0

dodać ten kod w pliku web.config wewnątrz systemu.tag internetowy:

<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> 
Powiązane problemy