I know this is a rather old topic, but I have a few things I would like to add. I tried davesw's answer but it was throwing a 500 error when trying to load the script files, so I had to add this to the web.config:
I also wanted to place js files related to a view in the same folder as the view.
I wasn't able to get the other solutions in this thread to work, not that they are broken but I am too new to MVC to get them working.
Using information given here and several other stacks I came up with a solution that:
Allows the javascript file to be placed in the same directory as the view it is associated with.
Script URL's don't give away the underlying physical site structure
Script URL's don't have to end with a trailing slash (/)
Doesn't interfere with static resources, eg: /Scripts/someFile.js still
works
Doesn't require runAllManagedModulesForAllRequests to be enabled.
Note: I am also using HTTP Attribute Routing. It's possible that the route's used in my soultion could be modified to work without enabling this.
Given the following example directory/file structure:
Controllers
-- Example
-- ExampleController.vb
Views
-- Example
-- Test.vbhtml
-- Test.js
Using the configuration steps given below, combined with the example structure above, the test view URL would be accessed via: /Example/Test and the javascript file would be referenced via: /Example/Scripts/test.js
Step 1 - Enable Attribute Routing:
Edit your /App_start/RouteConfig.vb file and add routes.MapMvcAttributeRoutes() just above the existing routes.MapRoute:
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 treat, and process, /{controller}/Scripts/*.js as an MVC path and not a static resource
Edit your /Web.config file, adding the following to the system.webServer --> handlers section of the file:
Step 3 - Add the following scripts action result to your Controller file
Be sure to edit the route path to match the {controller} name for the
controller, for this example it's:
<Route("Example/Scripts/{filename}")>
You will need to copy this into each of your Controller files. If you wanted, there is probably a way to do this as a single, one-time, route configuration somehow.
' /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 Notes
There is nothing special about the test.vbhtml view / test.js javascript files and are not shown here.
I keep my CSS in the view file but you could easily add to this solution so that you can reference your CSS files in a similar way.