Is there a way to loop through all the resources in a .resx file in C#?
You should always use the resource manager and not read files directly to ensure globalization is taken into account.
using System.Collections;
using System.Globalization;
using System.Resources;
...
/* Reference to your resources class -- may be named differently in your case */
ResourceManager MyResourceClass =
new ResourceManager(typeof(Resources));
ResourceSet resourceSet =
MyResourceClass.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
foreach (DictionaryEntry entry in resourceSet)
{
string resourceKey = entry.Key.ToString();
object resource = entry.Value;
}
Blogged about it on my blog :) Short version is, to find the full names of the resources(unless you already know them):
var assembly = Assembly.GetExecutingAssembly();
foreach (var resourceName in assembly.GetManifestResourceNames())
System.Console.WriteLine(resourceName);
To use all of them for something:
foreach (var resourceName in assembly.GetManifestResourceNames())
{
using(var stream = assembly.GetManifestResourceStream(resourceName))
{
// Do something with stream
}
}
To use resources in other assemblies than the executing one, you'd just get a different assembly object by using some of the other static methods of the Assembly class. Hope it helps :)
Use ResXResourceReader Class
ResXResourceReader rsxr = new ResXResourceReader("your resource file path");
// Iterate through the resources and display the contents to the console.
foreach (DictionaryEntry d in rsxr)
{
Console.WriteLine(d.Key.ToString() + ":\t" + d.Value.ToString());
}
The minute you add a resource .RESX file to your project, Visual Studio will create a Designer.cs with the same name, creating a a class for you with all the items of the resource as static properties. You can see all the names of the resource when you type the dot in the editor after you type the name of the resource file.
Alternatively, you can use reflection to loop through these names.
Type resourceType = Type.GetType("AssemblyName.Resource1");
PropertyInfo[] resourceProps = resourceType.GetProperties(
BindingFlags.NonPublic |
BindingFlags.Static |
BindingFlags.GetProperty);
foreach (PropertyInfo info in resourceProps)
{
string name = info.Name;
object value = info.GetValue(null, null); // object can be an image, a string whatever
// do something with name and value
}
This method is obviously only usable when the RESX file is in scope of the current assembly or project. Otherwise, use the method provided by "pulse".
The advantage of this method is that you call the actual properties that have been provided for you, taking into account any localization if you wish. However, it is rather redundant, as normally you should use the type safe direct method of calling the properties of your resources.
// Create a ResXResourceReader for the file items.resx.
ResXResourceReader rsxr = new ResXResourceReader("items.resx");
// Create an IDictionaryEnumerator to iterate through the resources.
IDictionaryEnumerator id = rsxr.GetEnumerator();
// Iterate through the resources and display the contents to the console.
foreach (DictionaryEntry d in rsxr)
{
Console.WriteLine(d.Key.ToString() + ":\t" + d.Value.ToString());
}
//Close the reader.
rsxr.Close();
see link: microsoft example
You can use ResourceManager.GetResourceSet.
If you want to use LINQ, use resourceSet.OfType<DictionaryEntry>(). Using LINQ allows you, for example, to select resources based on their index (int) instead of key (string):
ResourceSet resourceSet = Resources.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
foreach (var entry in resourceSet.OfType<DictionaryEntry>().Select((item, i) => new { Index = i, Key = item.Key, Value = item.Value }))
{
Console.WriteLine(#"[{0}] {1}", entry.Index, entry.Key);
}
With the nuget package System.Resources.ResourceManager (v4.3.0) the ResourceSet and ResourceManager.GetResourceSet are not available.
Using the ResourceReader, as this post suggest: "C# - Cannot getting a string from ResourceManager (from satellite assembly)"
It's still possible to read the key/values of the resource file.
System.Reflection.Assembly resourceAssembly = System.Reflection.Assembly.Load(new System.Reflection.AssemblyName("YourAssemblyName"));
String[] manifests = resourceAssembly.GetManifestResourceNames();
using (ResourceReader reader = new ResourceReader(resourceAssembly.GetManifestResourceStream(manifests[0])))
{
System.Collections.IDictionaryEnumerator dict = reader.GetEnumerator();
while (dict.MoveNext())
{
String key = dict.Key as String;
String value = dict.Value as String;
}
}
Simple read loop use this code
var resx = ResourcesName.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, false, false);
foreach (DictionaryEntry dictionaryEntry in resx)
{
Console.WriteLine("Key: " + dictionaryEntry.Key);
Console.WriteLine("Val: " + dictionaryEntry.Value);
}
Using LINQ to SQL:
XDocument
.Load(resxFileName)
.Descendants()
.Where(_ => _.Name == "data")
.Select(_ => $"{ _.Attributes().First(a => a.Name == "name").Value} - {_.Value}");
I put my PDF into the resources folder for an MVC 5 Razor project. This is how I opened the file:
public IActionResult ViewCCACH()
{
return GetDocumentLikeThis("FORM CC");
}
private IActionResult GetDocumentLikeThis(string likeThis)
{
ResourceManager MyResourceClass = new ResourceManager(typeof(Resources));
ResourceSet resourceSet = MyResourceClass.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
//ResourceManager resourceSet = new ResourceManager("ACH AUTH FORM CC Blank.pdf", System.Reflection.Assembly.Load("App_GlobalResources"));
foreach (DictionaryEntry entry in resourceSet)
{
string resourceKey = entry.Key.ToString();
object resource = entry.Value;
if (resourceKey.Contains(likeThis))
{
string RunningPath = AppDomain.CurrentDomain.BaseDirectory;
string FileName = string.Format("{0}Properties\\" + resourceKey + ".pdf", Path.GetFullPath(Path.Combine(RunningPath, #"..\..\..\")));
var fileStream2 = new FileStream(FileName, FileMode.Open, FileAccess.Read);
var fsResult2 = new FileStreamResult(fileStream2, "application/pdf");
return fsResult2;
}
}
return View();
}
The code in .cshtml was simple:
<a class="tablinks btn btn-primary m-2 pull-right" href="/Merchant/ViewCCACH" target="_blank">Download File</a>
Related
Is there a way to loop through all the resources in a .resx file in C#?
You should always use the resource manager and not read files directly to ensure globalization is taken into account.
using System.Collections;
using System.Globalization;
using System.Resources;
...
/* Reference to your resources class -- may be named differently in your case */
ResourceManager MyResourceClass =
new ResourceManager(typeof(Resources));
ResourceSet resourceSet =
MyResourceClass.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
foreach (DictionaryEntry entry in resourceSet)
{
string resourceKey = entry.Key.ToString();
object resource = entry.Value;
}
Blogged about it on my blog :) Short version is, to find the full names of the resources(unless you already know them):
var assembly = Assembly.GetExecutingAssembly();
foreach (var resourceName in assembly.GetManifestResourceNames())
System.Console.WriteLine(resourceName);
To use all of them for something:
foreach (var resourceName in assembly.GetManifestResourceNames())
{
using(var stream = assembly.GetManifestResourceStream(resourceName))
{
// Do something with stream
}
}
To use resources in other assemblies than the executing one, you'd just get a different assembly object by using some of the other static methods of the Assembly class. Hope it helps :)
Use ResXResourceReader Class
ResXResourceReader rsxr = new ResXResourceReader("your resource file path");
// Iterate through the resources and display the contents to the console.
foreach (DictionaryEntry d in rsxr)
{
Console.WriteLine(d.Key.ToString() + ":\t" + d.Value.ToString());
}
The minute you add a resource .RESX file to your project, Visual Studio will create a Designer.cs with the same name, creating a a class for you with all the items of the resource as static properties. You can see all the names of the resource when you type the dot in the editor after you type the name of the resource file.
Alternatively, you can use reflection to loop through these names.
Type resourceType = Type.GetType("AssemblyName.Resource1");
PropertyInfo[] resourceProps = resourceType.GetProperties(
BindingFlags.NonPublic |
BindingFlags.Static |
BindingFlags.GetProperty);
foreach (PropertyInfo info in resourceProps)
{
string name = info.Name;
object value = info.GetValue(null, null); // object can be an image, a string whatever
// do something with name and value
}
This method is obviously only usable when the RESX file is in scope of the current assembly or project. Otherwise, use the method provided by "pulse".
The advantage of this method is that you call the actual properties that have been provided for you, taking into account any localization if you wish. However, it is rather redundant, as normally you should use the type safe direct method of calling the properties of your resources.
// Create a ResXResourceReader for the file items.resx.
ResXResourceReader rsxr = new ResXResourceReader("items.resx");
// Create an IDictionaryEnumerator to iterate through the resources.
IDictionaryEnumerator id = rsxr.GetEnumerator();
// Iterate through the resources and display the contents to the console.
foreach (DictionaryEntry d in rsxr)
{
Console.WriteLine(d.Key.ToString() + ":\t" + d.Value.ToString());
}
//Close the reader.
rsxr.Close();
see link: microsoft example
You can use ResourceManager.GetResourceSet.
If you want to use LINQ, use resourceSet.OfType<DictionaryEntry>(). Using LINQ allows you, for example, to select resources based on their index (int) instead of key (string):
ResourceSet resourceSet = Resources.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
foreach (var entry in resourceSet.OfType<DictionaryEntry>().Select((item, i) => new { Index = i, Key = item.Key, Value = item.Value }))
{
Console.WriteLine(#"[{0}] {1}", entry.Index, entry.Key);
}
With the nuget package System.Resources.ResourceManager (v4.3.0) the ResourceSet and ResourceManager.GetResourceSet are not available.
Using the ResourceReader, as this post suggest: "C# - Cannot getting a string from ResourceManager (from satellite assembly)"
It's still possible to read the key/values of the resource file.
System.Reflection.Assembly resourceAssembly = System.Reflection.Assembly.Load(new System.Reflection.AssemblyName("YourAssemblyName"));
String[] manifests = resourceAssembly.GetManifestResourceNames();
using (ResourceReader reader = new ResourceReader(resourceAssembly.GetManifestResourceStream(manifests[0])))
{
System.Collections.IDictionaryEnumerator dict = reader.GetEnumerator();
while (dict.MoveNext())
{
String key = dict.Key as String;
String value = dict.Value as String;
}
}
Simple read loop use this code
var resx = ResourcesName.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, false, false);
foreach (DictionaryEntry dictionaryEntry in resx)
{
Console.WriteLine("Key: " + dictionaryEntry.Key);
Console.WriteLine("Val: " + dictionaryEntry.Value);
}
Using LINQ to SQL:
XDocument
.Load(resxFileName)
.Descendants()
.Where(_ => _.Name == "data")
.Select(_ => $"{ _.Attributes().First(a => a.Name == "name").Value} - {_.Value}");
I put my PDF into the resources folder for an MVC 5 Razor project. This is how I opened the file:
public IActionResult ViewCCACH()
{
return GetDocumentLikeThis("FORM CC");
}
private IActionResult GetDocumentLikeThis(string likeThis)
{
ResourceManager MyResourceClass = new ResourceManager(typeof(Resources));
ResourceSet resourceSet = MyResourceClass.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
//ResourceManager resourceSet = new ResourceManager("ACH AUTH FORM CC Blank.pdf", System.Reflection.Assembly.Load("App_GlobalResources"));
foreach (DictionaryEntry entry in resourceSet)
{
string resourceKey = entry.Key.ToString();
object resource = entry.Value;
if (resourceKey.Contains(likeThis))
{
string RunningPath = AppDomain.CurrentDomain.BaseDirectory;
string FileName = string.Format("{0}Properties\\" + resourceKey + ".pdf", Path.GetFullPath(Path.Combine(RunningPath, #"..\..\..\")));
var fileStream2 = new FileStream(FileName, FileMode.Open, FileAccess.Read);
var fsResult2 = new FileStreamResult(fileStream2, "application/pdf");
return fsResult2;
}
}
return View();
}
The code in .cshtml was simple:
<a class="tablinks btn btn-primary m-2 pull-right" href="/Merchant/ViewCCACH" target="_blank">Download File</a>
in c# by reflection change resource file look like below:
using (ResourceWriter resourceWriter = new ResourceWriter(PathName))
{
foreach (var textItem in selectedText)
{
resourceWriter.AddResource(textItem.Id, textItem.Name);
}
}
a selectedText is List of Id and Name instead of name and value.
when run test a destroy resource file and not opening.
I think you are looking for ResXResourceWriter class
using (ResXResourceWriter resourceWriter = new ResXResourceWriter(PathName))
{
foreach (var textItem in selectedText)
{
resourceWriter.AddResource(textItem.Id, textItem.Name);
}
resourceWriter.Close();
}
Is it possible to enumerate all XAML resources defined in an Assembly? I know how to retrieve a resource if you have it's Key available, but it isn't the case in my situation.
EDIT:
Seems like I wasn't clear enough. I want to list XAML resources defined in an external Assembly that I know full path to.
yeah, you can iterate resources through loops. For example, using foreach loop:
foreach (var res in Application.Current.Resources)
{
Console.WriteLine(res);
}
Update:
To get all ResourceDictionary'ies from external library, you should, at first, load the library, then get ManifestResourceInfo. Let me show an example:
string address = #"WpfCustomControlLibrary.dll";
List<Stream> bamlStreams = new List<Stream>();
Assembly skinAssembly = Assembly.LoadFrom(address);
string[] resourceDictionaries = skinAssembly.GetManifestResourceNames();
foreach (string resourceName in resourceDictionaries)
{
ManifestResourceInfo info = skinAssembly.GetManifestResourceInfo(resourceName);
if (info.ResourceLocation != ResourceLocation.ContainedInAnotherAssembly)
{
Stream resourceStream = skinAssembly.GetManifestResourceStream(resourceName);
using (ResourceReader reader = new ResourceReader(resourceStream))
{
foreach (DictionaryEntry entry in reader)
{
//Here you can see all your ResourceDictionaries
//entry is your ResourceDictionary from assembly
}
}
}
}
You can see all your ResourceDictionary's in reader. Please, see the above code.
I've tested this code and it works.
Try below code:
ResourceDictionary dictionary = new ResourceDictionary();
dictionary.Source = new Uri("pack://application:,,,/WpfControlAssembly;Component/RD1.xaml", UriKind.Absolute);
foreach (var item in dictionary.Values)
{
//Operations
}
Here WpfControlAssembly is name of your assembly.Component is fixed value and then RD1.xaml is a Resource Dictionary.
Below is the output:
Resource Dictionary
Code Output:
PS: All ResourceDictionary Files should have Build Action as 'Resource' or 'Page'.
Update :
Finally I'm able to do this. Please use below method:
public ResourceDictionary GetResourceDictionary(string assemblyName)
{
Assembly asm = Assembly.LoadFrom(assemblyName);
Stream stream = asm.GetManifestResourceStream(asm.GetName().Name + ".g.resources");
using (ResourceReader reader = new ResourceReader(stream))
{
foreach (DictionaryEntry entry in reader)
{
var readStream = entry.Value as Stream;
Baml2006Reader bamlReader = new Baml2006Reader(readStream);
var loadedObject = System.Windows.Markup.XamlReader.Load(bamlReader);
if (loadedObject is ResourceDictionary)
{
return loadedObject as ResourceDictionary;
}
}
}
return null;
}
OUTPUT:
Without any try-catch & expected Exceptions and I think in more WPF(instead of converting everything to ResourceDictionary) way.
I have a program that populates a combo box with details of files contained in a selected directory in a perforce depot.
The relevant piece of code is this:
PerforcePath dir = _ctlProductSelect.SelectedItem as PerforcePath;
_ctlServicePackSelect.Items.Clear();
if (dir != null)
{
foreach (P4.File file in _perforce.GetFiles(null, P4.FileSpec.DepotSpec(dir.Path + "/*.sp")))
{
_ctlServicePackSelect.Items.Add(new PerforcePath(file.DepotPath.Path));
}
}
The problem is that this also includes files that are marked as deleted. Is there any way I can filter the deleted files from the list returned by GetFiles method? I can't find any likely suspects in the P4_dotNet API documentation.
Using P4API.NET, you can add the -e option to GetFiles:
IList filesToFind = new List();
FileSpec fileToFind = new FileSpec(new DepotPath("//depot/..."), null, null, VersionSpec.Head);
filesToFind.Add(fileToFind);
Options o = new Options();
o.Add("-e", "");
IList filesFound = pRep.GetFiles(filesToFind, o);
What I eventually got working was to do this inisde the foreach loop:
foreach (P4.File file in _perforce.GetFiles(null, P4.FileSpec.DepotSpec(dir.Path + "/*.sp")))
{
if (_perforce.GetFileMetaData(null, file)[0].HeadAction.ToString() != "MoveDelete")
_ctlServicePackSelect.Items.Add(new PerforcePath(file.DepotPath.Path));
}
basically checking the metadata for each file before adding it to the combobox.
IList<FileSpec> filesToFind = new List<FileSpec>();
FileSpec fileToFind = new FileSpec(FileSpec.DepotSpec("//depot/...").DepotPath, Revision.Head);
filesToFind.Add(fileToFind);
Options o = new Options();
o.Add("-m", "changelistid");
IList<File> FilesFound = rep.GetFiles(filesToFind, o)
as shown here its possible to get the "default" IIS mime types from HKEY_Classes_Root.
However when I register a new type I cannot find the entry - does anyone know how I get read all IIS registered mime types progamatically ?
Sorry to answer my own question but the answer posted here (shown below) resolves this for both IIS 6 & 7
NameValueCollection map = new NameValueCollection();
using (DirectoryEntry entry = new DirectoryEntry("IIS://localhost/MimeMap"))
{
PropertyValueCollection properties = entry.Properties["MimeMap"];
Type t = properties[0].GetType();
foreach (object property in properties)
{
BindingFlags f = BindingFlags.GetProperty;
string ext = t.InvokeMember("Extension", f, null, property, null) as String;
string mime = t.InvokeMember("MimeType", f, null, property, null) as String;
map.Add(ext, mime);
}
}
You may have to add it in IIS.
http://technet.microsoft.com/en-us/library/cc725608(WS.10).aspx
Update
You could try the DirectoryServices API:
public static string GetMimeTypeFromExtension(string extension)
{
using (DirectoryEntry mimeMap =
new DirectoryEntry("IIS://Localhost/MimeMap"))
{
PropertyValueCollection propValues = mimeMap.Properties["MimeMap"];
foreach (object value in propValues)
{
IISOle.IISMimeType mimeType = (IISOle.IISMimeType)value;
if (extension == mimeType.Extension)
{
return mimeType.MimeType;
}
}
return null;
}
}
Can I setup an IIS MIME type in .NET?