2014-06-16 16 views
9

io non riesco a ottenere una consuetudine VirtualPathProvider lavora in asp.net MVC 5.VirtualPathProvider in MVC 5

Il metodo FileExists ritorna vero, ma allora il metodo GetFile non viene chiamato. Credo che ciò accada perché IIS accetta la richiesta e non consente a .NET di gestirlo.

Ho provato a impostare RAMMFAR e creare un gestore personalizzato, come in questa soluzione https://stackoverflow.com/a/12151501/801189 ma ancora senza fortuna. Mi appare un errore 404.

mio provider personalizzato:

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)); 
    } 
} 

gestore web.config ho cercato di utilizzare, senza successo. Attualmente dà errore 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> 

Se provo a navigare site.com/CMS/Home/Index, il metodo viene chiamato FileExists ma stranamente, il parametro virtualPath recieves solo ~/CMS/Casa.

Aggiunta di punti di interruzione, sembra che per l'url site.com/CMS/Home/Index, il metodo FileExists continui a essere chiamato ripetutamente. Questo potrebbe causare una ricorsione infinita, dando l'errore del server interno.

risposta

12

In realtà non aveva nulla a che fare con IIS e, di fatto, confusione sull'ordine degli eventi. Sembra che non abbia capito che un metodo di azione indirizzato deve restituire una vista, che il VirtualPathProvider proverà a risolvere, piuttosto che andare direttamente al VirtualPathProvider.

creo un controller semplice chiamata ContentPagesController con una sola azione getPage:

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

Poi ho impostato il mio percorso per servire pagine virtuali:

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

registro il mio VirtualPathProvider personalizzato prima mi iscrivo i miei percorsi, in globals.asax.cs.

Ora supponiamo di avere una pagina nel mio database con l'url relativo/CMS/Home/AboutUs. Il parametro pageName avrà valore Home/AboutUs e la chiamata return View() istruirà il VirtualPathProvider alla ricerca di varianti del file ~/Views/ContentPages/Home/AboutUs.cshtml.

Alcune delle variazioni sarà cercare includono:

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

Tutto quello che occorre fare è controllare la virtualPath che viene passato al metodo GetFiles, utilizzando una ricerca nel database o simili. Ecco un modo semplice:

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); 
     } 

Il file virtuale personalizzato verrà effettuata e restituita al browser nel metodo GetFile.

Infine, è possibile creare un motore di visualizzazione personalizzato per fornire percorsi di visualizzazione virtuale diversi inviati a VirtualPathProvider.

Spero che questo aiuti.

+0

La risposta è utile. Ho ottenuto il mio codice funzionante, tuttavia la visualizzazione non riesce a eseguire il rendering dopo "System.IO.Stream Open()". Hai riscontrato lo stesso problema? –

+0

No, non credo di averlo fatto. Quali errori stai vedendo? –

+0

Solo un html vuoto reso dopo Open(). L'Open() ottiene correttamente la vista dal DB –