Naeem Sarfraz
Naeem Sarfraz

Reputation: 7430

WebResource Hell - resource cannot be found

Marked a javascript file as "Embedded resource"
Added WebResource attribute to my AssemblyInfo class

Now i'm trying to output the embedded javascript to my master page. All I'm getting is a "Web Resource not found" from the web resource url.


Project Assembly Name:

CompanyProduct


Project Default Namespace:

Company.Product.Web


Javascript file located:
Library/navigation.js


AssemblyInfo:

[assembly: WebResource("CompanyProduct.Library.navigation.js", "text/javascript")]


Code in master page:

Page.ClientScript.RegisterClientScriptInclude("NavigationScript", Page.ClientScript.GetWebResourceUrl(this.GetType(), "CompanyProduct.Library.navigation.js"));

Server Error in '/' Application.

The resource cannot be found.

Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable.  Please review the following URL and make sure that it is spelled correctly.

Requested URL: /WebResource.axd
Version Information: Microsoft .NET Framework Version:2.0.50727.1433; ASP.NET Version:2.0.50727.1433

Upvotes: 14

Views: 12681

Answers (15)

NightOwl888
NightOwl888

Reputation: 56859

After trying most of the solutions here, I came across this other StackOverflow answer which worked.

The time that is stamped on the DLL must be after the current time, otherwise WebResource.axd will not serve resources from it.

This mechanism seems to be completely unaware of time zone differences. If your CI server is in a time zone that is further east than your target web server, the time difference between the zones makes the resources unavailable until the web server time reaches the time on the DLL. The solution is to ensure your CI agent's time zone is set to the same as (or further west than) your target servers using Set-TimeZone in your build script.

Of course, the ideal solution is to set all servers to UTC, but not all applications are coded to be time zone independent.

Upvotes: 0

Guish
Guish

Reputation: 5160

I had a similar problem and, in my case, it was caused by the fact that Page.ClientScript.GetWebResourceUrl resourceName parameter is case sensitive.

Upvotes: 1

Mark Dornian
Mark Dornian

Reputation: 416

Just had this problem and solved it based upon meandmycode's response; however, maybe a more detail explanation is needed.

When you register the script block using the ScriptManager.RegisterClientScriptInclude method the "type" parameter must be of a class inside the same project as the .js script. If you have no class associated with the script block you are going to just have to pick another class.

Upvotes: 1

kerem
kerem

Reputation: 2710

[assembly: ] attributes have to be in the Properties\AssemblyInfo.cs file. Even though the project is compiled when assembly attributes are in the custom control file, they are not visible to WebResource.axd.

Upvotes: 0

david
david

Reputation: 11

this blog is two years old now... but I I spent days on trying to get this to work. Trying to get an embedded js file to actually give me a WebResource.asx query string that would work. The final piece that seems to get glossed over here is that the file you have embedded HAS to be in the same physical directory structure as the controls code-behind that you are calling GetWebResourceUrl() from. If you've placed the embedded file in a folder called "scripts", then called GetWebResourceUrl() from the master page which is NOT found in "scripts", the ResourceURL returned will point to the wrong location... thus ALWAYS returning a 404.

