Приложение, над которым я сейчас работаю, - это приложение MVC3, которое сочетает в себе создание стандартного представления с извлечением представления из базы данных, если физическое представление не существует. Я сталкиваюсь с проблемой с 404 ошибками при реализации собственного контроллеразаводов и virtualpathprovider и не совсем уверен, что я могу делать неправильно.
Нам нужно следующее поведение:
1) если для запроса существует «физическое» представление, обслуживайте его непосредственно из файловой системы (следуйте стандартному поведению mvc). В этом случае на диске будет стандартный контроллер / просмотр.
2) если контроллер / представление не существует, проверьте, хранится ли необходимая информация в базе данных, и отправьте ее из базы данных. Будет вызван контроллер GenericController, который, в свою очередь, получит данные представления из базы данных.
Я создал фабрику пользовательских контроллеров:
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.Items["vc"] = viewcontext;
}
}
}
return returntype;
}
А также пользовательский поставщик виртуальных путей:
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);
}
Поток приложения работает правильно, если запрашивается страница, которая не существует в файловой системе:
1) первый вызов FileExists в virtualpathprovider возвращает false, поэтому IIS не пытается служить статическим файлом.
2) метод GetControllerType в фабрике контроллеров вызывается, и он соответствующим образом возвращает мой тип genericcontroller.
3) метод FileExists вызывается снова и на этот раз возвращает true.
4) Вызываются все методы фабрики контроллеров, включая метод ControllerRelease.
Однако GenericController фактически никогда не вызывается. И IIS возвращает исключение 404.
Есть ли где-то еще в конвейере создания экземпляра контроллера MVC, что мне нужно для захвата запроса MVC? Есть ли лучший способ для меня выполнить то, что я пытаюсь сделать?
Спасибо.