Вступление:
Если вы хотите разделить ресурсы своего приложения (например, CSS, JavaScript, изображения и т. Д.) Между различными проектами, тогда встроенный ресурс — отличный выбор. Встроенный ресурс также удобен для разработчиков компонентов / элементов управления, поскольку он позволяет разработчикам компонентов / элементов управления распределять все ресурсы приложения всего за одну сборку. Многие поставщики уже используют этот подход. Разработчикам компонентов / элементов управления будет хорошо, если они смогут использовать пакетирование и минимизацию ASP.NET для повышения производительности. Итак, в этой статье я покажу вам, как написать очень простой компонент (помощник), который будет использовать функцию связывания и минимизации ASP.NET для встроенных файлов javascript / css.
Описание:
Прежде всего создайте новый проект библиотеки классов и установите пакеты nuget для Microsoft.AspNet.Mvc , WebActivator и Microsoft ASP.NET Web Optimization Framework 1.1.0-alpha1 (не забудьте включить параметр -Pre в Консоль диспетчера пакетов). Далее добавьте ссылку на сборку System.Web. Затем создайте свой элемент управления / компонент / помощник. Для демонстрации я буду использовать этот пример помощника,
public static class HtmlHelpers { public static MvcHtmlString NewTextBox(this HtmlHelper html, string name) { var js = Scripts.Render("~/ImranB/Embedded/Js").ToString(); var css = Scripts.Render("~/ImranB/Embedded/Css").ToString(); var textbox = html.TextBox(name).ToString(); return MvcHtmlString.Create(textbox + js + css); } }
В этом помощнике я просто использую текстовое поле со стилем и набором скриптов. Пакет стилей включает 2 файла CSS, а пакет скриптов включает 2 файла JS. Итак, просто создайте 2 файла css (NewTextBox1.css и NewTextBox2.css) и 2 файла javascript (NewTextBox1.js и NewTextBox2.js), а затем пометьте эти файлы как встроенный ресурс. Затем добавьте файл AppStart.cs и добавьте в него следующие строки:
[assembly: WebActivator.PostApplicationStartMethod(typeof(AppStart), "Start")] namespace ImranB { public static class AppStart { public static void Start() { ConfigureRoutes(); ConfigureBundles(); } private static void ConfigureBundles() { BundleTable.VirtualPathProvider = new EmbeddedVirtualPathProvider(HostingEnvironment.VirtualPathProvider); BundleTable.Bundles.Add(new ScriptBundle("~/ImranB/Embedded/Js") .Include("~/ImranB/Embedded/NewTextBox1.js") .Include("~/ImranB/Embedded/NewTextBox2.js") ); BundleTable.Bundles.Add(new StyleBundle("~/ImranB/Embedded/Css") .Include("~/ImranB/Embedded/NewTextBox1.css") .Include("~/ImranB/Embedded/NewTextBox2.css") ); } private static void ConfigureRoutes() { RouteTable.Routes.Insert(0, new Route("ImranB/Embedded/{file}.{extension}", new RouteValueDictionary(new { }), new RouteValueDictionary(new { extension = "css|js" }), new EmbeddedResourceRouteHandler() )); } } }
Вышеупомянутый класс использует PostApplicationStartMethod WebActivator , который позволяет вашей сборке запускать некоторый код после метода Application_Start файла global.asax. Метод Start просто регистрирует пользовательский поставщик виртуального пути и два пакета, которые используются в нашем вспомогательном классе NewText. Но платформа оптимизации ASP.NET будет выдавать URL-адрес пакета только тогда, когда debug = «false» или когда BundleTable.EnableOptimizations = true. Поэтому нам также нужно обрабатывать обычные запросы javascript и css. Для этого случая вышеупомянутый метод также зарегистрировал определенный маршрут для обработки запросов встроенных ресурсов, используя обработчик маршрута EmbeddedResourceRouteHandler. Вот определение этого обработчика,
public class EmbeddedResourceRouteHandler : IRouteHandler { IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) { return new EmbeddedResourceHttpHandler(requestContext.RouteData); } } public class EmbeddedResourceHttpHandler : IHttpHandler { private RouteData _routeData; public EmbeddedResourceHttpHandler(RouteData routeData) { _routeData = routeData; } public bool IsReusable { get { return false; } } public void ProcessRequest(HttpContext context) { var routeDataValues = _routeData.Values; var fileName = routeDataValues["file"].ToString(); var fileExtension = routeDataValues["extension"].ToString(); string nameSpace = typeof(EmbeddedResourceHttpHandler) .Assembly .GetName() .Name;// Mostly the default namespace and assembly name are same string manifestResourceName = string.Format("{0}.{1}.{2}", nameSpace, fileName, fileExtension); var stream = typeof(EmbeddedResourceHttpHandler).Assembly.GetManifestResourceStream(manifestResourceName); context.Response.Clear(); context.Response.ContentType = "text/css";// default if (fileExtension == "js") context.Response.ContentType = "text/javascript"; stream.CopyTo(context.Response.OutputStream); } }
EmbeddedResourceRouteHandler возвращает http-обработчик EmbeddedResourceHttpHandler, который будет использоваться для извлечения файла встроенного ресурса из сборки и последующей записи файла в тело ответа. Теперь единственная недостающая вещь — это EmbeddedVirtualPathProvider,
public class EmbeddedVirtualPathProvider : VirtualPathProvider { private VirtualPathProvider _previous; public EmbeddedVirtualPathProvider(VirtualPathProvider previous) { _previous = previous; } public override bool FileExists(string virtualPath) { if (IsEmbeddedPath(virtualPath)) return true; else return _previous.FileExists(virtualPath); } public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) { if (IsEmbeddedPath(virtualPath)) { return null; } else { return _previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart); } } public override VirtualDirectory GetDirectory(string virtualDir) { return _previous.GetDirectory(virtualDir); } public override bool DirectoryExists(string virtualDir) { return _previous.DirectoryExists(virtualDir); } public override VirtualFile GetFile(string virtualPath) { if (IsEmbeddedPath(virtualPath)) { string fileNameWithExtension = virtualPath.Substring(virtualPath.LastIndexOf("/") + 1); string nameSpace = typeof(EmbeddedResourceHttpHandler) .Assembly .GetName() .Name;// Mostly the default namespace and assembly name are same string manifestResourceName = string.Format("{0}.{1}", nameSpace, fileNameWithExtension); var stream = typeof(EmbeddedVirtualPathProvider).Assembly.GetManifestResourceStream(manifestResourceName); return new EmbeddedVirtualFile(virtualPath, stream); } else return _previous.GetFile(virtualPath); } private bool IsEmbeddedPath(string path) { return path.Contains("~/ImranB/Embedded"); } } public class EmbeddedVirtualFile : VirtualFile { private Stream _stream; public EmbeddedVirtualFile(string virtualPath, Stream stream) : base(virtualPath) { _stream = stream; } public override Stream Open() { return _stream; } }
Класс EmbeddedVirtualPathProvider не требует пояснений. Он просто отображает объединенный URL (использованный выше) и возвращает встроенный запрос в виде потока. Обратите внимание, что этот класс будет вызываться платформой оптимизации ASP.NET во время процесса связывания и минимизации. Теперь просто создайте сборку ваш компонент / управление / помощник. Затем создайте пример приложения ASP.NET (MVC) и затем используйте этот компонент / control / helper на своей странице. Например, как,
@using ImranB.Helpers @Html.NewTextBox("New")
Резюме:
В этой статье я показал вам, как создать компонент / control / helper, который использует среду оптимизации ASP.NET. Пример приложения доступен на github для скачивания. Надеюсь, вам тоже понравится моя статья.