if you are using the MasterPage as the type for the first param then it will never work. GetWebResourceUrl(typeof(MasterPage),... I guess the real key here is that you have to drop the embedded resource into the same location that you are going to use as the type for the first parameter of the ResourceURL. After 3 days of wrestling with this thing, it finally found my Resource.

Upvotes: 1

RichardHowells
RichardHowells

Reputation: 9066

For anyone who happens to be using VB - there is a difference in behavior between the VB compiler and the C# compiler.

In VB the embedded resource HAS to be at the root level of your project. When I looked at the generated assembly with ILDASM I found that the name of the embedded resource NEVER includes the names of any subfolders. This eventually causes the AssemblyLoader to look in the wrong place for the embedded resource.

When you repeat the experiment with C# it DOES include the names of the subfolders.

EDIT - Changed to reflect that for VB the resource it HAS to be at the root level.

What I succeeded with was to have the embedded resource in the same folder as the code that uses it (nicer for source control). I then LIED in the Attribute AND the Page.ClientScript.GetWebResourceUrl call to account for the VB compiler claiming that the embedded resource has no paths.

Upvotes: 1

mizuki nakeshu
mizuki nakeshu

Reputation: 1354

As meandmycode already mentioned, the type passed to GetWebResourceUrl is the key

I didn't fancy passing type where it does not really matter, I solved it with this kind of helper method

static public string GetEmbeddedResourceLink(Page page, string assemblyName, string resource) {
    var assembly = Assembly.Load(assemblyName);
    var types = assembly.GetTypes();
    if (types.Length == 0) {
        throw new ArgumentException("assembly does not contain any type");
    }
    return page.ClientScript.GetWebResourceUrl(types[0], resource);
}

Upvotes: 0

jaraics
jaraics

Reputation: 4299

I had a similar situation, and after about 4 hours of researching and testing I got the final solution: the Default Namespace must be the same as the Assembly Name.
(One could use Reflector or use the below code snippet to get the names of the embedded resources.

string[] embeddedResNames = Assembly.LoadFile("YourDll.dll").GetManifestResourceNames()

Upvotes: 0

meandmycode
meandmycode

Reputation: 17317

Instead of this.GetType(), get a type from the assembly that contains the resource.. ie:

typeof(Company.Product.Web.Library.Class1)

Does that work?

Upvotes: 14

dh.
dh.

Reputation: 1511

Came to the same issue today. The problem seems to be that AssemblyResourceLoader uses the assembly containing the type provided to GetWebResourceUrl method (first parameter) which in your case is a dynamically created assembly for the master page (.master) and does not contain the resource you are looking for. I assume that your resource file is included in the same assembly as your base master page (.master.cs file) then you could use typeof to get the Type instance

Page.ClientScript.RegisterClientScriptInclude(
   "NavigationScript",
   Page.ClientScript.GetWebResourceUrl(
      typeof(MyMasterPage),
      "CompanyProduct.Library.navigation.js"));

where MyMasterPage is the name of your master page

Looks like it is also possible to use any other type declared in the same assembly where the resource is embedded.

Upvotes: 4

Helephant
Helephant

Reputation: 17028

Is the resource that you're adding in a different assembly to the code that you're using to generate the script tag? If that's the case, I think the this.GetType() will return a reference to a type in the wrong assembly so the web resource code won't have the right assembly to load the resource from.

I don't know for sure that this would be a problem but it seems to me that the code that generated the name would need to know what assembly the resource was on or it wouldn't be able to map back to that assembly when it received the request from the browser.

Upvotes: 0

Helephant
Helephant

Reputation: 17028

This is clutching at straws a bit, but could it be that your asp.net isn't set up to process the webresource.axd correctly? If something has gone wrong maybe the handler tag is missing from the machine's web.config?

The http handlers tag of C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\web.config should have a webresource.axd entry like this:

<httpHandlers>
    <add path="WebResource.axd" verb="GET" type="System.Web.Handlers.AssemblyResourceLoader" validate="True"/>
</httpHandlers>

Also double check there isn't any handler entry in the project's web.config that could be overriding the setting from the machine's web.config.

Upvotes: 1

Thomas Hansen
Thomas Hansen

Reputation: 5513

Turn this one;

Page.ClientScript.RegisterClientScriptInclude("NavigationScript"...

into this;

Page.ClientScript.RegisterClientScriptInclude("CompanyProduct.Library.navigation.js"...

Upvotes: 0

ChrisN
ChrisN

Reputation: 3413

The answer to your question completely depends on where you have this file in your actual project, and what the default namespace is. As Chris mentioned, the path you provide to the methods that register the script need the right path to locate the embedded resource. You don't just match the string you specify in your AssemblyInfo. The string has to be the correct path to the resource.

< default project namespace >/< any subfolders you have the file in >/< filename >

Upvotes: 0

Chris Shaffer
Chris Shaffer

Reputation: 32575

I think you want the full paths to be based on the namespace, not the assembly; So anywhere you have "CompanyProduct.Library.navigation.js", replace it with "Company.Product.Web.Library.navigation.js". Also, there is a method Page.ClientScript.RegisterClientScriptResource() that does what you need in one method (as opposed to using RegisterClientScriptInclude(GetWebResourceUrl()).

Upvotes: 3

Related Questions