Кешування вхідної сторінки сайту за допомогою System.Web.Mvc.ViewEngines.
На багатьох ресурсах вхідна сторінка занадто важка, формування підсумкового HTML, який видається в браузер потребує 30 секунд і більше. Зрозуміло, что чекати такий довгий час ніхто не буде і користувач просто закриє сайт. Цей ефект ще більше, якщо сайт досить нагружений. Наприклад http://www.votpusk.ru/ мав до падіння оборотів в туристичної індустрії до 33 мільонів відвідувачів на місяць - Rating.mail.ru зрозуміло, що кожного разу формувати тисячі разів на секунду одну і ту ж сторінку ніяк неможливо з точки зору можливостей серверів, та й не має ніякого сенсу, бо вхідна сторінка змінюється досить рідко.
Тому на цієї сторінці я опишу досить хитру технологію кешування вхідної сторінки сайту на ASP.NET.MVC. Могутні класи System.Web.Mvc.ViewEngines.Engines не досить часто використовують починаючі програмісти, тому, сподіваюсь, ця сторінка буде дуже цікавою для них.
По-перше, для напруженого сайту з важкої вхідної сторінкою потрібно зробити окремий вхід, через який буде робитися кеш. Я назвав його CreateCache. Тобто я зробив маркер у каталозі View і далі весь цей код буде викликатися зовні як /Home/CreateCache
Підсумок виклику /Home/CreateCache буде подвійний - по-перше сторінка головна вхідна сторінка сайту з ім'ям Cache.html, яка буде сформована у каталозі сайту, а подруге ця ж сторінка, яка звичайно видається як результат виклику /Home/Index буде видана як результат виклику /Home/CreateCache.
Далі повне налаштування цього метода кешування потребує ще дві речі:
- позначити в IIS дефолтною сторінкою сайту Cache.html, це можно зробити багатьма шляхами, один з них - звичайний редірект своїм власним кодом, наприклад ось так:
- зробити план виклику /Home/CreateCache, який можна зробити декількома шляхами, найпростіший для мене - за допомогою SQL-CLR Виконання періодичних задач в ASP.NET.
Альтернатива цьому методу - е будь-який засіб, описаний тут Request URL Scheduler (альтернатива SQL-CLR GetURL).
Все вищесказане стосується лише зовнішнього оточення беспосередьньо коду кешування. А тепер подивимося безпосередньо на код кешування. У коді контролеру я розмістив лише звернення до оточення головного классу System.Web.Mvc.ViewEngines.Engines, який безпосередньо поєднує VIEW и DATA, щоб зробити підсумковий HTML:
А ось, нарешті і сам сам механізм вштовхування даних у View (зверніть увагу, що цей класс зроблений на Дженеріках, тобто тип класа Model при компіляції невідомий). Вштовхування робиться у 51-й стрічці, все інше лише підготовка до цього. Результат заштовхування - у 53-й стрічці.
1: Public Class MVC_Engine
2:
3:
4: 'Dim MVC As New MVC_Engine
5: 'Dim ResultHTML1 As String = Mvc.GetHTML("Home", "Index", "M1", New With {.model = Nothing}, Me, HttpContext)
6: 'Response.ContentType = "text/html"
7: 'Response.Write(ResultHTML1)
8:
9:
10: Function GetHTML(Of T)(ControllerName As String, ActionName As String, MasterPageName As String, Model As T, ControllerClass As System.Web.Mvc.ControllerBase, HttpContext As System.Web.HttpContextBase) As String
11: 'System.Web.Mvc.ControllerContext - контекст исполнения контроллера
12: Dim Controller_Context As New System.Web.Mvc.ControllerContext()
13: Controller_Context.Controller = ControllerClass
14: Controller_Context.HttpContext = HttpContext
15: Controller_Context.RouteData = New RouteData()
16: Controller_Context.RouteData.Values.Add("controller", ControllerName)
17: Controller_Context.RouteData.Values.Add("action", ActionName)
18: Dim ViewEngineResult As System.Web.Mvc.ViewEngineResult
19: Dim ViewEngineError As String = ""
20: Try
21:
22: 'ViewEngines.Engines - движок поиска нужной вьюхи
23: 'ViewEngineResult.SearchedLocations - Gets or sets the searched locations.
24: 'ViewEngineResult.View - Gets or sets the view.
25: 'ViewEngineResult.ViewEngine - Gets or sets the view engine.
26: 'https://msdn.microsoft.com/en-US/library/system.web.mvc.viewengines%28v=vs.118%29.aspx
27: '
28: ViewEngineResult = System.Web.Mvc.ViewEngines.Engines.FindView(Controller_Context, ActionName, MasterPageName)
29: Catch ex As Exception
30: ViewEngineError = ex.Message
31: End Try
32: Dim ResultPath As String = ""
33: Dim ResultHTML As String = ""
34: If ViewEngineError = "" Then
35: If ViewEngineResult.View IsNot Nothing Then
36: 'єто итоговый путь найденной движком ViewEngines.Engines вьюхи
37: ResultPath = DirectCast(ViewEngineResult.View, System.Web.Mvc.WebFormView).ViewPath
38: '
39: 'System.Web.Mvc.ViewContext - контект исполнения вьюхи
40: 'ControllerContext - Encapsulates information about the HTTP request.
41: 'View - The view to render.
42: 'ViewData - The dictionary that contains the data that is required in order to render the view.
43: 'TempData - The dictionary that contains temporary data for the view.
44: 'Writer - The text writer object that is used to write HTML output.
45: 'https://msdn.microsoft.com/en-us/library/system.web.mvc.viewcontext%28v=vs.118%29.aspx
46: '
47: Try
48: Dim HomeView = New WebFormView(Controller_Context, ResultPath)
49: Dim NoModel = New ViewDataDictionary(Model)
50: Dim Writer = New IO.StringWriter()
51: Dim ViewContext As New System.Web.Mvc.ViewContext(Controller_Context, HomeView, NoModel, New TempDataDictionary(), Writer)
52: 'наконец
53: ViewEngineResult.View.Render(ViewContext, Writer)
54: ResultHTML = Writer.ToString
55: Return ResultHTML
56: Catch ex As Exception
57: Return ex.Message
58: End Try
59: End If
60: Else
61: Return ViewEngineError
62: End If
63: End Function
Цей клас дуже важливий. Late binding та відокремлення даних від їх відображення у ідеології MVC приводить до цікавого ефекту - проект добре компілюється, але падає у будь якому місці на етапі роботи. Тобто ви намагаєтесь відображати дані типу MODEL.DATA а з контролеру передаете для відображення MODEL.DATE - і хоч компіляція пройшла добре, сайт може впасти у будь який момент, коли процесс його виконання дійде до цього місця. Цих глюков не було в звичайної технології ASP.NET (без літер MVC) - там, якщо сайт компілюється, то він і виконуватися буде. Я описував цю проблему багато разів, останній раз тут - Моя CMS для ASP.NET MVC. як Мікрософт відмовилась розвивати ASP.NET і загубила всі свої передові технологічні наработки, повернувшись до простого ASP (який існував до 2002-го року), лише доповнив його трошки не досить вдалої технологією URL-реврайтінгу. Мабуть половина програмістів на ASP.NET після цього кульбіту назавжди прокляла Мікрософт і назавжди лишила цю платформу. Але я залишився і став шукати, чи можливо хоч якось вдосконалити цю не дуже вдалу задумку, що дуже поширилась зараз у web-програмінгі і називається MVC. І знайшов я ось це рішення у вигляді цього класу.
А ще дуже схожа техніка описана у мене тут - AJAX завантаження Partial View