将特定于视图的javascript文件放在ASP.NET MVC应用程序中的最佳位置(哪个文件夹等)是什么?
为了使我的项目井井有条,我真的很想能够将它们与视图的.aspx文件并排放置,但是在没有暴露〜/ Views的情况下,我没有找到一种引用它们的好方法/ Action /文件夹结构。让该文件夹结构的详细信息泄漏真的是一件坏事吗?
另一种方法是将它们放在〜/ Scripts或〜/ Content文件夹中,但有一点麻烦,因为现在我不得不担心文件名冲突。但是,如果这是“正确的事情”,我可以克服。
将特定于视图的javascript文件放在ASP.NET MVC应用程序中的最佳位置(哪个文件夹等)是什么?
为了使我的项目井井有条,我真的很想能够将它们与视图的.aspx文件并排放置,但是在没有暴露〜/ Views的情况下,我没有找到一种引用它们的好方法/ Action /文件夹结构。让该文件夹结构的详细信息泄漏真的是一件坏事吗?
另一种方法是将它们放在〜/ Scripts或〜/ Content文件夹中,但有一点麻烦,因为现在我不得不担心文件名冲突。但是,如果这是“正确的事情”,我可以克服。
Answers:
老问题了,但是我想把答案回答其他人。
我也想在views文件夹下查看特定于js / css的文件,这是我的操作方法:
在/ Views根目录下的web.config文件夹中,您需要修改两个部分以使Web服务器能够提供文件:
<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>
然后,您可以从视图文件中引用所需的URL:
@Url.Content("~/Views/<ControllerName>/somefile.css")
这将允许提供.js和.css文件,并禁止提供其他任何内容。
实现这一目标的一种方法是自行提供ActionInvoker。使用下面包含的代码,可以将其添加到控制器的构造函数中:
ActionInvoker = new JavaScriptActionInvoker();
现在,无论何时将.js文件放在视图旁边:

您可以直接访问它:
http://yourdomain.com/YourController/Index.js
以下是来源:
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);
}
}
}
您可以反转davesw的建议并仅阻止.cshtml
<httpHandlers>
<add path="*.cshtml" verb="*" type="System.Web.HttpNotFoundHandler"/>
</httpHandlers>
Site.Master。将白名单列入名单似乎是更安全的方法
我知道这是一个比较老的话题,但是我想补充一些内容。我尝试了davesw的答案,但是在尝试加载脚本文件时抛出500错误,因此我必须将其添加到web.config中:
<validation validateIntegratedModeConfiguration="false" />
到system.webServer。这是我所拥有的,并且能够使它正常工作:
<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>
这是有关验证的更多信息:https : //www.iis.net/configreference/system.webserver/validation
将此代码添加到system.web标记内的web.config文件中
<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>
我还想将与视图相关的js文件放置在与视图相同的文件夹中。
我无法使该线程中的其他解决方案正常工作,不是说它们已经坏了,但我对MVC来说还太陌生,无法使其正常工作。
使用此处给出的信息以及其他几个堆栈,我想到了一个解决方案:
注意:我也在使用HTTP属性路由。在不启用此功能的情况下,可能修改了我的灵魂使用的路线。
给定以下示例目录/文件结构:
Controllers
-- Example
-- ExampleController.vb
Views
-- Example
-- Test.vbhtml
-- Test.js
使用下面给出的配置步骤,结合上面的示例结构,可以通过以下方式访问测试视图URL:/Example/Test通过以下方式引用JavaScript文件:/Example/Scripts/test.js
步骤1-启用属性路由:
编辑您的/App_start/RouteConfig.vb文件,然后routes.MapMvcAttributeRoutes()在现有路线上方添加。
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
第2步-将您的网站配置为将/{controller}/Scripts/*.js当作MVC路径而非静态资源进行处理
编辑/Web.config文件,将以下内容添加到文件的system.webServer-> handlers部分:
<add name="ApiURIs-ISAPI-Integrated-4.0" path="*/scripts/*.js" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
这里还是上下文:
<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>
第3步-将以下脚本操作结果添加到Controller文件中
您将需要将此文件复制到每个Controller文件中。如果您愿意,可能有一种方法可以通过某种方式将其作为单一的一次性路由配置来完成。
' /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对于上下文,这是我的ExampleController.vb文件:
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
最后说明 关于test.vbhtml视图/ test.js javascript文件没有什么特别的,这里没有显示。
我将CSS保留在视图文件中,但是您可以轻松地将其添加到此解决方案中,以便可以以类似方式引用CSS文件。