English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
En los sistemas de sitios web a gran escala, para mejorar el rendimiento de acceso al sistema, a menudo se publican algunos contenido que no cambian con frecuencia como páginas estáticas, como las páginas de detalles de productos de la tienda en línea, las páginas de detalles de noticias. Una vez que se publican estos información, la frecuencia de cambio no es alta. Si aún se utiliza la forma de salida dinámica para procesar, definitivamente causará un gran desperdicio de recursos en el servidor. Pero no podemos crear páginas estáticas independientes para este contenido. Por lo tanto, podemos procesar de manera pseudoestática en el sistema. ¿Qué es pseudoestática? Puede buscar en Baidu. Aquí les presentamos cómo implementar pseudoestática en ASP.NET Core MVC.
En el framework MVC, view representa la vista, y su resultado es el contenido que se envía al navegador del cliente, que incluye html, css, js, etc. Si queremos implementar la estática, necesitamos guardar el resultado de la ejecución de view en un archivo estático, guardarlo en una ubicación específica, como disco, caché distribuida, etc. La próxima vez que se acceda, se puede leer directamente el contenido guardado sin tener que ejecutar nuevamente la lógica de negocio. Entonces, ¿cómo se debe hacer en ASP.NET Core MVC para implementar esta función? La respuesta es usar un filtro. En el framework MVC, se proporcionan varios tipos de filtros, aquí usaremos el filtro de acción, que ofrece dos puntos en el tiempo: antes de la ejecución de la acción, después de la ejecución de la acción. Podemos determinar si ya se ha generado una página estática antes de la ejecución de la acción, si ya se ha generado, leer directamente el contenido del archivo y enviarlo. El resto de la lógica se omitirá. Si no se ha producido, continuaremos con el flujo normal, capturaremos el resultado en la fase después de la ejecución de la acción y guardaremos el contenido estático generado.
Entonces, procedamos a la implementación específica del código. Primero, definimos un tipo de filtro, lo llamamos StaticFileHandlerFilterAttribute, esta clase hereda de ActionFilterAttribute proporcionada por el framework. StaticFileHandlerFilterAttribute sobrescribe dos métodos proporcionados por la clase base: OnActionExecuted (después de la ejecución de la acción), OnActionExecuting (antes de la ejecución de la acción). El código específico es el siguiente:
[AtributoUso(AtributosDeObjeto.Clase|AtributosDeObjeto.Metodo, PermitirMultiples = false, Heredado = false)] public class StaticFileHandlerFilterAttribute : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext context){} public override void OnActionExecuting(ActionExecutingContext context){} }
En OnActionExecuting, se necesita determinar si el contenido estático ya se ha generado, si ya se ha generado, directamente se muestra el contenido, la lógica de implementación es como sigue
//Generar el nombre del archivo estático según ciertas reglas, aquí es según el área+"-"+controlador+"-"+acción+Regla de generación de key string controllerName = context.RouteData.Values["controller"].ToString().ToLower(); string actionName = context.RouteData.Values["action"].ToString().ToLower(); string area = context.RouteData.Values["area"].ToString().ToLower(); //Aquí el Key por defecto es igual a id, por supuesto, podemos configurar diferentes nombres de Key string id = context.RouteData.Values.ContainsKey(Key) ? context.RouteData.Values[Key].ToString() : ""; if (string.IsNullOrEmpty(id) && context.HttpContext.Request.Query.ContainsKey(Key)) { id = context.HttpContext.Request.Query[Key]; } string filePath = Path.Combine(AppContext.BaseDirectory, "wwwroot", area, controllerName + "-" + actionName + (string.IsNullOrEmpty(id) ? "" : ("-" + id)) + .html"); //Determinar si el archivo existe if (File.Exists(filePath)) { //Si existe, leer directamente el archivo using (FileStream fs = File.Open(filePath, FileMode.Open)) { using (StreamReader sr = new StreamReader(fs, Encoding.UTF8)) { //Devolver el contenido del archivo a través de contentresult ContentResult contentresult = new ContentResult(); contentresult.Content = sr.ReadToEnd(); contentresult.ContentType = "text/html"; context.Result = contentresult; } } }
En OnActionExecuted necesitamos el resultado de la acción, determinar el tipo de resultado de la acción, si es ViewResult, ejecutar el código para obtener la salida, generar una página estática según las reglas anteriores, la implementación específica es como sigue
//Obtener el resultado IActionResult actionResult = context.Result; //Determinar si el resultado es un ViewResult if (actionResult is ViewResult) { ViewResult viewResult = actionResult as ViewResult; //El siguiente código es para ejecutar este ViewResult y poner el contenido html en un objeto StringBuilder var services = context.HttpContext.RequestServices; var executor = services.GetRequiredService<ViewResultExecutor>(); var option = services.GetRequiredService<IOptions<MvcViewOptions>>(); var result = executor.FindView(context, viewResult); result.EnsureSuccessful(originalLocations: null); var view = result.View; StringBuilder builder = new StringBuilder(); using (var writer = new StringWriter(builder)) { var viewContext = new ViewContext( context, view, viewResult.ViewData, viewResult.TempData, writer, option.Value.HtmlHelperOptions); view.RenderAsync(viewContext).GetAwaiter().GetResult(); //Esta línea debe ser llamada, de lo contrario el contenido estará vacío writer.Flush(); } //Generar nombre de archivo estático según las reglas string area = context.RouteData.Values["area"].ToString().ToLower(); string controllerName = context.RouteData.Values["controller"].ToString().ToLower(); string actionName = context.RouteData.Values["action"].ToString().ToLower(); string id = context.RouteData.Values.ContainsKey(Key) ? context.RouteData.Values[Key].ToString() : ""; if (string.IsNullOrEmpty(id) && context.HttpContext.Request.Query.ContainsKey(Key)) { id = context.HttpContext.Request.Query[Key]; } string devicedir = Path.Combine(AppContext.BaseDirectory, "wwwroot", area); if (!Directory.Exists(devicedir))}} { Directory.CreateDirectory(devicedir); } //Escribir en el archivo string filePath = Path.Combine(AppContext.BaseDirectory, "wwwroot", area, controllerName + "-" + actionName + (string.IsNullOrEmpty(id) ? "" : ("-" + id)) + .html"); using (FileStream fs = File.Open(filePath, FileMode.Create)) { using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) { sw.Write(builder.ToString()); } } //Mostrar el resultado actual ContentResult contentresult = new ContentResult(); contentresult.Content = builder.ToString(); contentresult.ContentType = "text/html"; context.Result = contentresult; }
La clave mencionada anteriormente, directamente agregamos la propiedad correspondiente
public string Key { get;set; }
De esta manera podemos usar este filtro, la forma de usarlo: agregar la característica [StaticFileHandlerFilter] a un controlador o método de controlador, si desea configurar diferentes claves, puede usar [StaticFileHandlerFilter(Key = "el valor configurado")]
La estaticización ya se ha implementado, pero también necesitamos considerar las actualizaciones, si el servidor actualiza un artículo, también debemos actualizar la página estática. Hay muchos planes: uno es que cuando se actualiza el contenido en el servidor, se elimine la página estática correspondiente de manera sincronizada. Aquí presentamos otro método, la actualización programada, que es hacer que la página estática tenga una fecha de vencimiento, y que se actualice automáticamente después de que expire. Para implementar esta lógica, necesitamos obtener la fecha de creación de la página estática en el método OnActionExecuting, compararla con la fecha actual y determinar si ha expirado. Si no ha expirado, se muestra directamente el contenido; si ha expirado, se sigue ejecutando la lógica posterior. El código específico es el siguiente:
//Obtener el objeto de información de archivo FileInfo fileInfo = new FileInfo(filePath); //El intervalo de tiempo de liquidación, si es menor o igual a dos minutos, se muestra directamente, por supuesto, las reglas aquí pueden modificarse TimeSpan ts = DateTime.Now - fileInfo.CreationTime; if(ts.TotalMinutes<=2) { using (FileStream fs = File.Open(filePath, FileMode.Open)) { using (StreamReader sr = new StreamReader(fs, Encoding.UTF8)) { ContentResult contentresult = new ContentResult(); contentresult.Content = sr.ReadToEnd(); contentresult.ContentType = "text/html"; context.Result = contentresult; } } }
La伪静态已经实现好了。目前的方法只能在一定程度上提高访问性能,但对于大型门户系统来说,可能远远不够。按照上面介绍的方式,可以再进行其他功能扩展,例如将生成的静态页发布到CDN上,也可以发布到单独的内容服务器等。无论是什么方式,实现思路都是一样的。
Esto es todo el contenido del artículo, espero que sea útil para su aprendizaje y que todos los demás apoyen a la tutorial de grito.
Declaración: el contenido de este artículo se ha obtenido de Internet, es propiedad del autor original, ha sido contribuido y subido por los usuarios de Internet, este sitio no posee los derechos de propiedad, no ha sido editado artificialmente y no asume ninguna responsabilidad legal relacionada. Si encuentra contenido sospechoso de infracción de derechos de autor, por favor envíe un correo electrónico a: notice#oldtoolbag.com (al enviar un correo electrónico, reemplace # con @) para denunciar y proporcionar evidencia relevante. Una vez verificada, este sitio eliminará inmediatamente el contenido sospechoso de infracción.