이 방법이 가장 효과적인 방법은 아니지만 테스트를 거쳐 작동합니다. GetRequestKey() 논리를 조정해야 할 수도 있고 시나리오에 따라 임시 임시 저장 위치를 선택할 수도 있습니다. 나는 당신이 관심을 가지지 않는 것처럼 보였기 때문에 파일 시간에 대한 어떤 캐싱도 구현하지 않았다. 시간이 소량 떨어져있는 것을 확인했다면 추가하기가 어렵지 않을 것이다. 모든 요청에 대한 파일 액세스 오버 헤드.
먼저,이 요청 중에 렌더링 된 모든 뷰에 대해 가장 최근에 수정 된 시간을 추적하는 뷰 엔진으로 RazorViewEngine을 확장합니다. 우리는 세션 ID와 요청 타임 스탬프에 의해 입력 된 세션에 최신 시간을 저장함으로써이를 수행합니다. 다른 뷰 엔진으로도이 작업을 쉽게 수행 할 수 있습니다.
public class CacheFriendlyRazorViewEngine : RazorViewEngine
{
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
UpdateLatestTime(controllerContext, GetLastModifiedForPath(controllerContext, viewPath));
var pathToMaster = masterPath;
if (string.IsNullOrEmpty(pathToMaster))
{
pathToMaster = "~/Views/Shared/_Layout.cshtml"; // TODO: derive from _ViewStart.cshtml
}
UpdateLatestTime(controllerContext, GetLastModifiedForPath(controllerContext, pathToMaster));
return base.CreateView(controllerContext, viewPath, masterPath);
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
UpdateLatestTime(controllerContext, GetLastModifiedForPath(controllerContext, partialPath));
return base.CreatePartialView(controllerContext, partialPath);
}
private DateTime GetLastModifiedForPath(ControllerContext controllerContext, string path)
{
return System.IO.File.GetLastWriteTime(controllerContext.HttpContext.Server.MapPath(path)).ToUniversalTime();
}
public static void ClearLatestTime(ControllerContext controllerContext)
{
var key = GetRequestKey(controllerContext.HttpContext);
controllerContext.HttpContext.Session.Remove(key);
}
public static DateTime GetLatestTime(ControllerContext controllerContext, bool clear = false)
{
var key = GetRequestKey(controllerContext.HttpContext);
var timestamp = GetLatestTime(controllerContext, key);
if (clear)
{
ClearLatestTime(controllerContext);
}
return timestamp;
}
private static DateTime GetLatestTime(ControllerContext controllerContext, string key)
{
return controllerContext.HttpContext.Session[key] as DateTime? ?? DateTime.MinValue;
}
private void UpdateLatestTime(ControllerContext controllerContext, DateTime timestamp)
{
var key = GetRequestKey(controllerContext.HttpContext);
var currentTimeStamp = GetLatestTime(controllerContext, key);
if (timestamp > currentTimeStamp)
{
controllerContext.HttpContext.Session[key] = timestamp;
}
}
private static string GetRequestKey(HttpContextBase context)
{
return string.Format("{0}-{1}", context.Session.SessionID, context.Timestamp);
}
}
다음으로, 일부 글로벌 필터, global.asax.cs 마지막으로
protected void Application_Start()
{
System.Web.Mvc.ViewEngines.Engines.Clear();
System.Web.Mvc.ViewEngines.Engines.Add(new ViewEngines.CacheFriendlyRazorViewEngine());
...
}
에 새 하나를 사용하여 기존의 엔진 (들)을 교체하거나 당 컨트롤러 근거하여 OnResultExecuted를 추가합니다. 참고, 나는 응답을 보낸 후에 컨트롤러에서 OnResultExecuted가 실행되므로 필터를 사용해야한다고 생각합니다. 내 테스트 결과이 사실을 나타냅니다.
또한 타임 스탬프를 사용하여 세션을 오염시키지 않으므로 세션에서 값을 지우고 있습니다. 캐시에 저장하고 짧은 만료를 설정하여 명시 적으로 정리할 필요가 없도록하거나 세션에 세션을 저장하는 트랜잭션 비용을 피하기 위해 세션을 메모리에 보관하지 않을 수도 있습니다.
[UpdateLastModifiedFromViews]
public class HomeController : Controller
{
...
}
재미있는 문제 :
마지막으로, 또는 글로벌 필터로 사용하고자하는 컨트롤러에 필터를 적용합니다. 내 솔루션이 가장 쉬운 방법인지는 모르지만 그걸 털어 놓는 것은 재미있었습니다. – tvanfosson