MVC ViewPathProvider,数据库视图和布局

时间:2012-06-27 12:27:57

标签: asp.net-mvc

我正在尝试使用MVC框架创建CMS。 一切顺利,我创建了我的表来存储我的ViewData,ViewTitle和virtualPath。 我使用VirthPathProvider,它看起来像这样:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Hosting;
using CMS;
using System.Collections.ObjectModel;
using CMS.Components;
using System.Web;

namespace CMS.Providers
{
    public class PageVirtualPathProvider : VirtualPathProvider
    {
        private Directory current { get; set; }
        private Collection<Directory> directories { get; set; }
        private Collection<BasePage> pages { get; set; }

        public override bool FileExists(string virtualPath)
        {
            string Path = (VirtualPathUtility.GetDirectory(virtualPath) != "~/") ? VirtualPathUtility.RemoveTrailingSlash(VirtualPathUtility.GetDirectory(virtualPath)) : VirtualPathUtility.GetDirectory(virtualPath);
            if (IsVirtualPath(Path))
            {
                BasePage oPage = FindPage(virtualPath);
                if (oPage != null) 
                    return true;
            }

            bool bExists = base.FileExists(virtualPath);
            return bExists;
        }

        public override VirtualFile GetFile(string virtualPath)
        {
            string Path = (VirtualPathUtility.GetDirectory(virtualPath) != "~/") ? VirtualPathUtility.RemoveTrailingSlash(VirtualPathUtility.GetDirectory(virtualPath)) : VirtualPathUtility.GetDirectory(virtualPath);
            if (IsVirtualPath(Path))
            {
                BasePage oPage = FindPage(virtualPath);
                if (oPage != null) 
                    return new PageVirtualFile(virtualPath, oPage.ViewData.ToArray());
            }

            return base.GetFile(virtualPath);
        }

        public override bool DirectoryExists(string virtualDir)
        {
            if (IsVirtualPath(virtualDir))
            {
                if (current != null)
                {
                    if (current.Path.ToLower() != virtualDir.ToLower())
                        current = new Directory(virtualDir, "53AF0033-4011-4C8F-A14D-7CE9301E264D");
                }
                else
                {
                    current = new Directory(virtualDir, "53AF0033-4011-4C8F-A14D-7CE9301E264D");
                }
                if (current != null)
                    return true;
            }

            return base.DirectoryExists(virtualDir);
        }

        public override VirtualDirectory GetDirectory(string virtualDir)
        {
            if (IsVirtualPath(virtualDir))
            {
                if (current != null)
                {
                    if (current.Path.ToLower() != virtualDir.ToLower())
                        current = new Directory(virtualDir, "53AF0033-4011-4C8F-A14D-7CE9301E264D");
                }
                else
                {
                    current = new Directory(virtualDir, "53AF0033-4011-4C8F-A14D-7CE9301E264D");
                }
                if (current != null)
                    return new CmsVirtualDirectory(virtualDir, "53AF0033-4011-4C8F-A14D-7CE9301E264D");
            }

            return base.GetDirectory(virtualDir);
        }

