asp.mvc 404 Error with Custom ControllerFactory and DBProvider
The app I am currently working on is an MVC3 app that combines standard view instantiation along with retrieving the view from a database if a physical view does not exist. I am running into a problem with 404 errors when implementing a custom controllerfactory and virtualpathprovider and am not quite sure what I may be doing wrong.
The behaviour we want is as follows:
1) if a "physical" view exists for a request, serve it directly from the file system (follow standard mvc behaviour). In this case, there will be the standard controller/view on disk. 2) if the controller/view does not exist, then check to see if the necessary info is stored in the database and serve it from the database. A controller called GenericController will be called and that in turn will get the view data from the database.
I have created a custom controller factory:
public class ControllerFactory : DefaultControllerFactory, IControllerFactory
{
protected override Type GetControllerType(RequestContext requestContext, string controllerName)
{
// check to see if this controller name can be resolved via DI. If it can, then hand this off to the Default factory.
Type returntype = base.GetControllerType(requestContext, controllerName);
// see if this is a type that is handled via the database. If it is, then send to the generic system controller for handling.
if (returntype == null)
{
// already requested?
if (requestContext.HttpContext.Items.Contains("vc"))
{
returntype = typeof(GenericSystemController);
}
else
{
if (viewcanberetrievedfromdb())
{
// TODO: check to see if the account has access to the module.
returntype = typeof(GenericSystemController);
requestContext.HttpContext.Item开发者_运维知识库s["vc"] = viewcontext;
}
}
}
return returntype;
}
As well as a custom virtual path provider:
public class DbPathProvider : VirtualPathProvider
{
public DbPathProvider()
: base()
{
}
public override bool FileExists(string virtualPath)
{
// first see if there is a physical version of the file. If there is, then use that. Otherwise, go to the database.
// database calls are ALWAYS overridden by physical files.
bool physicalFileExists = base.FileExists(virtualPath);
if (!physicalFileExists)
physicalFileExists = HttpContext.Current.Items.Contains("vc");
return physicalFileExists;
}
public override VirtualFile GetFile(string virtualPath)
{
if (base.FileExists(virtualPath))
return base.GetFile(virtualPath);
else
return new DbVirtualFile(virtualPath);
}
The app flow seems to work correctly if a page is requested that does not exist in the file system: 1) first call to FileExists in the virtualpathprovider returns false so that IIS does not try to serve as static file. 2) the GetControllerType method in the controller factory is called and it appropriately returns my genericcontroller type. 3) the FileExists method is called again and this time returns true. 4) all the controller factory methods are called including the ControllerRelease method.
However, the GenericController is actually never called. And IIS returns a 404 exception.
Is there somewhere else in the MVC controller instantiation pipeline that I need to be capturing the MVC request? Is there a better way for me to accomplish what I am trying to accomplish?
Thanks.
精彩评论