[asp.net-mvc] ASP.NET MVC 응용 프로그램에서보기 별 javascript 파일을 어디에 배치합니까?

ASP.NET MVC 응용 프로그램에서보기 별 javascript 파일을 배치하는 가장 좋은 위치 (폴더 등)는 무엇입니까?

내 프로젝트를 체계적으로 유지하기 위해 뷰의 .aspx 파일과 나란히 놓을 수 있기를 정말 좋아하지만 ~ / Views를 노출하지 않고이를 수행 할 때 참조 할 좋은 방법을 찾지 못했습니다. / Action / 폴더 구조. 그 폴더 구조의 세부 사항이 유출되도록하는 것이 정말 나쁜 일입니까?

대안은 ~ / Scripts 또는 ~ / Content 폴더에 넣는 것이지만 이제 파일 이름 충돌에 대해 걱정해야하므로 약간의 짜증이납니다. 그러나 그것이 “옳은 일”이라면 극복 할 수있는 자극이다.



답변

오래된 질문이지만 다른 사람이 찾아올 때를 대비하여 내 대답을 넣고 싶었습니다.

나도보기 폴더 아래에 내보기 특정 js / css 파일을 원했고, 여기에 내가 한 방법이 있습니다.

/ Views 루트의 web.config 폴더에서 웹 서버가 파일을 제공 할 수 있도록 두 섹션을 수정해야합니다.

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


답변

나는 이것이 다소 오래된 주제라는 것을 알고 있지만 몇 가지 추가하고 싶은 것이 있습니다. 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를 처음 사용하여 작동하도록 만들 수 없습니다.

여기에 제공된 정보와 몇 가지 다른 스택을 사용하여 다음과 같은 솔루션을 찾았습니다.

  • javascript 파일이 연관된보기와 동일한 디렉토리에 배치되도록 허용합니다.
  • 스크립트 URL은 기본 물리적 사이트 구조를 제공하지 않습니다.
  • 스크립트 URL은 후행 슬래시 (/)로 끝나지 않아도됩니다.
  • 정적 리소스를 방해하지 않습니다. 예 : /Scripts/someFile.js는 여전히 작동합니다.
  • runAllManagedModulesForAllRequests를 활성화 할 필요가 없습니다.

참고 : 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} 이름과 일치하도록 경로 경로를 편집해야합니다.이 예에서는 다음과 같습니다. <Route ( ” Example / Scripts / {filename}”)>
  • 이것을 각 컨트롤러 파일에 복사해야합니다. 원하는 경우 단일, 일회성 경로 구성으로이 작업을 수행 할 수있는 방법이 있습니다.

        ' /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 view / test.js javascript 파일에는 특별한 것이 없으며 여기에 표시되지 않습니다.

내 CSS를보기 파일에 보관하지만이 솔루션에 쉽게 추가하여 비슷한 방식으로 CSS 파일을 참조 할 수 있습니다.


답변