        public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
        {
            string Path = (VirtualPathUtility.GetDirectory(virtualPath) != "~/") ? VirtualPathUtility.RemoveTrailingSlash(VirtualPathUtility.GetDirectory(virtualPath)) : VirtualPathUtility.GetDirectory(virtualPath);
            if (IsVirtualPath(Path)) 
                return null;

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

        public override string GetFileHash(string virtualPath, System.Collections.IEnumerable virtualPathDependencies)
        {
            string Path = (VirtualPathUtility.GetDirectory(virtualPath) != "~/") ? VirtualPathUtility.RemoveTrailingSlash(VirtualPathUtility.GetDirectory(virtualPath)) : VirtualPathUtility.GetDirectory(virtualPath);
            if (IsVirtualPath(Path))
                return Guid.NewGuid().ToString();

            return base.GetFileHash(virtualPath, virtualPathDependencies);
        }

        private BasePage FindPage(string virtualPath)
        {
            string VirtualName = VirtualPathUtility.GetFileName(virtualPath).ToLower();
            if (pages == null)
            {
                pages = PageManager.getAllPages("53AF0033-4011-4C8F-A14D-7CE9301E264D", false);
            }
            BasePage oPage = pages.SingleOrDefault(page => page.Path.ToLower() == VirtualName);
            return oPage;
        }

        private bool IsVirtualPath(string virtualPath)
        {
            string Path = VirtualPathUtility.ToAppRelative(virtualPath);
            if (directories == null)
            {
                directories = DirectoryManager.GetAllDirectories("53AF0033-4011-4C8F-A14D-7CE9301E264D");
            }
            Directory oDir = directories.SingleOrDefault(dir => dir.Path.ToLower() == Path.ToLower());

            if (oDir == null || virtualPath == "~/") return false; // If we don't have directory, return false
            return true; // Hit only if we are null
        }
    }
}

现在我的问题是: 获取页面很好,当它们是虚拟的时候,它返回null作为Cache,而FileHash总是一个不同的字符串,因此调用GetFile。 我的文件被返回,但它永远找不到布局。

我相信这是因为没有_ViewStart.cshtml因为没有视图目录....所以如何强制它使用布局? 我尝试了很多东西,比如让我的虚拟页面继承自@inherits System.Web.Mvc.WebViewPage等,但我仍然遇到同样的问题....

当我导航到虚拟页面时,我收到此错误: 无法投射类型&#39; ASP._Page_Guidelines_index_cshtml&#39;输入&#39; System.Web.IHttpHandler&#39;。

请帮帮我;我已经坚持了3个星期....

1 个答案:

答案 0 :(得分:4)

如果有其他人遇到此问题。我确实解决了。这是我的完整代码:) 首先,创建我们的RouteHandler

public class CmsRouteHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new CmsHandler(requestContext); // Return the requestContext and handle as normal
    }
}

然后我们需要创建我们的MvcHanlder

class CmsHandler : MvcHandler, IRequiresSessionState
{    
    public CmsHandler(RequestContext requestContext)
        : base(requestContext)
    {
    }

    protected override IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state)
    {
        return base.BeginProcessRequest(httpContext, callback, state);
    }


    protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
    {
        try
        {
            // If we are using a company Url, then the session should not be null
            if (CompanyProvider.CurrentCompanyId() != null)
            {
                var vpp = new CmsVirtualPathProvider(); // Create an instance of our VirtualPathProvider class
                var requestContext = ((MvcHandler)httpContext.Handler).RequestContext; // Get our request context
                string path = requestContext.HttpContext.Request.Url.AbsolutePath; // Get our requested path

                // If we have a path
                if (path != null)
                {
                    Collection<IPage> pages = vpp.pages; // Get all the published pages for this company

                    // If we have pages
                    if (pages != null)
                    {
                        IPage oPage = pages.SingleOrDefault(page => page.Path.ToLower() == path.ToLower()); // Select the page matching our requested path (if any)
                        if (oPage != null) // If we find the page
                        {
                            requestContext.RouteData.Values["controller"] = "_Cms"; // Set the controller
                            requestContext.RouteData.Values["action"] = "Index"; // And the action
                        }
                    }
                }
            }

            return base.BeginProcessRequest(httpContext, callback, state);
        }
        catch (Exception ex)
        {
            log4net.ILog _log = log4net.LogManager.GetLogger(this.GetType());
            _log.Fatal(ex);
            throw new Exception(ex.Message);
        }
    }

    protected override void ProcessRequest(HttpContext httpContext)
    {
        base.ProcessRequest(httpContext);
    }
}

您可以在我的应用程序中看到我有一个companyId,因为我正在为多家公司使用子域名,但在正常情况下不需要。

完整的VirtualPathProvider如下所示:

public class CmsVirtualPathProvider : VirtualPathProvider
{
    public Collection<IPage> pages 
    { 
        get 
        {
            if (HttpContext.Current.Session != null)
            {
                return PageProvider.GetPublishedPages(CompanyProvider.CurrentCompanyId(), true);
            }
            else
                return null;
        } 
    }

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

