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
Related
I have a web application project. I generated the DLL and import it in another project. I implemented VirtualPathProvider.
I followed this web site: http://support.microsoft.com/kb/910441/en-us?spid=8940&sid=global, and everything works until I add another site master.
I added site_export.master and changed its Build Action to Embedded Resource.
I changed my page to use the new site master.
GetManifestResourceStream() returns null when I load site_export.master.
I call GetManifestResourceNames() to check if site_export.master exists in the DLL and it does. It's in the list. All of the name spaces match. I didn't list the name space out here.
Why can't GetManifestResourceStream() load my new site_export.master? It loads site.master just fine. I know my DLL is loaded because I can see other files in the DLL.
Remember the following issues...
Step 1. Build action set to embedded resource see
C#’s GetManifestResourceStream Gotcha
Step 2. Use namespace.resourcename see GetManifestResourceStream() returns null ?
Actually, this method returns null if a private resource in another assembly is accessed and the caller does not have ReflectionPermission with the ReflectionPermissionFlag.MemberAccess flag.
Side-hint. To make sure you're in the right assembly and with right name: dump and evaluate all the resources available in your target assembly
string[] names = assembly.GetManifestResourceNames();
(in my case, I misused a namespace from another assembly)
I did this to make it work:
Step 1: Select the resource (CRDF.xsl in my case) and right click > Properties.
Set Build Action to "EmbeddedResource" and Logical Name to name of your choice, e.g. CRDFXSL.
Step 2 : Change your Source code like this:
Assembly _assembly;
_assembly = Assembly.GetExecutingAssembly();
xslStream = _assembly.GetManifestResourceStream("CRDFXSL");
_xmlReader = XmlReader.Create(xslStream);
Thus everything went smoooooooth..
Hint and Caution:
If the "Assembly name" and "Default namespace" does not match in the project file then also GetManifestResourceStream would return null. GetManifestResourceNames still returns the names of assemblies but during loading the manifest would not work.
Try this:
Dim ctx As Windows.ApplicationModel.Resources.Core.ResourceContext = New Windows.ApplicationModel.Resources.Core.ResourceContext()
ctx.Languages = {Globalization.CultureInfo.CurrentUICulture.Name}
Dim rmap As Windows.ApplicationModel.Resources.Core.ResourceMap = Windows.ApplicationModel.Resources.Core.ResourceManager.Current.MainResourceMap
Dim res = rmap.GetValue("Assets/sample.png", ctx)
Dim resFile = Await res.GetValueAsFileAsync
The Windows.ApplicationModel.Resources.Core.ResourceManager.Current.MainResourceMap list all resources.
My main Windows Forms (managed C++) project has a class that presents an image with tiles that can be shown or hidden to create a responsive diagram.
I created a separate utility app that helps me get all the images positioned correctly, etc. This app is written in C# and writes a .resx file containing the image data and positioning, using the following code snippet:
using(ResXResourceWriter resx = new ResXResourceWriter(sfd.FileName)) {
resx.AddResource("Size", canvas.Size);
List<int> IDs = canvas.IDs;
resx.AddResource("IDList", IDs);
resx.AddResource("BackgroundIndex", canvas.BackgroundIndex);
foreach(int id in IDs) {
String positionKey = String.Format("Position.id{0}", id);
String visibilityKey = String.Format("Visibility.id{0}", id);
String imageKey = String.Format("Image.id{0}", id);
resx.AddResource(imageKey, canvas.TileImage(id));
resx.AddResource(positionKey, canvas.TilePosition(id));
resx.AddResource(visibilityKey, canvas.TileVisible(id));
}
}
I can open the .resx file in a text editor and see that it is well-formed and contains the expected data.
Then I take that .resx file and add it to my main application's project. Now I can't figure out how to get at the resources inside it. The code I've tried is:
ResourceManager ^ image_rm = gcnew ResourceManager(
"resx_file_name_without_extension", GetType()->Assembly);
ResourceSet ^ image_rs = image_rm->GetResourceSet(
System::Globalization::CultureInfo::CurrentCulture, true, true);
At runtime, the second line (the GetResourceSet call) throws a System.Resources.MissingManifestResourceException with the following message text:
Resource load failure:
Could not find any resources appropriate for the specified culture or the
neutral culture. Make sure "resx_file_name_without_extension.resources" was
correctly embedded or linked into assembly "my_assembly" at compile time, or
that all the satellite assemblies required are loadable and fully signed.
I suspect my problem is...well I don't really know. Maybe I'm not using the right identifier in the ResourceManager constructor. I tried explicitly setting "Excluded From Build: No" and "Content: Yes" in the file's properties, but that had no effect.
Is it even possible to drop an externally-created .resx file into a project and get at the resources within? I definitely need it compiled in; I can't ship a product with dangling .resx files. I can always create a set of static data objects in .cpp files, but the .resx approach seemed more elegant...
Turns out a comment on this unanswered question was the secret sauce. Prepending the root namespace to the identifier made the ResourceManager happy:
ResourceManager ^ image_rm = gcnew ResourceManager(
"my_root_namespace.resx_file_name_without_extension", GetType()->Assembly);
ResourceSet ^ image_rs = image_rm->GetResourceSet(
System::Globalization::CultureInfo::CurrentCulture, true, true);
Just how or why the compiler decided to place the resources within that namespace is still a bit of a mystery to me, but that's trivia for another day.
The question to which I link involves a .resx created with VS within the project, and mine involves adding one created externally, so I think it's a different-enough situation to warrant a separate Q/A.
I have a web application project. I generated the DLL and import it in another project. I implemented VirtualPathProvider.
I followed this web site: http://support.microsoft.com/kb/910441/en-us?spid=8940&sid=global, and everything works until I add another site master.
I added site_export.master and changed its Build Action to Embedded Resource.
I changed my page to use the new site master.
GetManifestResourceStream() returns null when I load site_export.master.
I call GetManifestResourceNames() to check if site_export.master exists in the DLL and it does. It's in the list. All of the name spaces match. I didn't list the name space out here.
Why can't GetManifestResourceStream() load my new site_export.master? It loads site.master just fine. I know my DLL is loaded because I can see other files in the DLL.
Remember the following issues...
Step 1. Build action set to embedded resource see
C#’s GetManifestResourceStream Gotcha
Step 2. Use namespace.resourcename see GetManifestResourceStream() returns null ?
Actually, this method returns null if a private resource in another assembly is accessed and the caller does not have ReflectionPermission with the ReflectionPermissionFlag.MemberAccess flag.
Side-hint. To make sure you're in the right assembly and with right name: dump and evaluate all the resources available in your target assembly
string[] names = assembly.GetManifestResourceNames();
(in my case, I misused a namespace from another assembly)
I did this to make it work:
Step 1: Select the resource (CRDF.xsl in my case) and right click > Properties.
Set Build Action to "EmbeddedResource" and Logical Name to name of your choice, e.g. CRDFXSL.
Step 2 : Change your Source code like this:
Assembly _assembly;
_assembly = Assembly.GetExecutingAssembly();
xslStream = _assembly.GetManifestResourceStream("CRDFXSL");
_xmlReader = XmlReader.Create(xslStream);
Thus everything went smoooooooth..
Hint and Caution:
If the "Assembly name" and "Default namespace" does not match in the project file then also GetManifestResourceStream would return null. GetManifestResourceNames still returns the names of assemblies but during loading the manifest would not work.
Try this:
Dim ctx As Windows.ApplicationModel.Resources.Core.ResourceContext = New Windows.ApplicationModel.Resources.Core.ResourceContext()
ctx.Languages = {Globalization.CultureInfo.CurrentUICulture.Name}
Dim rmap As Windows.ApplicationModel.Resources.Core.ResourceMap = Windows.ApplicationModel.Resources.Core.ResourceManager.Current.MainResourceMap
Dim res = rmap.GetValue("Assets/sample.png", ctx)
Dim resFile = Await res.GetValueAsFileAsync
The Windows.ApplicationModel.Resources.Core.ResourceManager.Current.MainResourceMap list all resources.
I'm using C# ASP.NET VS2010.
I have a procedure on an .aspx.cs that reads a XML file and works just fine.
It goes like this:
string fileName = "~/App_Data/" + filename + ".xml";
DataSet ds = new DataSet();
ds.ReadXml(MapPath(fileName));
I use this procedure alot to read various files with minimal changes (the file name), therefore, I tried to put the procedure in a Class1.cs file (in the App_Code folder), but I get this error message:
The type or namespace name 'MapPath' does not exist in the namespace 'Microsoft.SqlServer.Server' (are you missing an assembly reference?)
I use this MapPath to read an XML file into a dataset this way:
ds.ReadXml(Server.MapPath(fileName));
The filename is a string variable declared a few lines earlier:
string fileName = "~/App_Data/" + inputString + ".xml";
After putting this line in the class.cs file, the VS2010 asked to resolve the missing Server by replacing it into Microsoft.SqlServer.Server locally (at the same line and not by adding a namespace) , so the line in it's new form looks like this:
ds.ReadXml(Microsoft.SqlServer.Server.MapPath(fileName));
For the record, I made sure that all namespaces on the source .aspx.cs file are at the class file.
Why the difference between the Class1.cs and the .aspx.cs?
How do I workaround this?
What should I change in order to read the XML file from this new class file?
Is there a replacement for my line to read the XML file into the dataset?
MapPath is method of the System.Web.HttpServerUtility class, you need an instance of this class to call the method. In ASP pages, an instance is available in the Server member of the Page; elsewhere, you'll have to supply it. Either as
HttpContext.Current.Server.MapPath(fileName);
which uses the Server variable for the current HttpContext if you're inside one. HttpContext class contains many HTTP-related objects that you're used to access through Page members - like Request, Response, Server. The Current static property gives the context for the request you're currently handling. Inside classes in App_Code folder of your ASP web project, you're safe to assume that there's an active context.
If you wanted to move your class to a separate assembly, it would be better to make the Server (or Context) a parameter of your method and make it the responsibility of the caller to supply one:
public class Class1
{
public void MyMethod(HttpServerUtility server)
{
//...
server.MapPath(fileName);
//...
}
}
From the ASP page it would then be called like class1instance.MyMethod(this.Server);
Microsoft.SqlServer.Server has nothing to do with it, only the class/member names are the same and Visual Studio got it wrong.
I am trying here to do a manual translation for the application I am working with. (There is already a working LocalizationModule but it's working dodgy, so I can't use <asp:Localize /> tags.
Normally with ResourceManager you are supposed to be using it as Namespace.Folder.Resourcename (in an application). Currently I am translating an existing asp.net "website" (not web application so no namespace here....).
The resources are located into a folder name "Locales/resources" which contains "fr-ca.resx" and "en-us.resx".
So I used a code with something like this :
public static string T(string search)
{
System.Resources.ResourceManager resMan = new System.Resources.ResourceManager( "Locales", System.Reflection.Assembly.GetExecutingAssembly(), null );
var text = resMan.GetString(search, System.Threading.Thread.CurrentThread.CurrentCulture);
if (text == null)
return "null";
else if (text == string.Empty)
return "empty";
else
return text;
}
and inside the page I have something like this <%= Locale.T("T_HOME") %>
When I refresh I have this :
Could not find any resources
appropriate for the specified culture
or the neutral culture. Make sure
"Locales.resources" was correctly
embedded or linked into assembly
"App_Code.9yopn1f7" at compile time,
or that all the satellite assemblies
required are loadable and fully
signed. Description: An unhandled
exception occurred during the
execution of the current web request.
Please review the stack trace for more
information about the error and where
it originated in the code.
Exception Details:
System.Resources.MissingManifestResourceException:
Could not find any resources
appropriate for the specified culture
or the neutral culture. Make sure
"Locales.resources" was correctly
embedded or linked into assembly
"App_Code.9yopn1f7" at compile time,
or that all the satellite assemblies
required are loadable and fully
signed.
Source Error:
Line 14:
System.Resources.ResourceManager
resMan = new
System.Resources.ResourceManager(
"Locales",
System.Reflection.Assembly.GetExecutingAssembly(),
null ); Line 15: Line 16: var
text = resMan.GetString(search,
System.Threading.Thread.CurrentThread.CurrentCulture);
Line 17: Line 18: if (text == null)
Source File:
c:\inetpub\vhosts\galerieocarre.com\subdomains\dev\httpdocs\App_Code\Locale.cs
Line: 16
I even tried to load the resource with Locales.fr-ca or only fr-ca nothing quite work here.
Marvin Smit's solution is great if you do not have access to the HTTPContext
const string ASSEMBLY_NAME = "App_GlobalResources";
const string RESOURCE_NAME = "Resources.MetaTagResource";
const string RESOURCE_MANAGER = "ResourceManager";
Assembly assembly = Assembly.Load(ASSEMBLY_NAME);
Type type = assembly.GetType(RESOURCE_NAME);
PropertyInfo propertyInfo = type.GetProperty(RESOURCE_MANAGER);
ResourceManager resourceManager = propertyInfo.GetValue(null, new object[] { }) as ResourceManager;
resourceManager.GetResourceSet(CultureInfo.InvariantCulture, true, true);
But if you have access to the HTTPContext just use HttpContext.GetGlobalResourceObject
string title = HttpContext.GetGlobalResourceObject("MetaTagResource", "Title").ToString();
string keywords = HttpContext.GetGlobalResourceObject("MetaTagResource", "keywords").ToString();
string description = HttpContext.GetGlobalResourceObject("MetaTagResource", "Description").ToString();
Maybe you are just looking for The System.Web.Page's base GetLocalResourceObject(),?
see http://msdn.microsoft.com/en-us/library/ms153597.aspx
When using resources in ASP.Net, you will see a specialized compiler being used (custom Tool property) on the .resx files (ResXCodeGen)
Bottom line of this is that your resources are compiled into a class. The name of this class is the name you should use when you want to address the resources in there.
The name of the class is generated as follows:
{project namespace}{folder structure}{filename}.resx (.resx is NOT part of the generated name)
Since you mentioned your resx file is located in a directory name "Locales/resources", the name you would have to use is (assuming the resx file is called 'locales.resx')
"locales.resources.locales"
The addition of the language and locale, like the "uk-en" is added by the resource manager, loading the appropriate assembly based on the Culture that is specified when creating an instance of the ResourceManager. If none is given, the Thread.CurrentCulture is used. You should not use the language/locale extensions yourself, leave it to the resource manager to deal with that.
If you are not sure how the resources class will end up, you can always look at the MSIL or use reflector to determine the name of the resource class in the actual deployed assembly.
;-- Added after comments where placed -------
I also looked at some other code i had arround;
Have you tried the Reflection on App_GlobalResources approach?
1: You load the "App_GlobalResources" library while in the context of the website (in a HttpHandler, Aspx, Ascx, etc). =>
Assembly.Load("App_GlobalResources");
2: Walk through the available types in there and grab the "ResourceManager" property from each type.=>
PropertyInfo pi = type.GetProperty("ResourceManager");
resManager = pi.GetValue(null, new object[] { }) as ResourceManager;
3: If it had one, get the ResourceSet you want => resManager.GetResourceSet(englishCulture, true, true);
Hope this helps.
this is not c# but you can easily convert it into it
I have in the app_localResources directory with 2 files
myPage.aspx.resx
myPage.aspx.fr-ca.resx
and I use it like this in my .aspx page
<asp:Label ID="lAddress1" runat="server" Text="<%$ Resources: lAddress1 %>"></asp:Label>
this is how I manage it on mine
'using LCID from
Public Enum elang
En = &H1009 'en-CA http://www.microsoft.com/resources/msdn/goglobal/default.mspx?submitted=1009&OS=Windows%202003%20%20Service%20Pack%201
Fr = &HC0C 'fr-CA http://www.microsoft.com/resources/msdn/goglobal/default.mspx?submitted=0C0C&OS=Windows%202003%20%20Service%20Pack%201
End Enum
'strongly typed value in session
Private _lang As elang = elang.En
Public Property lang() As elang
Get
Return _lang
End Get
Set(ByVal value As elang)
_lang = value
End Set
End Property
and in every page I got
Protected Overrides Sub InitializeCulture()
If Not Me.IsPostBack Then
Threading.Thread.CurrentThread.CurrentUICulture = New Globalization.CultureInfo(Sess.lang)
Threading.Thread.CurrentThread.CurrentCulture = Globalization.CultureInfo.CreateSpecificCulture(Threading.Thread.CurrentThread.CurrentUICulture.Name)
End If
MyBase.InitializeCulture()
End Sub
when I want to use the resourcemanager I create a global resources file at the root level the I use it like this
Dim rm = New System.Resources.ResourceManager("Resources.MyPage", Reflection.Assembly.Load("App_GlobalResources"))
Edit
In case of a Web Site project, read this walkthrough of Microsoft.
I'm afraid you can't use the ResourceMagager in a Website project, because it requires a namespace / assembly where the resources are located.