在Razor View上处理嵌入式资源的正确方法是什么?

时间:2011-02-14 19:46:32

标签: asp.net-mvc-3 razor embedded-resource

我正在将一些代码从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中获取嵌入式资源的正确方法是什么?

我花了很多时间试图找到关于这个主题的解决方案,但我还没有找到除了“在帮助者中包装一个新页面”之外的任何其他内容。

这是唯一的方法吗?还是有更正确的东西?

2 个答案:

答案 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结果表明,PageScriptManager上下文只是一无所获。因此,直接调用AssemblyResourceLoader.GetWebResourceUrlInternal将会击中头部。 您需要创建有效的WebResource.axd网址是大会,当然还有资源名称

缺点是此函数是内部,因此必须通过反射调用它。但是,上述实现避免了每次通过反射调用函数的开销。相反,CreateDelegate被用一次来获得一个普通的委托,几乎没有开销就可以调用它。

目标GetWebResourceUrlInternal访问时的竞争条件。它不会造成任何重大损害,因为在第一次调用时很可能会遇到许多并行线程的代码片段,即使它发生了,结果仍然可靠。