2009-03-03 5 views
84

Quel est le meilleur emplacement (quel dossier, etc.) pour placer des fichiers javascript spécifiques à une vue dans une application ASP.NET MVC? Pour garder mon projet organisé, j'aimerais vraiment pouvoir les mettre côte à côte avec les fichiers .aspx de la vue, mais je n'ai pas trouvé un bon moyen de les référencer en faisant cela sans exposer la structure ~/Views/Action/folder. Est-ce vraiment une mauvaise chose de laisser les détails de cette structure de dossier de fuite? L'alternative est de les placer dans les dossiers ~/Scripts ou ~/Content, mais c'est une irritation mineure car maintenant je dois m'inquiéter des conflits de noms de fichiers. C'est une irritation que je peux surmonter, si c'est "la bonne chose".Où placer des fichiers javascript spécifiques à une vue dans une application ASP.NET MVC?

+2

J'ai trouvé des sections utiles pour cela. Voir: http://stackoverflow.com/questions/4311783/asp-net-mvc-3-razor-include-js-file-in-head-tag –

+1

Cela ressemble à une question folle, mais un scénario extrêmement utile est quand vous imbriquez le fichier javascript d'une page sous le fichier .cshtml. (Par exemple, avec [NestIn] (http://visualstudiogallery.msdn.microsoft.com/9d6ef0ce-2bef-4a82-9a84-7718caa5bb45)). Cela permet de ne pas avoir à rebondir autour de l'explorateur de solutions. –

Répondre

114

Vieille question, mais je voulais mettre ma réponse au cas où quelqu'un d'autre viendrait la chercher.

Moi aussi, je voulais que ma vue js spécifiques/fichiers css sous le dossier vues, et voici comment je l'ai fait:

Dans le dossier web.config à la racine/Vues vous devez modifier deux sections pour permettre le serveur Web pour servir les fichiers:

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

Ensuite, à partir de votre fichier de vue, vous pouvez référencer les urls comme vous attendez:

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

Cela permettra au service de .js et .css et interdira le service de toute autre chose.

+0

Merci, davesw. Exactement ce que je cherchais –

+1

Lorsque je fais cela, je reçois l'erreur que httpHandlers ne peut pas être utilisé en mode pipeline. Il veut que je passe en mode classique sur le serveur. Quelle est la manière correcte de le faire quand on ne veut pas que le serveur utilise le mode classique? –

+1

@ BjørnØyvindHalvorsen Vous pouvez supprimer l'une ou l'autre section de gestionnaire ou désactiver la validation de la configuration dans votre fichier web.config. [Voir ici] (http://stackoverflow.com/questions/4209999/an-asp-net-setting-has-been-detected-that-does-not-apply-in-integrated-managed-p) – davesw

5

Une façon d'y parvenir est de fournir votre propre ActionInvoker. En utilisant le code inclus ci-dessous, vous pouvez ajouter au constructeur de votre contrôleur:

ActionInvoker = new JavaScriptActionInvoker(); 

Maintenant, chaque fois que vous placez un fichier .js à côté de votre vue:

enter image description here

Vous pouvez y accéder directement:

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

est inférieure à la source:

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

Cela semble une bonne solution, mais est-ce que cela affecte le temps d'appel aux actions? –

+0

Cela pourrait bien marcher, mais qu'est-ce que c'est? Je veux écrire moins de code, pas plus. – joedotnot

+0

@joedotnot vous écrivez plus de code une fois, et moins de code pour toujours. Le mantra d'un programmeur, non? :) –

4

Vous pouvez inverser la suggestion de davesw et bloquer uniquement .cshtml

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

Parfait! :) Une belle solution courte! Et il fonctionne! :) Je n'ai aucune idée pourquoi ce n'est pas le paramètre par défaut, car il est préférable de garder les scripts relatifs aux vues avec les vues réelles. Merci, Vadym. – BruceHill

+21

Je serais prudent avec cette approche, même si elle semble belle et propre. Si à l'avenir, cette application comprend des moteurs de vue autres que Razor (ex WebForms, Spark, etc), ils seront silencieusement public. Affectant également des fichiers comme 'Site.Master'. La liste blanche semble l'approche la plus sûre – arserbin3

+0

Je suis d'accord avec @ arserbin3 que la liste blanche semble plus sûre; dans le même temps, je ne peux pas sentir une possibilité de changement de View Engine d'une application d'entreprise de l'un à l'autre. Il n'y a pas d'outil d'automatisation parfait pour le faire. La conversion doit être faite à la main. Une fois je l'ai fait pour une grande application Web; converti viewengine WebForm à Razor, et je me souviens des jours de cauchemar, pour quelques mois, les choses ne fonctionnaient pas ici et là ... Je ne peux pas penser à faire une telle chose à nouveau :). Si je dois quand même faire un tel changement géant, je crois que ce changement de configuration de web.config ne sera pas oublié. –

1

Je sais que ce sujet est un peu vieux, mais j'ai quelques choses que je voudrais ajouter. J'ai essayé la réponse de davesw mais il jetais une erreur 500 en essayant de charger les fichiers de script, donc je devais ajouter à la web.config:

<validation validateIntegratedModeConfiguration="false" /> 

à system.webServer. Voici ce que j'ai, et j'ai pu le faire fonctionner:

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

est ici plus d'informations sur la validation: https://www.iis.net/configreference/system.webserver/validation

0

ajouter ce code dans le fichier web.config à l'intérieur du système.étiquette 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> 
Questions connexes