Где разместить javascript файлы, специфичные для просмотра, в приложении ASP.NET MVC?
Какое место лучше всего (в какой папке и т.д.) разместить javascript файлы, специфичные для просмотра, в приложении ASP.NET MVC?
Чтобы мой проект был организован, мне бы очень хотелось, чтобы они могли размещать их бок о бок с файлами .aspx вида, но я не нашел хороший способ ссылаться на них при этом, не подвергая ~/Views/Action/folder structure. Разве это действительно плохо, чтобы сообщить о проблемах с этой структурой папок?
Альтернативой является размещение их в папках ~/Scripts или ~/Content, но это небольшое раздражение, потому что теперь мне приходится беспокоиться о конфликтах с именами файлов. Это раздражение, которое я могу преодолеть, если это "правильно".
Ответы
Ответ 1
Старый вопрос, но я хотел поставить свой ответ на то, что кто-то еще ищет его.
Мне тоже захотелось, чтобы мои конкретные файлы js/css под папкой views, и вот как я это сделал:
В папке web.config в корневом каталоге /Views вам необходимо изменить два раздела, чтобы веб-сервер мог обслуживать файлы:
<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 и запретит выполнение чего-либо еще.
Ответ 2
Один из способов достижения этого - предоставить свой 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);
}
}
}
Ответ 3
Вы можете инвертировать предложение davesw и блокировать только .cshtml
<httpHandlers>
<add path="*.cshtml" verb="*" type="System.Web.HttpNotFoundHandler"/>
</httpHandlers>
Ответ 4
Я знаю, что это довольно старая тема, но у меня есть несколько вещей, которые я хотел бы добавить. Я попробовал ответить davesw, но при попытке загрузить файлы script он выбрал 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
Ответ 5
добавить этот код в файл web.config внутри тега system.web
<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>
Ответ 6
Я также хотел поместить файлы js, относящиеся к представлению, в ту же папку, что и представление.
Я не смог заставить другие решения в этой теме работать, не то чтобы они сломались, но я слишком новичок в MVC, чтобы заставить их работать.
Используя приведенную здесь информацию и несколько других стеков, я нашел решение, которое:
- Позволяет размещать файл javascript в том же каталоге, что и представление, с которым он связан.
- Скрипт URL не раскрывает основную физическую структуру сайта
- URL скрипта не должен заканчиваться косой чертой (/)
- Не мешает статическим ресурсам, например: /Scripts/someFile.js все еще работает
- Не требует запуска runAllManagedModulesForAllRequests.
Примечание: я также использую маршрутизацию атрибутов HTTP. Вполне возможно, что маршрут, используемый в моей душе, может быть изменен для работы без включения этого.
Ниже приведен пример структуры каталогов/файлов:
Controllers
-- Example
-- ExampleController.vb
Views
-- Example
-- Test.vbhtml
-- Test.js
Используя шаги конфигурации, приведенные ниже, в сочетании с приведенной выше /Example/Scripts/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 -Configure ваш сайт, чтобы обрабатывать и обрабатывать /averagecontroller‹ /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
Заключительные замечания В файлах javascript test.vbhtml view/test.js нет ничего особенного, и они здесь не показаны.
Я держу свой CSS в файле представления, но вы можете легко добавить к этому решению, чтобы вы могли ссылаться на ваши файлы CSS аналогичным образом.