Where to place view-specific javascript files in an ASP.NET MVC application?

What is the best place (in which folder, etc.) to place javascript-specific viewing files in an ASP.NET MVC application?

In order for my project to be organized, I would really like them to be able to place them side by side with .aspx files of the form, but I did not find a good way to refer to them without having to expose ~ / Views / Action / folder structure. Is it really bad to report problems with this folder structure?

An alternative is to place them in the ~ / Scripts or ~ / Content folders, but this is a bit of an annoyance because now I have to worry about conflicts with file names. This is an annoyance that I can overcome if it is β€œright.”

+88
asp.net-mvc
Mar 03 '09 at 2:30
source share
6 answers

An old question, but I wanted to put my answer on the fact that someone else is looking for it.

I also wanted my specific js / css files under the views folder, and here is how I did it:

In the web.config folder in the / Views root directory, you need to change two sections so that the web server can serve the files:

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

Then from your view file, you can link to the URLs you expect:

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

This will allow you to serve .js and .css files and prevent anything else from running.

+119
Jun 23 2018-11-12T00:
source share

One way to achieve this is to provide your ActionInvoker . Using the code below, you can add it to the controller constructor:

 ActionInvoker = new JavaScriptActionInvoker(); 

Now when you place the .js file next to your view:

enter image description here

You can access it directly:

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

Below is the 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); } } } 
+5
Jun 07 2018-11-11T00:
source share

You can invert the davesw clause and block only .cshtml

 <httpHandlers> <add path="*.cshtml" verb="*" type="System.Web.HttpNotFoundHandler"/> </httpHandlers> 
+4
Dec 15 '12 at 20:14
source share

I know this is a pretty old topic, but I have a few things I would like to add. I tried davesw's answer, but when I tried to load the script files, it selected 500 errors, so I had to add this to the web.config file:

 <validation validateIntegratedModeConfiguration="false" /> 

in system.webServer. Here is what I have, and I was able to get it to work:

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

More about verification: https://www.iis.net/configreference/system.webserver/validation

+1
Jan 27 '17 at 18:56
source share

add this code to the web.config file inside the 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> 
0
Jul 24 '17 at 20:49
source share

I also wanted to put the js files related to the view in the same folder as the view.

I could not get the other solutions in this thread to work, not that they broke, but I am too new to MVC to get them working.

Using the information given here and several other stacks, I found a solution that:

  • Allows you to place the javascript file in the same directory as the view with which it is associated.
  • The script URL does not reveal the basic physical structure of the site
  • Script URL must not end with a slash (/)
  • Does not interfere with static resources, for example: /Scripts/someFile.js still works
  • Does not require running runAllManagedModulesForAllRequests.

Note: I also use HTTP attribute routing. It is possible that the route used in my soul can be changed to work without including this.

The following is an example of a directory / file structure:

 Controllers -- Example -- ExampleController.vb Views -- Example -- Test.vbhtml -- Test.js 

Using the configuration steps below, combined with the above /Example/Scripts/test.js structure, the URL of the test view will be accessible via: /Example/Test and the javascript file will be referenced via: /Example/Scripts/test.js

Step 1 - Enable Attribute Routing:

Edit the file /App_start/RouteConfig.vb and add routes.MapMvcAttributeRoutes() just above the existing routes. Map:

 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 

Step 2 -Configure your site to process and process / averagecontroller β€Ή/Scripts/*.js as a path to MVC, and not as a static resource

Edit the /Web.config file by adding the following to the system.webServer section β†’ handlers file:

 <add name="ApiURIs-ISAPI-Integrated-4.0" path="*/scripts/*.js" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /> 

Here it is again with context:

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

Step 3 - Add the following script action result to your controller file

  • Be sure to change the route path to match the name {controller} for the controller, for this example it is: <Route (" Example / Scripts / {filename}")>
  • You will need to copy this to each of your controller files. If you want, there may be a way to do this as a one-time route configuration.

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

For context, this is my ExampleController.vb file:

 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 

Final remarks There is nothing special about the javascript files test.vbhtml view / test.js and they are not shown here.

I keep my CSS in a presentation file, but you can easily add to this solution so that you can reference your CSS files in a similar way.

0
Jan 10 '19 at 19:01
source share



All Articles