将视图特定的javascript文件放在ASP.NET MVC应用程序中的位置?

时间:2009-03-03 02:30:15

标签: asp.net-mvc

将特定于视图的javascript文件放在ASP.NET MVC应用程序中的最佳位置(哪个文件夹等)是什么?

为了保持我的项目有条不紊,我真的很想能够将它们与视图的.aspx文件并排放置,但我没有找到一个很好的方法来引用它们而不暴露〜/ Views / Action /文件夹结构。让文件夹结构的细节泄露真的是一件坏事吗?

另一种方法是将它们放在〜/ Scripts或〜/ Content文件夹中,但这是一个小小的烦恼,因为现在我不得不担心文件名冲突。不过,如果这是“正确的事情”,我可以克服这种烦恼。

6 个答案:

答案 0 :(得分:120)

老问题,但我想把我的答案放在其他任何人都来找它。

我也希望我在view文件夹下查看特定的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.Content("~/Views/<ControllerName>/somefile.css")

这将允许提供.js和.css文件,并禁止提供任何其他文件。

答案 1 :(得分:5)

实现此目标的一种方法是提供您自己的ActionInvoker。使用下面的代码,您可以添加到控制器的构造函数:

ActionInvoker = new JavaScriptActionInvoker();

现在,每当您在视图旁边放置.js文件时:

enter image description here

您可以直接访问它:

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);
        }
    }
}

答案 2 :(得分:4)

您可以反转davesw的建议并仅阻止.cshtml

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

答案 3 :(得分:1)

我知道这是一个相当古老的话题,但我想添加一些内容。我尝试了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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

我还想将与视图相关的js文件放置在与视图相同的文件夹中。

我无法使该线程中的其他解决方案正常工作,不是说它们已经坏了,但我对MVC来说还太陌生,无法使其正常工作。

使用此处提供的信息以及其他几个堆栈,我想出了一个解决方案:

  • 允许将javascript文件放置在与其关联的视图相同的目录中。
  • 脚本URL不会放弃底层的物理站点结构
  • 脚本URL不必以斜杠(/)结尾
  • 不干扰静态资源,例如:/Scripts/someFile.js仍然 有效
  • 不需要启用runAllManagedModulesForAllRequests。

注意:我也在使用HTTP属性路由。在我的灵魂中使用的路线可能会修改而无法启用。

给出以下示例目录/文件结构:

Controllers
-- Example
   -- ExampleController.vb

Views
-- Example
   -- Test.vbhtml
   -- Test.js

使用下面给出的配置步骤,结合上面的示例结构,可以通过/Example/Test访问测试视图URL,并且可以通过/Example/Scripts/test.js

引用javascript文件。

步骤1-启用属性路由:

编辑/App_start/RouteConfig.vb文件,并在现有路由上方添加routes.MapMvcAttributeRoutes()。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

第2步-配置您的网站,将/{controller}/Scripts/*.js视为MVC路径而不是静态资源

编辑/Web.config文件,将以下内容添加到文件的system.webServer->处理程序部分:

<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}名称相匹配 控制器,在此示例中为: 示例 /脚本/ {文件名}”)>
  • 您将需要将其复制到每个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文件。