gpt4 book ai didi

c# - 为什么 MVC 5 不调用我的 VirtualPathProvider 类的 GetFile 方法?

转载 作者:太空狗 更新时间:2023-10-29 17:48:04 26 4
gpt4 key购买 nike

我正在尝试从数据库加载 Razor View。

我关注 ASP.NET MVC and virtual viewsVirtualPathProvider in MVC 5这样做。

我的代码:

虚拟路径提供者:

 public class DbPathProvider : VirtualPathProvider
{
public override bool FileExists(string virtualPath)
{
var page = FindPage(virtualPath);
if (page == null)
{
return base.FileExists(virtualPath);
}
else
{
return true;
}
}

public override VirtualFile GetFile(string virtualPath)
{
var page = FindPage(virtualPath);
if (page == null)
{
return base.GetFile(virtualPath);
}
else
{
return new DbVirtualFile(virtualPath, page.PageData.ToArray());
}
}

private SiteModel FindPage(string virtualPath)
{
var db = new DatabaseContext();
var page = db.SiteModels.FirstOrDefault(x => x.SiteName == virtualPath);
return page;
}
}

虚拟文件

public class DbVirtualFile : VirtualFile
{
private byte[] data;

public DbVirtualFile(string virtualPath, byte[] data)
: base(virtualPath)
{
this.data = data;
}

public override System.IO.Stream Open()
{
return new MemoryStream(data);
}
}

全局.asax:

protected void Application_Start()
{
HostingEnvironment.RegisterVirtualPathProvider(new DbPathProvider());
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);

}

行动:

public ActionResult Display(string id)
{
var db = new DatabaseContext();
var site = db.SiteModels.FirstOrDefault(x => x.PageName == id);
if (site == null)
{
return RedirectToAction("Index", "Home");
}
ViewBag.Body = site.PageContent;
return View(System.IO.Path.GetFileNameWithoutExtension(site.SiteName));
}

数据:

enter image description here

案例一:

当 virtualPath 值为 "/Views/Home/Contact.cshtml" 时,FileExists 方法返回 true 并调用 GetFile 方法

案例二:

当 virtualPath 值为 "~/Home/Display/ce28bbb6-03cb-4bf4-8820-373890396a90" 时,FileExists 方法返回 trueGetFile 方法和永远不会调用显示操作。 结果是

HTTP 错误 404.0 - 未找到您要查找的资源已被删除、更名或暂时不可用。

我不知道动态 View 。我刚刚阅读了那两篇文章并尝试实现它。

请告诉我哪里做错了。

我正在使用 MVC 5 和 .NET 4.5

最佳答案

有些事情我应该可以帮助你。有一些你没有考虑的事情没关系,因为我也遇到过很多麻烦。

