Вступление:
Если вы хотите разделить ресурсы своего приложения (например, 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 для скачивания. Надеюсь, вам тоже понравится моя статья.