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&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.
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.
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
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.
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