2011-09-18 38 views
1

我傾向於不喜歡張貼幾十行代碼,並假設整個社區有興趣解開我的混亂。在這種情況下,我運用了所有我能想到的在Google上搜索的內容,通過Glimpse和Firebug/Fiddler進行了追蹤,我留下的是偶爾的工作行爲,這對調試尤其惱人。所以,我打電話尋求幫助。自定義未找到路線一次只觸發

這裏有一個要點:我有一系列處理MVC路由的類,這些類無法找到(並且會產生404錯誤),這要感謝@AndrewDavey。我試圖攔截404並顯示任何存在的數據驅動內容。它一直運行,直到我刷新頁面。該請求在第一次加載時起作用,但之後再也不會再次觸發。

如果你感到無聊或有癢,整個代碼塊在下面。

設置是這樣的:

  • 通過的NuGet
  • 添加WebActivator在你的AppStart的文件夾中添加一個CS文件下面
  • 代碼中的 「PageContext中」 連接字符串添加到您的web.config
  • 運行的應用程序,默認MVC畫面出現
  • 現在,添加「/ ABC」到URL的結束(即http://localhost/abc
  • 存儲在數據庫中的cshtml視圖將呈現。
  • 更改數據庫中視圖的標記並重新加載頁面。 注意您的瀏覽器中沒有更改。

的/ ABC路線假設你在數據庫中的記錄與以下

  • 路徑: 「〜/ ABC/index.cshtml」

  • 查看:"@{ Layout = null;}<!doctype html><html><head><title>abc</title></head><body><h2>About</h2></body></html>"

我不知道爲什麼第一個請求工作s和隨後的請求不會達到中斷點並提供陳舊的內容。

我的懷疑是:

  • 一些巫術與緩存VirtualFile
  • 東西
  • 錯誤配置的處理器

感謝您的幫助 - 這裏的代碼((但在哪裏?)因爲我可恥地掖着我的尾巴發佈這麼多的代碼)。

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Data.Entity; 
using System.IO; 
using System.Linq; 
using System.Text; 
using System.Web; 
using System.Web.Caching; 
using System.Web.Hosting; 
using System.Web.Mvc; 
using System.Web.Routing; 
using System.Web.SessionState; 
using Microsoft.Web.Infrastructure.DynamicModuleHelper; 
using SomeCms; 

[assembly: WebActivator.PreApplicationStartMethod(typeof(Sample.Web.App_Start.cms), "PreStart")] 

namespace Sample.Web.App_Start 
{ 
    public static class cms 
    { 
     public static void PreStart() 
     { 
      DynamicModuleUtility.RegisterModule(typeof(InstallerModule)); 
     } 
    } 
} 

namespace SomeCms 
{ 
    class ActionInvokerWrapper : IActionInvoker 
    { 
     readonly IActionInvoker actionInvoker; 

     public ActionInvokerWrapper(IActionInvoker actionInvoker) 
     { 
      this.actionInvoker = actionInvoker; 
     } 

     public bool InvokeAction(ControllerContext controllerContext, string actionName) 
     { 
      if (actionInvoker.InvokeAction(controllerContext, actionName)) 
      { 
       return true; 
      } 

      // No action method was found. 
      var controller = new CmsContentController(); 
      controller.ExecuteCmsContent(controllerContext.RequestContext); 

      return true; 
     } 
    } 

    class ControllerFactoryWrapper : IControllerFactory 
    { 
     readonly IControllerFactory factory; 

     public ControllerFactoryWrapper(IControllerFactory factory) 
     { 
      this.factory = factory; 
     } 

     public IController CreateController(RequestContext requestContext, string controllerName) 
     { 
      try 
      { 
       var controller = factory.CreateController(requestContext, controllerName); 
       WrapControllerActionInvoker(controller); 
       return controller; 
      } 
      catch (HttpException ex) 
      { 
       if (ex.GetHttpCode() == 404) 
       { 
        return new CmsContentController(); 
       } 

       throw; 
      } 
     } 

     static void WrapControllerActionInvoker(IController controller) 
     { 
      var controllerWithInvoker = controller as Controller; 
      if (controllerWithInvoker != null) 
      { 
       controllerWithInvoker.ActionInvoker = new ActionInvokerWrapper(controllerWithInvoker.ActionInvoker); 
      } 
     } 

     public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName) 
     { 
      return factory.GetControllerSessionBehavior(requestContext, controllerName); 
     } 

     public void ReleaseController(IController controller) 
     { 
      factory.ReleaseController(controller); 
     } 
    } 

    class InstallerModule : IHttpModule 
    { 
     static bool installed; 
     static readonly object installerLock = new object(); 

     public void Init(HttpApplication application) 
     { 
      if (installed) 
      { 
       return; 
      } 

      lock (installerLock) 
      { 
       if (installed) 
       { 
        return; 
       } 

       Install(); 
       installed = true; 
      } 
     } 

     static void Install() 
     { 
      Database.SetInitializer(new CreateDatabaseIfNotExists<PageContext>()); 
      HostingEnvironment.RegisterVirtualPathProvider(new ExampleVirtualPathProvider()); 
      WrapControllerBuilder(); 
      AddNotFoundRoute(); 
      AddCatchAllRoute(); 
     } 

     static void WrapControllerBuilder() 
     { 
      ControllerBuilder.Current.SetControllerFactory(new ControllerFactoryWrapper(ControllerBuilder.Current.GetControllerFactory())); 
     } 

     static void AddNotFoundRoute() 
     { 
      // To allow IIS to execute "/cmscontent" when requesting something which is disallowed, 
      // such as /bin or /add_data. 
      RouteTable.Routes.MapRoute(
       "CmsContent", 
       "cmscontent", 
       new { controller = "CmsContent", action = "CmsContent" } 
      ); 
     } 

     static void AddCatchAllRoute() 
     { 
      RouteTable.Routes.MapRoute(
       "CmsContent-Catch-All", 
       "{*any}", 
       new { controller = "CmsContent", action = "CmsContent" } 
      ); 
     } 

     public void Dispose() { } 
    } 

    public class CmsContentController : IController 
    { 
     public void Execute(RequestContext requestContext) 
     { 
      ExecuteCmsContent(requestContext); 
     } 

     public void ExecuteCmsContent(RequestContext requestContext) 
     { 
      //new CmsContentViewResult().ExecuteResult(new ControllerContext(requestContext, new FakeController())); 
      new CmsContentViewResult().ExecuteResult(new ControllerContext(requestContext, new FakeController())); 
     } 

     // ControllerContext requires an object that derives from ControllerBase. 
     // NotFoundController does not do this. 
     // So the easiest workaround is this FakeController. 
     class FakeController : Controller { } 
    } 

    public class CmsContentHandler : IHttpHandler 
    { 
     public void ProcessRequest(HttpContext context) 
     { 
      var routeData = new RouteData(); 
      routeData.Values.Add("controller", "CmsContent"); 
      var controllerContext = new ControllerContext(new HttpContextWrapper(context), routeData, new FakeController()); 
      var cmsContentViewResult = new CmsContentViewResult(); 
      cmsContentViewResult.ExecuteResult(controllerContext); 
     } 

     public bool IsReusable 
     { 
      get { return false; } 
     } 

     // ControllerContext requires an object that derives from ControllerBase. 
     class FakeController : Controller { } 
    } 

    public class CmsContentViewResult : ViewResult 
    { 
     public CmsContentViewResult() 
     { 
      ViewName = "index"; 
     } 

     public override void ExecuteResult(ControllerContext context) 
     { 
      var request = context.HttpContext.Request; 
      if (request != null && request.Url != null) 
      { 
       var url = request.Url.OriginalString; 

       ViewData["RequestedUrl"] = url; 
       ViewData["ReferrerUrl"] = (request.UrlReferrer != null && request.UrlReferrer.OriginalString != url) 
               ? request.UrlReferrer.OriginalString 
               : null; 
      } 

      base.ExecuteResult(context); 
     } 
    } 

    public class ExampleVirtualPathProvider : VirtualPathProvider 
    { 
     private readonly List<SimpleVirtualFile> virtualFiles = new List<SimpleVirtualFile>(); 

     public ExampleVirtualPathProvider() 
     { 
      var context = new PageContext(); 
      var pages = context.Pages.ToList(); 

      foreach (var page in pages) 
      { 
       virtualFiles.Add(new SimpleVirtualFile(page.Path)); 

      } 
     } 

     public override bool FileExists(string virtualPath) 
     { 
      var files = (from f in virtualFiles 
         where f.VirtualPath.Equals(virtualPath, StringComparison.InvariantCultureIgnoreCase) || 
           f.RelativePath.Equals(virtualPath, StringComparison.InvariantCultureIgnoreCase) 
         select f) 
         .ToList(); 

      return files.Count > 0 || base.FileExists(virtualPath); 
     } 

     private class SimpleVirtualFile : VirtualFile 
     { 
      public SimpleVirtualFile(string filename) : base(filename) 
      { 
       RelativePath = filename; 
      } 

      public override Stream Open() 
      { 
       var context = new PageContext(); 
       var page = context.Pages.FirstOrDefault(p => p.Path == RelativePath); 

       return new MemoryStream(Encoding.ASCII.GetBytes(page.View), false); 
      } 

      public string RelativePath { get; private set; } 
     } 

     private class SimpleVirtualDirectory : VirtualDirectory 
     { 
      public SimpleVirtualDirectory(string virtualPath) 
       : base(virtualPath) 
      { 

      } 

      public override IEnumerable Directories 
      { 
       get { return null; } 
      } 

      public override IEnumerable Files 
      { 
       get 
       { 
        return null; 
       } 
      } 

      public override IEnumerable Children 
      { 
       get { return null; } 
      } 
     } 

     public override VirtualFile GetFile(string virtualPath) 
     { 
      var files = (from f in virtualFiles 
         where f.VirtualPath.Equals(virtualPath, StringComparison.InvariantCultureIgnoreCase) || 
           f.RelativePath.Equals(virtualPath, StringComparison.InvariantCultureIgnoreCase) 
         select f).ToList(); 
      return files.Count > 0 
       ? files[0] 
       : base.GetFile(virtualPath); 
     } 

     public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) 
     { 
      return IsPathVirtual(virtualPath) ? null : base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart); 
     } 

     private bool IsPathVirtual(string virtualPath) 
     { 
      var checkPath = VirtualPathUtility.ToAppRelative(virtualPath); 
      return 
       virtualFiles.Any(f => checkPath.StartsWith(virtualPath, StringComparison.InvariantCultureIgnoreCase)) || 
       virtualFiles.Any(f => checkPath.Replace("~", "").StartsWith(virtualPath, StringComparison.InvariantCultureIgnoreCase)); 
     } 

     public override bool DirectoryExists(string virtualDir) 
     { 
      return IsPathVirtual(virtualDir) || Previous.DirectoryExists(virtualDir); 
     } 

     public override VirtualDirectory GetDirectory(string virtualDir) 
     { 
      return IsPathVirtual(virtualDir) 
       ? new SimpleVirtualDirectory(virtualDir) 
       : Previous.GetDirectory(virtualDir); 
     } 
    } 

    public class ContentPage 
    { 
     public int Id { get; set; } 
     public string Path { get; set; } 
     public string View { get; set; } 
    } 

    public class PageContext : DbContext 
    { 
     public DbSet<ContentPage> Pages { get; set; } 
    } 
} 

回答

2

這個問題原來是一個非問題。我對虛擬路徑提供程序中的緩存依賴性的監督對虛擬路徑返回null。因此,視圖被無限期地緩存。

解決方案是使用立即過期的自定義緩存依賴項提供程序。

public class NoCacheDependency : CacheDependency 
{ 
    public NoCacheDependency() 
    { 
     NotifyDependencyChanged(this, EventArgs.Empty); 
    } 
} 

public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) 
{ 
    return IsPathVirtual(virtualPath) ? new NoCacheDependency() : base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart); 
} 
+0

您是否處於發佈模式或調試模式? – nikmd23

+0

這不是編譯模式的問題。這是一個潛在的緩存機制問題,假設在應用程序域的生命週期期間緩存空信號。您可以通過修改運行時重新創建應用程序域的web.config來測試它。在這一點上,頁面變化反映出來。 –