我设法让它工作。
对于那些感兴趣的人,请执行以下操作(我假设您从现在开始有一个常规的 ASP.NET MVC 项目 -A - 并且在同一个解决方案中还有一个单独的类库项目 - 让我们调用它B-):
- 在 B 中创建资源文件(我在示例中使用了名称 Views.resx)。
- 将您的视图作为常规文本文件添加到该资源文件。请注意,您不会有 Intellisense。您可以在 A 中创建视图并将它们复制/粘贴到 B 中以便于开发。此外,您应该为在那里创建的资源选择一个命名策略(在获取视图内容时需要它;在本示例中,我使用
CONTROLLER_VIEW 作为命名模式)。另一个注意事项:添加到资源文件的视图中的特殊字符将不会正确显示,除非您将它们替换为相应的 HTML 实体。
- 在 B 中实现以下类:
public class ResourceVirtualFile : VirtualFile
{
private byte[] _content;
public byte[] Content
{
get { return _content; }
}
public ResourceVirtualFile(string virtualPath, byte[] content)
: base(virtualPath)
{
_content = content;
}
public override Stream Open()
{
return new MemoryStream(_content);
}
}
public class ResourceVirtualPathProvider : VirtualPathProvider
{
private static Dictionary<string, string> _resource_entries;
private static Regex _virtual_path_regex;
static ResourceVirtualPathProvider()
{
_resource_entries = Views
.ResourceManager
.GetResourceSet(CultureInfo.InvariantCulture, true, true)
.OfType<DictionaryEntry>()
.ToDictionary(d => d.Key as string, d => d.Value as string);
_virtual_path_regex = new Regex(@"~{0,1}\/Views\/(?'controller'[\w]+)\/(?'view'[\w]+)\.cshtml$");
}
public override bool FileExists(string virtualPath)
{
var view_exists = CheckViewExistsInResource(virtualPath);
if (view_exists)
{
return true;
}
return base.FileExists(virtualPath);
}
public override VirtualFile GetFile(string virtualPath)
{
var view_content = GetViewFromResource(virtualPath);
if (view_content == null)
{
return base.GetFile(virtualPath);
}
else
{
return new ResourceVirtualFile(virtualPath, view_content);
}
}
public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
{
var view_content = GetViewFromResource(virtualPath);
if (view_content != null)
{
return null;
}
else
{
return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
}
}
private string ProcessVirtualPath(string virtualPath)
{
var match = _virtual_path_regex.Match(virtualPath);
if (!match.Success)
{
return null;
}
var resource_name = string.Format(
"{0}_{1}",
match.Groups["controller"].Value,
match.Groups["view"].Value);
return resource_name;
}
private bool CheckViewExistsInResource(string virtualPath)
{
var resource_name = ProcessVirtualPath(virtualPath);
if (string.IsNullOrEmpty(resource_name))
{
return false;
}
var contains_view = _resource_entries.ContainsKey(resource_name);
return contains_view;
}
private byte[] GetViewFromResource(string virtualPath)
{
var resource_name = ProcessVirtualPath(virtualPath);
if (string.IsNullOrEmpty(resource_name))
{
return null;
}
var contains_view = _resource_entries.ContainsKey(resource_name);
if (!contains_view)
{
return null;
}
var view_content = Views.ResourceManager.GetString(resource_name);
var view_bytes = Encoding.UTF8.GetBytes(view_content);
return view_bytes;
}
}
这些类允许您实现一个路径提供程序,它将 MVC 的路径请求转换为您可以从 B 的资源文件中获取的名称。如果ResourceVirtualPathProvider 无法为您获取视图,它将遵循 A 的常规路径提供者。
- 最后,在A的
Global.asaxApplication_Start方法中注册这个新的路径提供者
HostingEnvironment.RegisterVirtualPathProvider(new ResourceVirtualPathProvider());
你就完成了。在 B 中创建任意数量的视图;只要您尊重命名模式,就会找到并显示视图。