我正在研究一个包含多个带有控制器和视图的项目的解决方案。使用VirtualPathProvider加载视图的时间过长。我现在正在尝试使用RazorViewEngine的不同方法。但是我仍然得到:找不到“索引”视图或其主视图,或者没有视图引擎支持搜索到的位置。
已经存在的是: EmbeddedVirtualPathProvider
// source: http://www.ianmariano.com/2013/06/11/embedded-razor-views-in-mvc-4/
internal sealed class EmbeddedVirtualPathProvider : VirtualPathProvider
{
private readonly Type _type;
private readonly ConcurrentDictionary<string, string> _embededResources = new ConcurrentDictionary<string, string>();
private readonly DateTime _modified;
public EmbeddedVirtualPathProvider()
{
_type = GetType();
_modified = File.GetCreationTime(_type.Assembly.Location);
}
public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
{
string embedded = GetCachedEmbeddedPath(virtualPath);
// not embedded? fall back
if (string.IsNullOrEmpty(embedded)) return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
// there is no cache dependency for embedded resources
return null;
}
public override bool FileExists(string virtualPath)
{
string embedded = GetCachedEmbeddedPath(virtualPath);
// You can override the embed by placing a real file
// at the virtual path...
return base.FileExists(virtualPath) || !string.IsNullOrEmpty(embedded);
}
public override VirtualFile GetFile(string virtualPath)
{
// You can override the embed by placing a real file
// at the virtual path...
if (base.FileExists(virtualPath))
return base.GetFile(virtualPath);
string embedded = GetCachedEmbeddedPath(virtualPath);
// sanity...
return !string.IsNullOrEmpty(embedded)
? new EmbeddedVirtualFile(virtualPath, _type.Assembly.GetManifestResourceStream(embedded), _modified)
: null;
}
private string GetCachedEmbeddedPath(string path)
{
return _embededResources.GetOrAdd(path, GetEmbeddedPath);
}
private string GetEmbeddedPath(string path)
{
if (path.StartsWith("~/")) path = path.Substring(1);
string directory = VirtualPathUtility.GetDirectory(path);
string file = VirtualPathUtility.GetFileName(path);
string[] resourcePath = directory.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < resourcePath.Length; i++)
{
resourcePath[i] = StronglyTypedResourceBuilder.VerifyResourceName(resourcePath[i], new CSharpCodeProvider());
}
path = string.Concat(_type.Namespace, ".", string.Join(".", resourcePath), ".", file);
// this makes sure the "virtual path" exists as an embedded resource;
return _type.Assembly.GetManifestResourceNames().FirstOrDefault(s => s.Equals(path, StringComparison.OrdinalIgnoreCase));
}
}
EmbeddedVirtualFile:
internal sealed class EmbeddedVirtualFile : VirtualFile
{
private readonly Stream _stream;
private readonly DateTime _modified;
public EmbeddedVirtualFile(string virtualPath, Stream stream, DateTime modified)
: base(virtualPath)
{
if (null == stream) throw new ArgumentNullException("stream");
_stream = stream;
_modified = modified;
}
public override Stream Open()
{
// hack (http://stackoverflow.com/questions/8224075/maintaining-cache-control-property-on-a-file-when-it-is-returned-as-stream-from)
if (VirtualPath.Equals(HttpContext.Current.Request.RawUrl, StringComparison.OrdinalIgnoreCase))
{
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.Public);
HttpContext.Current.Response.Cache.SetMaxAge(TimeSpan.FromMinutes(30));
HttpContext.Current.Response.Cache.SetLastModified(_modified);
}
return _stream;
}
}
从PreApplicationStartCode类初始化虚拟路径提供程序。
PreApplicationStartCode:
public class PreApplicationStartCode
{
private static bool isStarting;
public static void Start()
{
if (isStarting) return;
isStarting = true;
// Fix for precompiled website: http://stackoverflow.com/questions/7527571/virtualpathprovider-not-working-on-hosting-environment
if (!BuildManager.IsPrecompiledApp)
{
HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedVirtualPathProvider());
return;
}
// We get the current instance of HostingEnvironment class. We can't create a new because
// it is not allowed to do so. An AppDomain can only have one HostingEnvironment instance.
EmbeddedVirtualPathProvider providerInstance = new EmbeddedVirtualPathProvider();
HostingEnvironment hostingEnvironmentInstance = (HostingEnvironment)typeof(HostingEnvironment).InvokeMember("_theHostingEnvironment", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField, null, null, null);
if (hostingEnvironmentInstance == null)
return;
// We get the MethodInfo for RegisterVirtualPathProviderInternal method which is internal and also static.
MethodInfo mi = typeof(HostingEnvironment).GetMethod("RegisterVirtualPathProviderInternal", BindingFlags.NonPublic | BindingFlags.Static);
if (mi == null)
return;
// finally we invoke RegisterVirtualPathProviderInternal method with one argument which
// is the instance of our own VirtualPathProvider.
mi.Invoke(hostingEnvironmentInstance, new object[] { providerInstance });
}
}
这有效,但是再次启动/调试花费的时间太长。在Controller已经完成运行之后,需要花费一分钟多的时间来加载视图。
我现在要开始工作的是:
public class MultiProjectRazorViewEngine : RazorViewEngine
{
private readonly string[] _areaMasterLocationFormats = new[]
{
"~/Areas/{2}/Views/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.cshtml",
"~/Views/{0}.cshtml",
"~/Views/Shared/{0}.cshtml"
};
private readonly string[] _areaViewLocationFormats = new[]
{
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{1}/{0}.cshtml"
};
private readonly string[] _areaPartialViewLocationFormats = new[]
{
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{1}/{0}.cshtml"
};
private readonly string[] _masterLocationFormats = new[]
{
"~/Views/{0}.cshtml",
"~/Views/Shared/{0}.cshtml"
};
private readonly string[] _viewLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{1}/{0}.cshtml"
};
private readonly string[] _partialViewLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{1}/{0}.cshtml"
};
public MultiProjectRazorViewEngine()
{
AreaMasterLocationFormats = _areaMasterLocationFormats;
AreaViewLocationFormats = _areaViewLocationFormats;
AreaPartialViewLocationFormats = _areaPartialViewLocationFormats;
MasterLocationFormats = _masterLocationFormats;
ViewLocationFormats = _viewLocationFormats;
PartialViewLocationFormats = _partialViewLocationFormats;
}
}
仅在正确的位置检查.cshtml文件(HomeController.Index被查找为:“〜/ Views / Home / Index.cshtml”)是正确的。但是,它没有从启动项目中找到Base项目中的控制器和/或视图。我不知道为什么会这样。似乎在我的启动项目中找不到引用的基础项目视图/控制器。有人可以告诉我为什么吗?
所以我要实现的是一个快速启动的应用程序,在控制器完成运行之后,它不需要1分钟的时间即可加载所有视图。我还不完全了解视图的位置,因此我不确定从哪里开始。 Google搜索尚无定论,而且似乎已经过时。
(但是我可能会经常看错东西……)