What is the right way to handle Embedded Resources on a Razor View?

懵懂的女人 提交于 2019-12-07 02:39:40

问题


I'm migrating some code from the ASPX view engine to Razor and I've run up onto a roadblock.

I have this code:

<link rel="Stylesheet" type="text/css" href="
    <%=Page.ClientScript.GetWebResourceUrl
        (typeof(DotNetOpenAuth.OpenId.RelyingParty.OpenIdSelector), 
        "DotNetOpenAuth.OpenId.RelyingParty.OpenIdSelector.css")%>" />

The problem here is that with Razor, I have no Page property.

So I took a step back for a second, and I'm looking at this wondering: What is the right way to get embedded resources in Razor?

I've spent a good bit of time trying to find solutions on this subject, but I haven't really found anything other than "wrap a new Page in a helper"

Is that the only way to do it? Or is there something more correct?


回答1:


Unfortunately the web resources are quite tied to the webforms infrastructure and it is difficult to reuse them without it. So a bit hacky but you could write a helper:

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);
    }
}

and in your razor view:

<link rel="stylesheet" type="text/css" href="@Url.WebResource(typeof(DotNetOpenAuth.OpenId.RelyingParty.OpenIdSelector), "DotNetOpenAuth.OpenId.RelyingParty.OpenIdSelector.css")" />

Another possibility is to write a custom HTTP handler/controller which will read the embedded resource from the assembly and stream it to the response by setting the proper content type.




回答2:


Beside invoking new Page()... you can directly call the underlying implementation. Place this code in some static class:

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;

And in the Razor view or code behind use:

typeof(SomeClassInTheSameAssembly).Assembly.GetWebResourceUrl("Namespace.Resource.xxx")

Of course, using WebResource URLs in Razor views is not very useful. Instead it is recommended to place the resource into the Content or Scripts folder of your MVC application directly.

But the situation changes if you want to write HtmlHelper functions in shared class libraries which cannot place content into the target project.


Rationale

This approach basically avoids to create a new, bulky Page object on each invocation of GetWebResourceUrl.

Looking at the reference source code it turns out that the Page and ScriptManager context is used just for nothing. So invoking AssemblyResourceLoader.GetWebResourceUrlInternal directly will hit the nail on the head. All you need to create a working WebResource.axd URL is the Assembly and, of course, the resource name.

The drawback is that this function is internal, so it have to be invoked by reflection. However, the above implementation avoids the overhead of calling the function by reflection every time. Instead CreateDelegate is used once to get an ordinary delegate which can be called almost without overhead.

The race condition at the access of field GetWebResourceUrlInternal is intended. It does not cause any significant harm because it is very unlikely to run into this code fragment with many parallel threads at the first invocation, and even if it happens the result is still reliable.



来源:https://stackoverflow.com/questions/4996522/what-is-the-right-way-to-handle-embedded-resources-on-a-razor-view

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!