我认为您在这里遇到的问题是了解所有内容的触发顺序。这是发生了什么:

  1. 首先调用 VirtualPathProvider FileExists 方法并这是您施展魔法寻找页面的地方。我的方法和你的略有不同,这里是一个例子:

    public IList<Page> Pages
    {
    get
    {
    using (var uow = new UnitOfWork<SkipstoneContext>())
    {
    var companyService = new CompanyService(uow);
    var company = companyService.GetTenant();

    if (company != null)
    {
    var pageService = new PageService(uow, company.Id);

    return pageService.GetPublished();
    }
    }

    return null;
    }
    }

    public override bool FileExists(string virtualPath)
    {
    if (IsVirtualPath(virtualPath))
    {
    if (FindPage(virtualPath) != null)
    {
    var file = (PageVirtualFile)GetFile(virtualPath);
    return file.Exists;
    }
    }

    return Previous.FileExists(virtualPath);
    }

    public override VirtualFile GetFile(string virtualPath)
    {
    if (IsVirtualPath(virtualPath))
    {
    var page = FindPage(virtualPath);
    if (page != null)
    {
    var decodedString = Uri.UnescapeDataString(page.ViewData);
    var bytes = Encoding.ASCII.GetBytes(decodedString);

    return new PageVirtualFile(virtualPath, bytes);
    }
    }

    return Previous.GetFile(virtualPath);
    }

    public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
    {
    if (IsVirtualPath(virtualPath))
    return null;

    return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
    }

    public override string GetFileHash(string virtualPath, System.Collections.IEnumerable virtualPathDependencies)
    {
    if (IsVirtualPath(virtualPath))
    return Guid.NewGuid().ToString();

    return Previous.GetFileHash(virtualPath, virtualPathDependencies);
    }

    private Page FindPage(string virtualPath)
    {
    var virtualName = VirtualPathUtility.GetFileName(virtualPath);
    var virtualExtension = VirtualPathUtility.GetExtension(virtualPath);

    try
    {
    if (Pages != null)
    {
    var id = Convert.ToInt32(virtualName.Replace(virtualExtension, ""));
    var page = Pages.Where(model => model.Id == id && model.Extension.Equals(virtualExtension, StringComparison.OrdinalIgnoreCase)).SingleOrDefault();

    return page;
    }
    }
    catch(Exception ex)
    {
    // Do nothing
    }

    return null;
    }

    private bool IsVirtualPath(string virtualPath)
    {
    var path = (VirtualPathUtility.GetDirectory(virtualPath) != "~/") ? VirtualPathUtility.RemoveTrailingSlash(VirtualPathUtility.GetDirectory(virtualPath)) : VirtualPathUtility.GetDirectory(virtualPath);
    if (path.Equals("~/Views/Routing", StringComparison.OrdinalIgnoreCase) || path.Equals("/Views/Routing", StringComparison.OrdinalIgnoreCase))
    return true;
    else
    return false;
    }
  2. 现在,如果这个页面是从数据库提供的,它就是一个虚拟页面,那么接下来发生的事情就是它调用您的 MvcHandler(在我的处理程序中我有这些函数)

    protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
    {
    var vpp = new SkipstoneVirtualPathProvider(); // Create an instance of our VirtualPathProvider class
    var requestContext = ((MvcHandler)httpContext.Handler).RequestContext; // Get our request context
    var path = requestContext.HttpContext.Request.Url.AbsolutePath; // Get our requested path
    var pages = vpp.Pages; // Get all the published pages for this company

    if (pages != null && !string.IsNullOrEmpty(path)) // If we have any pages and we have a path
    {
    var page = this.MatchPage(pages, path);
    if (page != null) // If we find the page
    {
    requestContext.RouteData.Values["controller"] = "Routing"; // Set the controller
    requestContext.RouteData.Values["action"] = "Index"; // And the action
    }
    }

    return base.BeginProcessRequest(httpContext, callback, state);
    }

    private Page MatchPage(IList<Page> pages, string path)
    {
    if (path == "/" || !path.EndsWith("/"))
    {
    var page = pages.Where(model => model.Path.Equals(path, StringComparison.OrdinalIgnoreCase)).SingleOrDefault(); // Try to match the path first
    if (page == null) // If we have no page, then get the directory and see if that matches any page
    {
    path = VirtualPathUtility.RemoveTrailingSlash(VirtualPathUtility.GetDirectory(path));
    page = pages.Where(model => model.Path.Equals(path, StringComparison.OrdinalIgnoreCase)).SingleOrDefault();
    }

    return page; // return our page or null if no page exists
    }

    return null; // return null if anything fails
    }
  3. 以防万一,如果您尚未创建 MvcHandler,则必须像这样在 RouteConfig 中注册它:

        // default MVC route
    routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    ).RouteHandler = new SkipstoneRouteHandler();
  4. 在我的 MvcHandler 中,我获取我的页面,如果它与我移动到 RoutingController

    的任何虚拟页面匹配
    public ActionResult Index()
    {
    using (var uow = new UnitOfWork<SkipstoneContext>())
    {
    var userId = User.Identity.GetUserId();
    var service = new PageService(uow, this.CompanyId);
    var userService = new UserService(uow, this.CompanyId);
    var user = userService.Get(userId);

    var fileName = service.View(Request.Url, user);

    if (!fileName.StartsWith(@"/") && !fileName.StartsWith("~/"))
    return View(fileName); // Show the page
    else
    return Redirect(fileName); // Redirect to our page
    }
    }

为了您的方便,我将展示service.View 方法

    /// <summary>
/// Views the CMS page
/// </summary>
/// <param name="uri">The current Request.Url</param>
/// <param name="user">The current User</param>
/// <returns>The filename of the requested page</returns>
public string View(Uri uri, User user)
{
var path = uri.AbsolutePath; // Get our Requested Url
var queryString = uri.Query;
var pages = this.GetPublished();
var page = pages.Where(model => model.Path.Equals(path, StringComparison.OrdinalIgnoreCase)).SingleOrDefault(); // Try to get the page

if (page == null) // If our page is null
page = pages.Where(model => model.Path.Equals(VirtualPathUtility.RemoveTrailingSlash(VirtualPathUtility.GetDirectory(path)))).SingleOrDefault(); // try to get the page based off the directory

if (page == null) // If the page is still null, then it doesn't exist
throw new HttpException(404, "This page has been deleted or removed."); // Throw the 404 error

if (page.Restricted && user == null) // If our page is restricted and we are not logged in
return "~/Account/LogOn?ReturnUrl=" + page.Path + queryString; // Redirect to the login page

if (user != null && page.Restricted)
{
if (PageService.IsForbidden(page, user))
throw new HttpException(401, "You do not have permission to view this page."); // Throw 401 error
}

return Path.GetFileNameWithoutExtension(page.Id.ToString());
}
  1. 然后我们被带回我们的 VirtualPathProvider 并且该过程再次开始,但是这次虚拟路径看起来像这样:"~/Views/Routing/1331.aspx"
  2. 如果您注意到,我的 FindPage 方法还会查找我也存储在数据库中的扩展名匹配项:enter image description here
  3. 然后 GetFile 将被调用,只要您遵循我的路径,您应该返回 VirtualFile

我真的希望能有所帮助:)

关于c# - 为什么 MVC 5 不调用我的 VirtualPathProvider 类的 GetFile 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24843728/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com