English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Em sistemas de sites grandes, para melhorar o desempenho de acesso ao sistema, geralmente publicamos conteúdos que não mudam frequentemente como páginas estáticas, como detalhes de produtos de loja, detalhes de notícias. Essas informações, uma vez publicadas, não mudam com frequência. Se continuarmos a processar de maneira dinâmica, certamente causaremos um grande desperdício de recursos no servidor. Mas não podemos criar páginas estáticas individuais para esses conteúdos. Portanto, podemos usar uma maneira de pseudo-staticização no sistema. O que é pseudo-staticização? Você pode pesquisar no Baidu. Vamos introduzir como implementar pseudo-staticização no ASP.NET Core MVC.
No framework MVC, a view representa a vista, e o resultado da execução é o conteúdo final exibido no navegador do cliente, incluindo HTML, CSS, JS, etc. Se quisermos implementar a staticização, precisamos salvar o resultado da execução da view em um arquivo estático, armazenado em um local específico, como disco, cache distribuído, etc. Assim, ao acessar novamente, podemos ler diretamente o conteúdo salvo sem precisar executar novamente a lógica de negócios. Então, como o ASP.NET Core MVC deve fazer para implementar essa funcionalidade? A resposta é usar um filtro. No framework MVC, são fornecidos vários tipos de filtros. Aqui, usaremos o filtro de ação, que oferece dois pontos de tempo: antes da execução da ação e após a execução da ação. Podemos, antes da execução da ação, verificar se já foi gerado uma página estática. Se já foi gerada, podemos ler o conteúdo do arquivo e exibi-lo diretamente, pular a lógica subsequente. Se não foi gerada, continuamos para baixo, capturamos o resultado após a execução da ação e salvamos o conteúdo estático gerado.
Então vamos à implementação específica do código. Primeiro, definimos um tipo de filtro, chamado StaticFileHandlerFilterAttribute, que herda do ActionFilterAttribute fornecido pelo framework. StaticFileHandlerFilterAttribute sobrescreve os dois métodos fornecidos pela classe base: OnActionExecuted (após a execução da ação) e OnActionExecuting (antes da execução da ação). O código específico é o seguinte:
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public class StaticFileHandlerFilterAttribute : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext context){} public override void OnActionExecuting(ActionExecutingContext context){} }
No OnActionExecuting, precisamos verificar se o conteúdo estático já foi gerado, se já foi gerado, sair o conteúdo, a lógica de implementação é como follows
//Gerar o nome do arquivo estático conforme uma regra específica, aqui é conforme a área+"-"+controlador+"-"+ação+Regras de geração de chave string controllerName = context.RouteData.Values["controller"].ToString().ToLower(); string actionName = context.RouteData.Values["action"].ToString().ToLower(); string area = context.RouteData.Values["area"].ToString().ToLower(); //Aqui, a chave padrão é igual a id, claro que podemos configurar diferentes nomes de chave 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 //Verificar se o arquivo existe if (File.Exists(filePath)) { //Se existir, ler diretamente o arquivo using (FileStream fs = File.Open(filePath, FileMode.Open)) { using (StreamReader sr = new StreamReader(fs, Encoding.UTF8)) { //Retornar o conteúdo do arquivo através de contentresult ContentResult contentresult = new ContentResult(); contentresult.Content = sr.ReadToEnd(); contentresult.ContentType = "text/html"; context.Result = contentresult; } } }
No OnActionExecuted, precisamos do resultado da ação, verificar o tipo do resultado da ação se é um ViewResult, se for, executar o código para obter a saída do resultado, gerar a página estática conforme as regras acima, a implementação específica é como follows
//Obter o resultado IActionResult actionResult = context.Result; //Verificar se o resultado é um ViewResult if (actionResult is ViewResult) { ViewResult viewResult = actionResult as ViewResult; //O código a seguir é responsável por executar este ViewResult e inserir o conteúdo html resultante em um 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 linha deve ser chamada, senão o conteúdo ficará vazio writer.Flush(); } //gerar nome de arquivo estático conforme regra 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); } //Escrever no arquivo 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()); } } //Output o resultado atual ContentResult contentresult = new ContentResult(); contentresult.Content = builder.ToString(); contentresult.ContentType = "text/html"; context.Result = contentresult; }
A Chave mencionada acima, adicionamos a propriedade correspondente
public string Key { get;set; }
Dessa forma, podemos usar esse filtro, a maneira de usar é: adicionar a característica [StaticFileHandlerFilter] ao controlador ou ao método do controlador, se quiser configurar diferentes Chaves, pode usar [StaticFileHandlerFilter(Key = "o valor configurado")]
A estatização já foi implementada, precisamos considerar a atualização, se o backend atualizar um artigo, precisamos atualizar a página estática também, há muitos planos: um é excluir a página estática correspondente durante a atualização de conteúdo no backend. Aqui introduzimos outro, atualização agendada, é fazer com que a página estática tenha um período de validade, após esse período de validade, atualize automaticamente. Para implementar essa lógica, precisamos obter o tempo de criação da página estática no método OnActionExecuting, então comparar com o tempo atual, verificar se já expirou, se não expirou, output diretamente o conteúdo, se expirou, continuar executando a lógica posterior. O código específico é o seguinte:
//Obter o objeto de informações do arquivo FileInfo fileInfo = new FileInfo(filePath); //O intervalo de tempo de fechamento, se for menor ou igual a dois minutos, ele será output diretamente, claro, as regras aqui podem ser alteradas 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; } } }
A pseudoestática está pronta aqui. O método atual pode melhorar o desempenho de acesso em certa medida, mas pode não ser suficiente para sistemas de portais grandes. Seguindo a maneira descrita acima, você pode expandir outras funcionalidades, como publicar páginas estáticas no CDN, ou em um servidor de conteúdo separado, etc. Independentemente do método, a lógica de implementação é a mesma.
Isso é tudo o que há no artigo. Espero que ajude na sua aprendizagem e que você apoie fortemente o tutorial Yell.
Declaração: o conteúdo deste artigo é extraído da Internet, pertencendo ao autor original. O conteúdo é contribuído e carregado voluntariamente pelos usuários da Internet, este site não possui direitos de propriedade, não foi editado manualmente e não assume responsabilidade por questões legais relacionadas. Se você encontrar conteúdo suspeito de violação de direitos autorais, por favor, envie e-mail para: notice#oldtoolbag.com (ao enviar e-mail, substitua # por @ para denunciar e forneça provas relevantes. Aos encontrarmos conteúdo suspeito de violação de direitos autorais, este site deletará imediatamente o conteúdo questionável.