无法在asp.net中访问嵌入式资源。

7
我正在尝试将用户控件中的图像和样式表移动到程序集的嵌入资源中。我使用Reflector查看了图像和.css文件已经被嵌入到程序集中,但是当我尝试使用ClientScript.GetWebResourceUrl()创建的URL访问它们时,无法找到该资源。我困惑了。
程序集默认命名空间:
TestWebApp

文件的路径(标记为BuildAction:Embedded Resource)为:
TestWebApp/Resources/CSS/PaymentHistory.css
TestWebApp/Resources/Images/loading.gif

因此,我的资源已注册为:

[assembly: WebResource("TestWebApp.Resources.CSS.PaymentHistory.css", "text/css", PerformSubstitution = true)]
[assembly: WebResource("TestWebApp.Resources.Images.loading.gif", "image/gif")]

访问资源的用户控件(在同一程序集中):

TestWebApp.UserControls.PaymentHistory

为了简化,我目前只是尝试引用图像而不是样式表。在我的用户控件的Page_Load中,我将Image控件的ImageUrl设置为资源URL:
image1.ImageUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(), "TestWebApp.Resources.Images.loading.gif");

运行时,一切似乎没有错误,但是它呈现了一张损坏的图片。这是呈现出来的图片源代码:

<img style="border-width:0px;" src="/WebResource.axd?d=8fC_1tLPjrUCxmFc_Q2MKY0-pHAak-sTWkpLLV3D56H_c08LujXC63ia2PNICE65_i-Q4JqprAigLpbrXG-rIAr6ePO4HHcdQKgdd3szlThv2gizxOJLJsPRNe-b_M6ApTwPsH_5oZAuONTN0cumOTRr1nA1&amp;t=635133745137507721" id="ph1_image1">

如果我在浏览器中导航到该URL,我会得到一个404错误,即找不到该资源。我做错了什么吗?
编辑: 我一定是没有理解某些基本的东西和/或者我做了一些非常愚蠢的事情。 这里有一个简单的VS 2010示例。我已经按照我知道的所有必需步骤来嵌入JScript1.js并通过WebResource.axd访问它,但它出现了错误。

2
在调试中,验证Assembly.GetExecutingAssembly().GetManifestResourceNames()返回您所期望的资源名称。此外,考虑使用字符串常量来确保您在WebResource属性和GetWebResourceUrl命令中使用相同的字符串。 - Grax32
@Grax - 谢谢,我很感激。使用GetManifestResourceNames(),我已经多次验证了正在使用的字符串都是匹配和正确的。我还尝试将资源从它们的子文件夹移动到项目根目录。我注意到我有一个不正确的内容类型“img/gif”,现在已更改为“image/gif”,但令我惊讶的是,这并没有解决问题。我还注意到输出窗口记录了两个System.Web.HttpExceptions,指出“这是无效的webresource请求。”。我不确定为什么会有两个...我的猜测是Firefox或“Cassini”自动重试。 - xr280xr
@Grax 我已更新问题,并提供了一个示例,如果您愿意可以尝试一下。 - xr280xr
我找到了你的答案 https://dev59.com/CmnWa4cB1Zd3GeqPwhHn 你需要将其转换为Web应用程序或将嵌入式资源放在单独的dll中。 - Grax32
WebResource.axd处理程序工作吗?这可能有许多失败的情况。 - Simon Mourier
显示剩余2条评论
4个回答

12
在你的示例项目的Default.aspx.cs文件中,将this.GetType()更改为typeof(_Default)
Page.ClientScript.RegisterClientScriptInclude("JScript1",
    Page.ClientScript.GetWebResourceUrl(typeof(_Default), "EmbeddedResources.JScript1.js"));

同样地,在 PaymentHistory.ascx.cs 文件中,将 this.GetType() 修改为 typeof(PaymentHistory)

image1.ImageUrl = Page.ClientScript.GetWebResourceUrl(
    typeof(PaymentHistory), "TestWebApp.Resources.Images.loading.gif");

