2009-03-03 7 views
84

Was ist der beste Ort (welcher Ordner usw.), um sichtspezifische JavaScript-Dateien in eine ASP.NET MVC-Anwendung zu übertragen?Wohin mit sichtspezifischen JavaScript-Dateien in eine ASP.NET MVC-Anwendung?

Um mein Projekt organisiert zu halten, würde ich wirklich gerne in der Lage sein, sie Seite an Seite mit den ASPX-Dateien der Ansicht zu platzieren, aber ich habe keine gute Möglichkeit gefunden, sie ohne Belichtung zu referenzieren die ~/Views/Action/Ordnerstruktur. Ist es wirklich eine schlechte Sache, Details dieser Ordnerstruktur zu verlieren?

Die Alternative ist, sie in die Ordner ~/Scripts oder ~/Content zu legen, aber es ist eine kleine Irritation, weil ich mich jetzt um Dateikonflikte kümmern muss. Es ist eine Irritation, die ich überwinden kann, wenn es "das Richtige" ist.

+2

Ich fand Abschnitte nützlich für diese. Siehe: http://stackoverflow.com/questions/4311783/asp-net-mvc-3-razor-include-js-file-in-head-tag –

+1

Das klingt wie eine verrückte Frage, aber ein extrem nützliches Szenario ist wann Sie verschachteln die Javascript-Datei einer Seite unter dem .cshtml. (Zum Beispiel mit [NestIn] (http://visualstudiogallery.msdn.microsoft.com/9d6ef0ce-2bef-4a82-9a84-7718caa5bb45)). Es hilft, nicht um den Lösungs-Explorer herumspringen zu müssen. –

Antwort

114

Alte Frage, aber ich wollte meine Antwort setzen, wenn jemand anderes danach sucht.

Ich wollte auch meine Ansicht spezifische js/CSS-Dateien unter den Ansichten-Ordnern, und hier ist, wie ich es tat:

Im web.config Ordner in der Wurzel/Ansichten Sie müssen zwei Abschnitte ändern, damit der Webserver die Dateien dienen:

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

aus Ihrer Sicht Datei Dann können Sie die URLs verweisen, wie Sie erwarten:

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

Dies ermöglicht es der Js dienen und CSS-Dateien und verbietet alles andere.

+0

Danke, davesw. Genau das, was ich gesucht habe –

+1

Wenn ich dies tue, bekomme ich den Fehler, dass httpHandlers nicht im Pipeline-Modus verwendet werden kann. Ich möchte, dass ich auf dem Server in den klassischen Modus umschalte. Was ist die richtige Vorgehensweise, wenn der Server den klassischen Modus nicht verwenden soll? –

+1

@ BjørnØyvindHalvorsen Sie können den einen oder anderen Handlerabschnitt löschen oder die Konfigurationsprüfung in Ihrer web.config deaktivieren. [Siehe hier] (http://stackoverflow.com/questions/4209999/an-asp-net-setting-has-been-detected-that-does-not-apply-in-integrated-managed-p) – davesw

5

Eine Möglichkeit, dies zu erreichen, ist die Lieferung Ihrer eigenen ActionInvoker. Verwenden Sie den Code unten enthalten ist, können Sie Ihren Controller Konstruktor hinzu:

ActionInvoker = new JavaScriptActionInvoker(); 

Nun, wenn Sie eine .js Datei platzieren neben Ihrer Ansicht:

enter image description here

Sie direkt zugreifen können:

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

Unten ist die Quelle:

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

Das scheint eine gute Lösung zu sein, aber beeinflusst es die Anrufzeit für Aktionen? –

+0

Es mag gut funktionieren, aber was? Ich möchte weniger Code schreiben, nicht mehr. – joedotnot

+0

@joedotnot schreiben Sie mehr Code einmal und weniger Code für immer. Das Mantra eines Programmierers, nicht? :) –

4

Sie können davesw Vorschlag umkehren und blockieren nur .cshtml

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

Perfekt! :) Eine schöne kurze Lösung! Und es funktioniert! :) Ich habe keine Ahnung, warum dies nicht die Standardeinstellung ist, weil es viel besser ist, Skripte in Bezug auf Ansichten zusammen mit den tatsächlichen Ansichten zu halten. Danke, Vadym. – BruceHill

+21

Ich wäre vorsichtig mit diesem Ansatz, obwohl es nett und sauber scheint. Wenn diese App in Zukunft andere View-Engines als Razor (z. B. WebForms, Spark usw.) enthält, werden sie automatisch veröffentlicht. Betroffen sind auch Dateien wie 'Site.Master'. Whitelisting scheint der sicherere Ansatz – arserbin3

+0

Ich stimme mit @ arserbin3 überein, dass White-Listing sicherer scheint; Gleichzeitig kann ich die Möglichkeit nicht wahrnehmen, dass die View Engine einer Enterprise-Anwendung von einem zum anderen wechselt. Dafür gibt es kein perfektes Automatisierungswerkzeug. Die Konvertierung muss von Hand erfolgen. Sobald ich dies für eine große Webanwendung getan habe; konvertierte WebForm Viewengine zu Razor, und ich erinnere mich an die Tage des Albtraums, für einige Monate, Dinge funktionierten nicht hier und da ... Kann nicht darüber nachdenken, so etwas wieder zu tun :). Wenn ich sowieso so einen Riesenwechsel machen muss, dann glaube ich, dass solche web.config Einstellungsänderungen nicht vergessen werden. –

1

Ich weiß, das ein ziemlich altes Thema, aber ich habe ein paar Dinge, Ich mag würde hinzuzufügen. Ich habe versucht, die Antwort von davesw aber es wirft einen 500-Fehler beim Versuch, die Script-Dateien zu laden, also musste ich dies auf die web.config hinzufügen:

<validation validateIntegratedModeConfiguration="false" /> 

zu system.webServer. Hier ist, was ich habe, und ich konnte es an die Arbeit:

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

hier weitere Informationen über die Validierung ist: https://www.iis.net/configreference/system.webserver/validation

0

fügen Sie diesen Code in web.config-Datei im System.web tag

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