VirtualPathProvider类,提供了一组方法,使 Web 应用程序可以从虚拟文件系统中检索资源。
参见MSDN:http://msdn.microsoft.com/zh-cn/library/system.web.hosting.virtualpathprovider.aspx
遇到这样一个需求,要将.ascx作为嵌入资源放到一个Library项目中,在Web App中需要可以使用。
上网查找后发现,VirtualPathProvider类可以实现这个目的。
步骤一:
通过继承VirtualPathProvider类,实现自己的AssemblyResourceVirtualPathProvider,用来为Assembly中的Resource提供支持。
VirtualPathProvider代码
public class AssemblyResourceVirtualPathProvider : System.Web.Hosting.VirtualPathProvider
{
/// <summary>
/// AssemblyPath与VirtualPath映射
/// </summary>
private string _VirtualPath;
private string _AssemblyPath;
private string VirtualPath { get { return _VirtualPath; } }
private string AssemblyPath { get { return _AssemblyPath; } }
public AssemblyResourceVirtualPathProvider(string virtualPath, string assemblyPath)
{
_VirtualPath = "~/" + virtualPath;
_AssemblyPath = assemblyPath;
}
/// <summary>
/// 是否是AssemblyResource类型的VirtualPath
/// </summary>
/// <param name="virtualPath">virtualPath</param>
/// <returns></returns>
private bool IsAssemblyResourceVirtualPath(string virtualPath)
{
string path = VirtualPathUtility.ToAppRelative(virtualPath);
return path.StartsWith(VirtualPath, StringComparison.InvariantCultureIgnoreCase);
}
/// <summary>
/// 获取virtualPath对应Assembly内的ResourceName
/// </summary>
/// <param name="virtualPath">virtualPath</param>
/// <returns></returns>
private string GetResourceName(string virtualPath)
{
return VirtualPathUtility.GetFileName(virtualPath);
}
#region override
/// <summary>
/// 获取VirtualFile
/// </summary>
/// <param name="virtualPath"></param>
/// <returns></returns>
public override VirtualFile GetFile(string virtualPath)
{
if (IsAssemblyResourceVirtualPath(virtualPath))
{
string resourceName = this.GetResourceName(virtualPath);
return new AssemblyResourceVirtualFile(virtualPath, AssemblyPath, resourceName);
}
else
{
return Previous.GetFile(virtualPath);
}
}
/// <summary>
/// virtualPath指定的文件是否存在。
/// </summary>
/// <param name="virtualPath"></param>
/// <returns></returns>
public override bool FileExists(string virtualPath)
{
if (IsAssemblyResourceVirtualPath(virtualPath))
{
//return true;
Assembly assembly = Assembly.LoadFrom(AssemblyPath);
if (assembly != null)
{
string resourceName = this.GetResourceName(virtualPath);
return (assembly.GetManifestResourceInfo(resourceName) != null);
}
return false;
}
else
{
return Previous.FileExists(virtualPath);
}
}
public override bool DirectoryExists(string virtualDir)
{
if (IsAssemblyResourceVirtualPath(virtualDir))
{
return true;
}
else
{
return Previous.DirectoryExists(virtualDir);
}
}
public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)
{
return null;
//HashCodeCombiner combiner = new HashCodeCombiner();
//foreach (string str in virtualPathDependencies)
//{
// string fileName = HostingEnvironment.MapPathInternal(str);
// combiner.AddFile(fileName);
//}
//return combiner.CombinedHashString;
}
public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
{
return null;
//System.Collections.Specialized.StringCollection fullPathDependencies = null;
//// Get the full path to all dependencies.
//foreach (string virtualDependency in virtualPathDependencies)
//{
// if (fullPathDependencies == null)
// fullPathDependencies = new System.Collections.Specialized.StringCollection();
// fullPathDependencies.Add(virtualDependency);
//}
//if (fullPathDependencies == null)
// return null;
//// Copy the list of full-path dependencies into an array.
//string[] fullPathDependenciesArray = new string[fullPathDependencies.Count];
//fullPathDependencies.CopyTo(fullPathDependenciesArray, 0);
//// Copy the virtual path into an array.
//string[] virtualPathArray = new string[1];
//virtualPathArray[0] = virtualPath;
//return new CacheDependency(virtualPathArray, fullPathDependenciesArray, utcStart);
}
//public override string CombineVirtualPaths(string basePath, string relativePath)
//{
// if (IsAssemblyResourceVirtualPath(basePath))
// {
// return null;
// }
// else
// {
// return Previous.CombineVirtualPaths(basePath, relativePath);
// }
//}
//public override System.Runtime.Remoting.ObjRef CreateObjRef(Type requestedType)
//{
// return Previous.CreateObjRef(requestedType);
//}
//public override string GetCacheKey(string virtualPath)
//{
// if (IsAssemblyResourceVirtualPath(virtualPath))
// {
// return null;
// }
// else
// {
// return Previous.GetCacheKey(virtualPath);
// }
//}
#endregion
}
public class AssemblyResourceVirtualPathProvider : System.Web.Hosting.VirtualPathProvider
{
/// <summary>
/// AssemblyPath与VirtualPath映射
/// </summary>
private string _VirtualPath;
private string _AssemblyPath;
private string VirtualPath { get { return _VirtualPath; } }
private string AssemblyPath { get { return _AssemblyPath; } }
public AssemblyResourceVirtualPathProvider(string virtualPath, string assemblyPath)
{
_VirtualPath = "~/" + virtualPath;
_AssemblyPath = assemblyPath;
}
/// <summary>
/// 是否是AssemblyResource类型的VirtualPath
/// </summary>
/// <param name="virtualPath">virtualPath</param>
/// <returns></returns>
private bool IsAssemblyResourceVirtualPath(string virtualPath)
{
string path = VirtualPathUtility.ToAppRelative(virtualPath);
return path.StartsWith(VirtualPath, StringComparison.InvariantCultureIgnoreCase);
}
/// <summary>
/// 获取virtualPath对应Assembly内的ResourceName
/// </summary>
/// <param name="virtualPath">virtualPath</param>
/// <returns></returns>
private string GetResourceName(string virtualPath)
{
return VirtualPathUtility.GetFileName(virtualPath);
}
#region override
/// <summary>
/// 获取VirtualFile
/// </summary>
/// <param name="virtualPath"></param>
/// <returns></returns>
public override VirtualFile GetFile(string virtualPath)
{
if (IsAssemblyResourceVirtualPath(virtualPath))
{
string resourceName = this.GetResourceName(virtualPath);
return new AssemblyResourceVirtualFile(virtualPath, AssemblyPath, resourceName);
}
else
{
return Previous.GetFile(virtualPath);
}
}
/// <summary>
/// virtualPath指定的文件是否存在。
/// </summary>
/// <param name="virtualPath"></param>
/// <returns></returns>
public override bool FileExists(string virtualPath)
{
if (IsAssemblyResourceVirtualPath(virtualPath))
{
//return true;
Assembly assembly = Assembly.LoadFrom(AssemblyPath);
if (assembly != null)
{
string resourceName = this.GetResourceName(virtualPath);
return (assembly.GetManifestResourceInfo(resourceName) != null);
}
return false;
}
else
{
return Previous.FileExists(virtualPath);
}
}
public override bool DirectoryExists(string virtualDir)
{
if (IsAssemblyResourceVirtualPath(virtualDir))
{
return true;
}
else
{
return Previous.DirectoryExists(virtualDir);
}
}
public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)
{
return null;
//HashCodeCombiner combiner = new HashCodeCombiner();
//foreach (string str in virtualPathDependencies)
//{
// string fileName = HostingEnvironment.MapPathInternal(str);
// combiner.AddFile(fileName);
//}
//return combiner.CombinedHashString;
}
public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
{
return null;
//System.Collections.Specialized.StringCollection fullPathDependencies = null;
//// Get the full path to all dependencies.
//foreach (string virtualDependency in virtualPathDependencies)
//{
// if (fullPathDependencies == null)
// fullPathDependencies = new System.Collections.Specialized.StringCollection();
// fullPathDependencies.Add(virtualDependency);
//}
//if (fullPathDependencies == null)
// return null;
//// Copy the list of full-path dependencies into an array.
//string[] fullPathDependenciesArray = new string[fullPathDependencies.Count];
//fullPathDependencies.CopyTo(fullPathDependenciesArray, 0);
//// Copy the virtual path into an array.
//string[] virtualPathArray = new string[1];
//virtualPathArray[0] = virtualPath;
//return new CacheDependency(virtualPathArray, fullPathDependenciesArray, utcStart);
}
//public override string CombineVirtualPaths(string basePath, string relativePath)
//{
// if (IsAssemblyResourceVirtualPath(basePath))
// {
// return null;
// }
// else
// {
// return Previous.CombineVirtualPaths(basePath, relativePath);
// }
//}
//public override System.Runtime.Remoting.ObjRef CreateObjRef(Type requestedType)
//{
// return Previous.CreateObjRef(requestedType);
//}
//public override string GetCacheKey(string virtualPath)
//{
// if (IsAssemblyResourceVirtualPath(virtualPath))
// {
// return null;
// }
// else
// {
// return Previous.GetCacheKey(virtualPath);
// }
//}
#endregion
}
步骤二:
通过继承VirtualFile类,实现AssemblyResourceVirtualPathProvider的AssemblyResourceVirtualFile,用来提供Resource的Open。
VirtualFile代码
public class AssemblyResourceVirtualFile : VirtualFile
{
private string AssemblyPath;
private string ResourceName;
public AssemblyResourceVirtualFile(string virtualPath, string assemblyPath, string resourceName)
: base(virtualPath)
{
AssemblyPath = assemblyPath;// Path.Combine(HttpRuntime.BinDirectory, assemblyPath);
ResourceName = resourceName;
}
public override System.IO.Stream Open()
{
Assembly assembly = Assembly.LoadFrom(AssemblyPath);
if (assembly != null)
{
return assembly.GetManifestResourceStream(ResourceName);
}
return null;
}
}
{
private string AssemblyPath;
private string ResourceName;
public AssemblyResourceVirtualFile(string virtualPath, string assemblyPath, string resourceName)
: base(virtualPath)
{
AssemblyPath = assemblyPath;// Path.Combine(HttpRuntime.BinDirectory, assemblyPath);
ResourceName = resourceName;
}
public override System.IO.Stream Open()
{
Assembly assembly = Assembly.LoadFrom(AssemblyPath);
if (assembly != null)
{
return assembly.GetManifestResourceStream(ResourceName);
}
return null;
}
}
步骤三:
在Global.asax中注册VirtualPathProvider。
Global代码
protected void Application_Start(object sender, EventArgs e)
{
string assemblyPath = "WebControlLibrary.dll";
assemblyPath = Path.Combine(HttpRuntime.BinDirectory, assemblyPath);
AssemblyResourceVirtualPathProvider provider = new AssemblyResourceVirtualPathProvider("WebControlDemo", assemblyPath);
//按链表方式链接注册的VirtualPathProvider。
HostingEnvironment.RegisterVirtualPathProvider(provider);
}
protected void Application_Start(object sender, EventArgs e)
{
string assemblyPath = "WebControlLibrary.dll";
assemblyPath = Path.Combine(HttpRuntime.BinDirectory, assemblyPath);
AssemblyResourceVirtualPathProvider provider = new AssemblyResourceVirtualPathProvider("WebControlDemo", assemblyPath);
//按链表方式链接注册的VirtualPathProvider。
HostingEnvironment.RegisterVirtualPathProvider(provider);
}
步骤四:
创建Library项目,添加Web User Control,将.ascx文件为嵌入资源。
步骤五:
在Web App的页面中使用Web User Control。
Page代码
protected override void OnInit(EventArgs e)
{
//LoadControl中获取对程序集内资源
//当然,可以在aspx中使用:
//<%@ Register Src="WebControlDemo/WebControlLibrary.WebUserControl.ascx" TagName="WebUserControl" TagPrefix="uc1" %>
//<uc1:WebUserControl id="WebUserControl1_1" runat="server"/>
WebUserControl1 = this.LoadControl("WebControlDemo/WebControlLibrary.WebUserControl.ascx") as WebUserControl;
SubWebUserControl1 = this.LoadControl("WebControlDemo/WebControlLibrary.SubDirectory.SubWebUserControl.ascx") as SubWebUserControl;
this.form1.Controls.Add(WebUserControl1);
this.form1.Controls.Add(SubWebUserControl1);
base.OnInit(e);
}
{
//LoadControl中获取对程序集内资源
//当然,可以在aspx中使用:
//<%@ Register Src="WebControlDemo/WebControlLibrary.WebUserControl.ascx" TagName="WebUserControl" TagPrefix="uc1" %>
//<uc1:WebUserControl id="WebUserControl1_1" runat="server"/>
WebUserControl1 = this.LoadControl("WebControlDemo/WebControlLibrary.WebUserControl.ascx") as WebUserControl;
SubWebUserControl1 = this.LoadControl("WebControlDemo/WebControlLibrary.SubDirectory.SubWebUserControl.ascx") as SubWebUserControl;
this.form1.Controls.Add(WebUserControl1);
this.form1.Controls.Add(SubWebUserControl1);
base.OnInit(e);
}
结束语:
通过嵌入资源的联想,可以将JS文件作为嵌入资源,同样可以通过VirtualPathProvider提供访问支持。
JS嵌入资源
//获取对程序集内资源的 URL 引用 的 虚拟路径方法
//当然,可以在aspx中使用:<script language="javascript" src="WebControlDemo/WebControlLibrary.VirtualPathProvider.js"></script>
if (!this.ClientScript.IsClientScriptIncludeRegistered(GetType(), "JS By VirtualPathProvider"))
{
string webUrl = "WebControlDemo/WebControlLibrary.VirtualPathProvider.js";
this.ClientScript.RegisterClientScriptInclude(GetType(), "JS By VirtualPathProvider", webUrl);
}
//获取对程序集内资源的 URL 引用 的 一般方法
if (!this.ClientScript.IsClientScriptIncludeRegistered(GetType(), "JS By WebResourceUrl"))
{
string webUrl = Page.ClientScript.GetWebResourceUrl(new WebUserControl().GetType(), "WebControlLibrary.WebResourceUrl.js");
this.ClientScript.RegisterClientScriptInclude(GetType(), "JS By WebResourceUrl", webUrl);
}
//当然,可以在aspx中使用:<script language="javascript" src="WebControlDemo/WebControlLibrary.VirtualPathProvider.js"></script>
if (!this.ClientScript.IsClientScriptIncludeRegistered(GetType(), "JS By VirtualPathProvider"))
{
string webUrl = "WebControlDemo/WebControlLibrary.VirtualPathProvider.js";
this.ClientScript.RegisterClientScriptInclude(GetType(), "JS By VirtualPathProvider", webUrl);
}
//获取对程序集内资源的 URL 引用 的 一般方法
if (!this.ClientScript.IsClientScriptIncludeRegistered(GetType(), "JS By WebResourceUrl"))
{
string webUrl = Page.ClientScript.GetWebResourceUrl(new WebUserControl().GetType(), "WebControlLibrary.WebResourceUrl.js");
this.ClientScript.RegisterClientScriptInclude(GetType(), "JS By WebResourceUrl", webUrl);
}