Cannot access embedded resource in asp.net

2020-06-17 04:48发布

问题:

I'm trying to move an image and a style sheet from a user control to embedded resources in the assembly. I have used Reflector to see that the image and .css file are embedded in the assembly, but when I try to access them using the URL created by ClientScript.GetWebResourceUrl(), the resource is not found. I'm stumped.

Assembly default namespace:

TestWebApp

The paths to the files (marked as BuildAction: Embedded Resource) are

TestWebApp/Resources/CSS/PaymentHistory.css
TestWebApp/Resources/Images/loading.gif

And so my resources are registered as:

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

User Control (in the same assembly) that accesses the resources :

TestWebApp.UserControls.PaymentHistory

To simplify, I'm currently just trying to reference the image and not the stylesheet. In my user control's Page_Load, I set the ImageUrl of an Image control to the resource URL:

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

At runtime, everything appears to work without errors but it renders a broken image. Here is the rendered image source:

<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">

If I navigate to that URL in my browser, I get a 404, The resource cannot be found. What am I doing wrong?

EDIT: There must be something fundamental I'm not understanding and/or I'm doing something really stupid. Here is a simple VS 2010 example. I have followed all of the required steps I'm aware of to embed JScript1.js and access it via WebResource.axd, but it gets the error.

回答1:

In the Default.aspx.cs file of your example project, change this.GetType() to typeof(_Default):

Page.ClientScript.RegisterClientScriptInclude("JScript1",
    Page.ClientScript.GetWebResourceUrl(typeof(_Default), "EmbeddedResources.JScript1.js"));

Similarly, in the PaymentHistory.ascx.cs file, change this.GetType() to typeof(PaymentHistory):

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

Explanation: GetWebResourceUrl looks at the type argument to determine which assembly contains the embedded resource. Specifying this.GetType() as the type is incorrect because, in an .aspx or .ascx code-behind class, this.GetType() refers not to that class but rather to the derived class that gets dynamically generated from the .aspx or .ascx markup. This derived class resides in a separate assembly, so GetWebResourceUrl can't find the embedded resource.



回答2:

Is the resource in a separate project or in the same project as your User Control? If separate you have to substitute this.GetType() with an object's GetType() function that resides in the separate project.

If in the same project, just do Page.GetType(), because you want a reference to the page and not the user control



回答3:

First of all, the type that you are passing to the GetWebResourceUrl call (or to the RegisterClientScriptResource I show below) is actually there to point to which assembly contains your resource. The problem is that "this.GetType()" is returning a type that is not in the current executing assembly (as strange as that may be).

The following 2 lines demonstrate the issue.

        Response.Write(this.GetType().Assembly.FullName + "<br>");
        Response.Write(Assembly.GetExecutingAssembly().FullName + "<br>");

The first line returns the name of a "App_Web_??????" assembly. The second returns the expected "EmbeddedResources" assembly.

In the call below, I just pass in the first type I get back from the executing assembly and the call works. Page.ClientScript.RegisterClientScriptResource(Assembly.GetExecutingAssembly().GetTypes()[0], names[0]);

this.GetType() actually returns a type that the web server creates that inherits from your type. That is why typeof(_Default) would also work to designate the correct assembly.



回答4:

Here you can see a code in Vb.NET that uses the Reflection library to detect the current Assembly Name and the current NameSpace.

If you concatenate the namespace with embedded image name, you can use the command Page.clientScript.GetWebResourceURL to generate a link for image as you see in first function

In second function, you see a loop in all of resources name until find the complete name of embedded resouce.

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