我正在将一些代码从ASPX视图引擎迁移到Razor,而且我遇到了障碍。
我有这段代码:
<link rel="Stylesheet" type="text/css" href="
<%=Page.ClientScript.GetWebResourceUrl
(typeof(DotNetOpenAuth.OpenId.RelyingParty.OpenIdSelector),
"DotNetOpenAuth.OpenId.RelyingParty.OpenIdSelector.css")%>" />
这里的问题是,使用Razor,我没有Page属性。
所以我退后一步,我正在看这个想知道:在Razor中获取嵌入式资源的正确方法是什么?
我花了很多时间试图找到关于这个主题的解决方案,但我还没有找到除了“在帮助者中包装一个新页面”之外的任何其他内容。
这是唯一的方法吗?还是有更正确的东西?
答案 0 :(得分:7)
不幸的是,Web资源与webforms基础架构紧密相关,如果没有它,很难重用它们。所以有点hacky但你可以写一个帮手:
public static class UrlExtensions
{
public static string WebResource(this UrlHelper urlHelper, Type type, string resourcePath)
{
var page = new Page();
return page.ClientScript.GetWebResourceUrl(type, resourcePath);
}
}
并在你的剃须刀视图中:
<link rel="stylesheet" type="text/css" href="@Url.WebResource(typeof(DotNetOpenAuth.OpenId.RelyingParty.OpenIdSelector), "DotNetOpenAuth.OpenId.RelyingParty.OpenIdSelector.css")" />
另一种可能性是编写一个自定义HTTP处理程序/控制器,它将从程序集中读取嵌入的资源,并通过设置正确的内容类型将其传递给响应。
答案 1 :(得分:0)
除了调用new Page()...
之外,您还可以直接调用底层实现。将此代码放在一些静态类中:
public static string GetWebResourceUrl(this Assembly assembly, string name)
{ if (GetWebResourceUrlInternal == null)
GetWebResourceUrlInternal = (Func<Assembly,string,bool,bool,System.Web.UI.ScriptManager,string>)
typeof(System.Web.Handlers.AssemblyResourceLoader)
.GetMethod("GetWebResourceUrlInternal", BindingFlags.NonPublic|BindingFlags.Static, null,
new[]{typeof(Assembly),typeof(string),typeof(bool),typeof(bool),typeof(System.Web.UI.ScriptManager)}, null)
.CreateDelegate(typeof(Func<Assembly,string,bool,bool,System.Web.UI.ScriptManager,string>));
return GetWebResourceUrlInternal(assembly, name, false, false, null);
}
volatile static Func<Assembly,string,bool,bool,System.Web.UI.ScriptManager,string> GetWebResourceUrlInternal = null;
在Razor视图或代码背后使用:
typeof(SomeClassInTheSameAssembly).Assembly.GetWebResourceUrl("Namespace.Resource.xxx")
当然,在Razor视图中使用WebResource URL并不是很有用。相反,建议将资源直接放入MVC应用程序的Content或Scripts文件夹中。
但如果您想在共享类库中编写HtmlHelper
函数,情况会发生变化,而这些函数无法将内容放入目标项目中。
这种方法基本上避免了在Page
的每次调用时创建一个新的,庞大的GetWebResourceUrl
对象。
结果reference source code结果表明,Page
和ScriptManager
上下文只是一无所获。因此,直接调用AssemblyResourceLoader.GetWebResourceUrlInternal
将会击中头部。 您需要创建有效的WebResource.axd网址是大会,当然还有资源名称。
缺点是此函数是内部,因此必须通过反射调用它。但是,上述实现避免了每次通过反射调用函数的开销。相反,CreateDelegate
被用一次来获得一个普通的委托,几乎没有开销就可以调用它。
目标GetWebResourceUrlInternal
访问时的竞争条件。它不会造成任何重大损害,因为在第一次调用时很可能会遇到许多并行线程的代码片段,即使它发生了,结果仍然可靠。