        return Previous.FileExists(virtualPath);
    }

    public override VirtualFile GetFile(string virtualPath)
    {
        if (IsVirtualPath(virtualPath))
        {
            IPage oPage = FindPage(virtualPath);
            if (oPage != null)
                return new PageVirtualFile(virtualPath, oPage.ViewData);
        }

        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 IPage FindPage(string virtualPath)
    {
        string VirtualName = VirtualPathUtility.GetFileName(virtualPath).ToLower();

        if (pages != null)
        {
            IPage oPage = pages.SingleOrDefault(page => page.FileName == VirtualName);
            return oPage;
        }
        else
            return null;
    }

    private bool IsVirtualPath(string virtualPath)
    {
        string Path = (VirtualPathUtility.GetDirectory(virtualPath) != "~/") ? VirtualPathUtility.RemoveTrailingSlash(VirtualPathUtility.GetDirectory(virtualPath)) : VirtualPathUtility.GetDirectory(virtualPath);
        if (Path.StartsWith("/Views/_Cms", StringComparison.InvariantCultureIgnoreCase))
            return true;
        else
            return false;
    }
}

现在您只需要一个控制器来处理所有页面请求。我看起来像这样:

public class _CmsController : Controller
{
    private Collection<IPage> pages { get; set; }

    public ActionResult Index()
    {
        string uri = Request.Url.AbsolutePath; // Get our Requested Url
        string queryString = Request.Url.Query;
        Profile currentUser = ProfileProvider.CurrentUser(); // Get our current user if we have one

        if (pages == null) // If pages is null
            pages = PageProvider.GetPublishedPages(CompanyProvider.CurrentCompanyId(), true); // Get our published pages

        IPage page = pages.SingleOrDefault(p => p.Path.ToLower() == uri.ToLower()); // Get the current page

        if (page == null) // If our page is null
            throw new HttpException(404, "Are you sure this page exists?"); // Throw the 404 error

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

        if (currentUser != null)
        {
            IPage oForbidden = currentUser.GetForbiddenPages().SingleOrDefault(p => p.Id == page.Id); // Finds the page in our forbidden pages, if it exists

            if (oForbidden != null) // If we find the forbidden page
                throw new HttpException(401, "You do not have permission to view this page."); // Throw 401 error

            AuditProvider.Create(currentUser, page, Event.View); // Create our audit trail if we get this far
        }

        return View(Path.GetFileNameWithoutExtension(page.Id.ToString())); // Show the page
    }
}

只是因为我感觉很好,这是我的表结构

CREATE TABLE [dbo].[cms_Pages](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [DateCreated] [datetime] NOT NULL,
    [UserId] [uniqueidentifier] NOT NULL,
    [Author] [nvarchar](256) NOT NULL,
    [DateModified] [datetime] NULL,
    [ModifiedById] [uniqueidentifier] NULL,
    [ModifiedBy] [nvarchar](256) NULL,
    [CompanyId] [uniqueidentifier] NOT NULL,
    [Name] [varchar](100) NOT NULL,
    [Description] [text] NULL,
    [FileName] [varchar](255) NULL,
    [Path] [varchar](255) NULL,
    [Link] [varchar](255) NULL,
    [Published] [bit] NOT NULL,
    [TypeId] [int] NOT NULL,
    [Order] [int] NOT NULL,
    [Lineage] [nvarchar](255) NOT NULL,
    [ParentId] [int] NULL,
    [ViewData] [varbinary](max) NULL,
    [ViewTitle] [varchar](255) NULL,
    [Restricted] [bit] NOT NULL,
 CONSTRAINT [PK_cg_Pages] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

显然,你不需要companyId :) 这里是一个表格中包含的数据

enter image description here

我使用这行代码将页面的html转换为字节:

ASCIIEncoding encoding = new ASCIIEncoding();
var decodedContent = HttpUtility.UrlDecode(Content, Encoding.Default);
Byte[] bytes = encoding.GetBytes(decodedContent);

如果您在将HTML提交到保存功能之前转义HTML,则只需要UrlDecode。如果你不是那么你可以使用:

ASCIIEncoding encoding = new ASCIIEncoding();
Byte[] bytes = encoding.GetBytes(Content);

我真的希望这可以帮助别人。我正试图解决这个问题:)

欢呼声, r3plica