Load Razor view from db, but ViewBag is broken

2019-01-24 16:51发布

问题:

I'm pulling a razor view's markup from the database, as detailed in this question:

ASP.NET MVC load Razor view from database

I can pull the view, but it fails on execution because ViewBag is not recognized.

CS0103: The name 'ViewBag' does not exist in the current context

Any suggestions?

Here's the source:

global:

protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(new BearForce.Web.Core.DbPathProvider());
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }

my path provider:

namespace BearForce.Web.Core
{
    public class DbPathProvider : VirtualPathProvider
    {
        public DbPathProvider()
            : base()
        {

        }

        public override bool FileExists(string virtualPath)
        {
            var repo = new Repository();

            var viewPage = repo.GetView(240, virtualPath);

            if (base.FileExists(virtualPath))
            {
                return true;
            }

            if (viewPage != null)
            {
                return true;
            }

            return false;

        }

        public override VirtualFile GetFile(string virtualPath)
        {
            if (base.FileExists(virtualPath))
            {
                return base.GetFile(virtualPath);
            }

            var repo = new Repository();
            var result = repo.GetView(240, virtualPath);

            var vf = new DbVirtualFile(virtualPath, result.Markup);
            return vf;
        }


    }
}

my Virtual File:

  public class DbVirtualFile : System.Web.Hosting.VirtualFile
    {
        string _fileContents = string.Empty;
        public DbVirtualFile(string path, string fileContents)
            : base(path)
        {
            _fileContents = fileContents;
         }

        public override System.IO.Stream Open()
        {
            return new System.IO.MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(_fileContents));
        }
    }

My Controller:

  public ActionResult Index()
        {
            ViewBag.Title = "aaah!!! Muppets!!! Help!!!!!";

            return View();
        }

Obviously, this is a proof of concept, so the names are all silly and the code sloppy as hell...

回答1:

You should make sure that the view you are returning corresponds to a razor view. Here's a simplified working example:

public class CustomPathProvider : VirtualPathProvider
{
    private class CustomVirtualFile : VirtualFile
    {
        public CustomVirtualFile(string path)
            : base(path)
        { }

        public override Stream Open()
        {
            return new MemoryStream(Encoding.UTF8.GetBytes("Hello @ViewBag.Name"));
        }
    }

    public override bool FileExists(string virtualPath)
    {
        // This is very important: make sure that here you 
        // are returning true only for Razor view pages or
        // you won't have ViewBag.
        // In this oversimplified example we support
        // the index view for the home controller
        return virtualPath == "/Views/Home/Index.cshtml";
    }

    public override VirtualFile GetFile(string virtualPath)
    {
        return new CustomVirtualFile(virtualPath);
    }
}

which would be registered in Application_Start:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
    HostingEnvironment.RegisterVirtualPathProvider(new CustomPathProvider());
}

and finally a sample controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewBag.Name = "John";
        return View();
    }
}

And a final very important remark if you are implementing a custom VirtualPathProvider:

This doesn't work if your web application is precompiled. So if you are using precompilation (things like Publish... or Web Deployment Projects) your custom virtual path provider will never be used.



回答2:

For future people who get this error, you can get this exact error if your web.config files are missing from your Views and your root project folder.