2014-06-16 4 views
9

ich keine benutzerdefinierte VirtualPathProvider arbeiten in asp.net MVC 5.VirtualPathProvider in MVC 5

Die FileExists Methode gibt true zurück, aber dann die GetFile Methode aufgerufen zu bekommen scheinen kann, ist es nicht. Ich glaube, das liegt daran, dass IIS die Anfrage übernimmt und .NET nicht damit umgehen kann.

Ich habe versucht, RAMMFAR und erstellen einen benutzerdefinierten Handler, wie in dieser Lösung https://stackoverflow.com/a/12151501/801189, aber immer noch kein Glück. Ich erhalte eine Fehler 404.

My Custom Provider:

public class DbPathProvider : VirtualPathProvider 
{ 
    public DbPathProvider() : base() 
    { 

    } 

    private static bool IsContentPath(string virtualPath) 
    { 
     var checkPath = VirtualPathUtility.ToAppRelative(virtualPath); 
     return checkPath.StartsWith("~/CMS/", StringComparison.InvariantCultureIgnoreCase); 
    } 

    public override bool FileExists(string virtualPath) 
    { 
     return IsContentPath(virtualPath) || base.FileExists(virtualPath); 
    } 

    public override VirtualFile GetFile(string virtualPath) 
    { 
     return IsContentPath(virtualPath) ? new DbVirtualFile(virtualPath) : base.GetFile(virtualPath); 
    } 

    public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) 
    { 
     return null; 

    } 

    public override String GetFileHash(String virtualPath, IEnumerable virtualPathDependencies) 
    { 
     return Guid.NewGuid().ToString(); 
    } 
} 

My Custom Virtual File:

public class DbVirtualFile : VirtualFile 
{ 
    public DbVirtualFile(string path): base(path) 
    { 

    } 

    public override System.IO.Stream Open() 
    { 
     string testPage = "This is a test!"; 
     return new System.IO.MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(testPage)); 
    } 
} 

web.config Handler Ich habe versucht, zu verwenden, ohne Erfolg. Aktuelle Zeit gibt Fehler 500:

<system.webServer> 
<modules runAllManagedModulesForAllRequests="true"> 
    <remove name="FormsAuthenticationModule" /> 
</modules> 

<handlers> 
    <add name="ApiURIs-ISAPI-Integrated-4.0" 
path="/CMS/*" 
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" 
type="System.Web.Handlers.TransferRequestHandler" 
preCondition="runtimeVersionv4.0" /> 
</handlers> 

Wenn ich versuche zu site.com/CMS/Home/Index zu navigieren, die FileExists Methode aufgerufen wird, aber seltsamerweise die virtualPath Parameter BEKOMMT nur ~/CMS/Zuhause.

Das Hinzufügen von Haltepunkten scheint, dass die FileExists-Methode für die URL site.com/CMS/Home/Index wiederholt aufgerufen wird. Dies kann eine unendliche Rekursion verursachen, die den internen Serverfehler verursacht.

Antwort

12

Es war eigentlich nichts mit IIS zu tun, und in der Tat Verwirrung über die Reihenfolge der Ereignisse. Es scheint, dass ich nicht verstanden habe, dass eine Methode mit gerouteter Aktion eine Ansicht zurückgeben muss, die der VirtualPathProvider versucht, zu lösen, anstatt direkt zum VirtualPathProvider zu gehen.

ich eine einfache Steuerung ContentPagesController mit einer einzigen GetPage Aktion aufgerufen:

public class ContentPagesController : Controller 
    { 
     [HttpGet] 
     public ActionResult GetPage(string pageName) 
     { 
      return View(pageName); 
     } 
    } 

ich dann meine Route einrichten, um virtuelle Seiten zu dienen:

routes.MapRoute(
name: "ContentPageRoute", 
url: "CMS/{*pageName}", 
defaults: new { controller = "ContentPages", action = "GetPage" }, 
constraints: new { controller = "ContentPages", action = "GetPage" } 
); 

melde ich mich meinen benutzerdefinierten VirtualPathProvider bevor ich registriere meine Routen, in globals.asax.cs.

Angenommen, ich habe eine Seite in meiner Datenbank mit der relativen URL/CMS/Home/AboutUs. Der pageName -Parameter hat den Wert Home/AboutUs und der Aufruf von View() weist den VirtualPathProvider an, nach Variationen der Datei ~/Views/ContentPages/Home/AboutUs.cshtml zu suchen.

~/Views/ContentPages/Home/AboutUs.aspx 
~/Views/ContentPages/Home/AboutUs.ascx 
~/Views/ContentPages/Home/AboutUs.vbhtml 

Alles, was Sie jetzt tun müssen, ist die virtualPath zu überprüfen, die auf die GetFiles Methode übergeben wird, eine Datenbankabfrage oder einem ähnlichen Gegenstand:

Einige der Varianten wird es gehören aussehen werden. Hier ist eine einfache Art und Weise:

private bool IsCMSPath(string virtualPath) 
     { 
      return virtualPath == "/Views/ContentPages/Home/AboutUs.cshtml" || 
       virtualPath == "~/Views/ContentPages/Home/AboutUs.cshtml"; 
     } 

     public override bool FileExists(string virtualPath) 
     { 
      return IsCMSPath(virtualPath) || base.FileExists(virtualPath); 
     } 

     public override VirtualFile GetFile(string virtualPath) 
     { 
      if (IsCMSPath(virtualPath)) 
      { 
       return new DbVirtualFile(virtualPath); 
      } 

      return base.GetFile(virtualPath); 
     } 

Die benutzerdefinierte virtuelle Datei vorgenommen werden und wieder in den Browser in der GetFile Methode.

Schließlich kann eine benutzerdefinierte Ansichts-Engine erstellt werden, um verschiedene virtuelle Ansichtspfade anzugeben, die an VirtualPathProvider gesendet werden.

Hoffe, das hilft.

+0

Sie antworten ist hilfreich. Ich habe meinen Code funktioniert, aber die Ansicht wird nach "System.IO.Stream Open()" nicht gerendert. Sind Sie auf dasselbe Problem gestoßen? –

+0

Nein, ich glaube nicht, dass ich es tat. Welche Fehler siehst du? –

+0

Nur ein leeres HTML nach Open() gerendert. Die Open() erhält erfolgreich die Ansicht von DB –