解释:GetWebResourceUrl检查type参数以确定包含嵌入式资源的程序集。在.aspx或.ascx代码后备类中指定this.GetType()作为type是不正确的,因为this.GetType()引用的不是该类而是从.aspx或.ascx标记生成的派生类。这个派生类驻留在一个单独的程序集中,所以GetWebResourceUrl无法找到嵌入的资源。


哇,我简直不敢相信我没有想到检查这个.GetType()来进行故障排除。然而,我从未知道预编译页面和控件会生成一个类。非常感谢你,Michael! - xr280xr

1
首先,您传递给GetWebResourceUrl调用(或我下面展示的RegisterClientScriptResource)的类型实际上是指向包含资源的程序集。问题在于,“this.GetType()”返回的类型不在当前执行的程序集中(尽管这可能很奇怪)。
以下两行演示了这个问题。
        Response.Write(this.GetType().Assembly.FullName + "<br>");
        Response.Write(Assembly.GetExecutingAssembly().FullName + "<br>");

第一行返回一个“App_Web_??????”程序集的名称。第二行返回预期的“EmbeddedResources”程序集。
在下面的调用中,我只是传递执行程序集返回的第一个类型,该调用有效。 Page.ClientScript.RegisterClientScriptResource(Assembly.GetExecutingAssembly().GetTypes()[0], names[0]);
this.GetType() 实际上返回一个 Web 服务器创建的继承于您的类型的类型。这就是为什么 typeof(_Default) 也可以指定正确程序集的原因。

使用 GetTypes()[0] 可以工作,但是当你只需要一个类型时,加载程序集中的所有类型似乎有点低效。 - Michael Liu

1

资源是在单独的项目中还是与您的用户控件在同一个项目中?如果是单独的,您必须用位于单独项目中的对象的GetType()函数替换this.GetType()。

如果在同一个项目中,只需使用Page.GetType(),因为您需要引用页面而不是用户控件。


你的问题已经在我的原始帖子中得到了回答,但感谢你指出了那个细节。使用Page.GetType()并不能解决它。该方法所需的只是包含资源的程序集中的类型。在我的情况下,页面和用户控件都符合这个条件,所以不应该有任何区别。 - xr280xr

0
在这里,您可以看到一个使用反射库来检测当前程序集名称和当前命名空间的VB.NET代码。
如果将命名空间与嵌入式图像名称连接起来,您可以使用命令Page.clientScript.GetWebResourceURL生成图像链接,如第一个函数中所示。
在第二个函数中,您可以看到循环遍历所有资源名称,直到找到嵌入式资源的完整名称。
Friend Class ReadResources

    ' Get our assembly.
    Private Shared executingAssembly As System.Reflection.Assembly = Reflection.Assembly.GetExecutingAssembly()

    ' Get our namespace.
    Private Shared myNamespace As String = executingAssembly.GetName().Name.ToString()

    ''' <summary>
    ''' Generate resource link
    ''' </summary>
    Friend Shared Function GetResourceLink(ByVal ref As String,
                                           ByVal obj As Object,
                                           ByVal page As Web.UI.Page) As String
        Dim out As String = Nothing
        out = Page.ClientScript.GetWebResourceUrl(obj.GetType, myNamespace & "." & ref)

        If out Is Nothing OrElse out.Length <= 0 Then
            out = FindResource(ref, obj)
        End If

        Return out
    End Function

    Friend Shared Function FindResource(ByVal reference As String,
                                        ByVal obj As Object) As String
        Dim out As String = ""
        For Each embedded In obj.GetType().Assembly.GetManifestResourceNames()
            If embedded.Contains(reference) Then
                out = embedded
                Exit For
            End If
        Next
        Return out
    End Function


End Class

请避免仅提供代码的答案。考虑为您的代码添加解释。 - user585968
根据您的建议 - Fabio Kfouri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接