I'm currently working on a dll which would be used across future projects, and trying to fill it with every useful method developped in the last one. One of these methods that i'd like to re-use allows to generate an excel file with any object collection, and uses a resx resource file to get the column headers based on the object's property names.
Now, my problem is that I can't access or even check the existence of such a file from the library. A possible workaround would be to turn this resource file into a dictionary and pass it as a parameter, but I didn't find a way to do so or any documentation on the subject. Any hint or suggestion about this ?
Thank you for helping me here...
P.S. : I'm working with Visual Studio 2013, in case that could be relevant.
Here's a workaround I found and which allows to get a "RuntimeResourceSet" object, which is structurally close to a dictionnary (and which could be easily turned into one, if you specifically need a dictionnary) :
var myResourceSet = MyResource.ResourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, true);
Then, you can get the set's items this way :
var myString = myResourceSet.GetString("MyKey");
Hope that will help !
I am using 2 separators, and I re-create the dictionary by using split:
Dictionary<string, string> MyDictionary = Resource.MyResourceNme.Split(',').ToDictionary(x => x.Split('|')[0], x => x.Split('|')[1]);
MyResource would look like:
AUD|SYD,GBP|LON,JPY|TOK
Maybe there is a more efficient way of doing it (I don't like using twice the second split).
Related
I have a background in C++ and recently I started working in C#.
I have written following pieces of code (in Visual Studio):
var list_Loads = database.GetData<Load>().ToList();
var test_list = list_Loads.Where(o => (o.Name.Substring(0, 3) == "123")).ToList();
When I run the program and I move my mouse over both lists, first I get the count, which is very useful, but when I ask for the entries, this is what I get:
0 : namespace.Load
1 : namespace.Load
2 : namespace.Load
...
Not very useful, as you can imagine :-)
So my question: how can I show the Name attributes of those objects?
I thought: no problem. I have a background in native visualisers, so it should be rather easy to turn this into useful information, but then it comes:
In order to alter the way that those objects are represented, there is the first proposal to add a [DebuggerDisplay] "tag" to the definition of that class in source code.
However, as those classes are part of a framework I'm just referring to, I don't have access to the source code and hence I can't modify this.
Then I found another solution, which comes down to: "Write an entire C# project, debug, test and install it and it might work" (see documentation on "Custom visualisers of data" on the Microsoft website).
I almost choked in my coffee: writing an entire project, just for altering the view of an object??? (While, in C++, you just create a simple .natvis file, mention the classname and some configuration, launch .nvload and that's it.
Does anybody know a simple way to alter the appearance of C# object, without needing to pass through the whole burden of creating an entire C# project?
By the way, when I try to load a natvis file in Visual Studio immediate window, this is what I get:
.nvload "C:\Temp_Folder\test.natvis"
error CS1525: Invalid expression term '.'
What am I doing wrong?
Thanks in advance
OP (my emphasis):
In order to alter the way that those objects are represented, there is the first proposal to add a [DebuggerDisplay] "tag" to the definition of that class in source code.
However, as those classes are part of a framework I'm just referring to, I don't have access to the source code and hence I can't modify this.
Does anybody know a simple way to alter the appearance of C# object, without needing to pass through the whole burden of creating an entire C# project?
If you just want to specify [DebuggerDisplay] on a type, you don't have to have access to the source code. You can make use of [assembly:DebuggerDisplay()] and control how a type appears in the debugger. The only downside is that [assembly:DebuggerDisplay()] naturally only affects the current assembly whose code your mouse is hovering over. If you wish to use the customised display in other assemblies that you own, then you must repeat the [assembly:DebuggerDisplay()] definition.
Here's an easy before-and-after example with DateTime. I picked DateTime because we generally don't have access to the source code and it has some interesting properties:
var items = new List<DateTime>
{
DateTime.Now.AddDays(-2),
DateTime.Now.AddDays(-1),
DateTime.Now
};
...which on my machine defaults to:
Maybe I'm fussy and I just want to see:
Day of the week and
Day of the year
...I can do that via:
using System.Diagnostics;
[assembly: DebuggerDisplay("{DayOfWeek} {DayOfYear}", Target = typeof(DateTime))]
...which results in:
Example:
namespace DebuggerDisplayTests
{
public class DebuggerDisplayTests
{
public DebuggerDisplayTests()
{
var items = new List<DateTime>
{
DateTime.Now.AddDays(-2),
DateTime.Now.AddDays(-1),
DateTime.Now
};
}
}
.
.
.
}
Overrides
[assembly:DebuggerDisplay()] can also be used as a means to override pre-existing [DebuggerDisplay] on a 3-rd party type. Don't like what style they have chosen? Is the type showing far too much information? Change it with [assembly:DebuggerDisplay()].
I am trying to localize a hosted service in response to a runtime condition which is fed in a variable lang, which represents a 2-letter ISO code (such as 'en', 'es', ...).
I set the localization service in my Startup.cs like this:
services.AddLocalization(options => { options.ResourcesPath = "xresx"; });
In my controller I have the following code:
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(lang);
I know this works, because when I pass in lang='es' the following:
var check = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName;
returns the correct value check = 'es'.
But then the next statement:
var msg = Resources.TestMsg
picks up my the value from my English resource file Resource.resx instead of Resource.es.resx.
What am I doing wrong, and how can I make it work?
Thanks!
OK, so what ultimately worked for me was following exactly the steps in this guide: https://joonasw.net/view/aspnet-core-localization-deep-dive
This link is the only source I've found that worked for me, and it was better than Microsoft's own documentation (which omits potential pitfalls like not naming your Resource files a very certain way).
Let me summarize some points:
One needs to inject IStringLocalizer into their controller, eg:
IStringLocalizer<MyController> _localizer;
Then inside the controller you can localize your strings, eg:
_localizer["STRINGKEY"]
where STRINGKEY is a key from your resource file.
Make sure to name your resource files properly. This is very important and is not documented by Microsoft as far as I know! Cost me a lot of time until I stumbled over the web link I've referenced above.
I was naming my files like this:
Resource.resx, Resource.es.resx etc
and the localized wasn't finding the values, instead just returning the key itself.
Eg, _localizer["STRINGKEY]" would return "STRINGKEY" rather than the corresponding value in the resource file.
So you must name your files instead using your Controller's name, like this:
Controllers.MyController.resx, Controllers.MyController.es.resx
These are the main points to remember. Sadly, Microsoft documentation glosses over a lot of this stuff.
I'm actually pursuing a way to create csv file which records could vary on type and order. They are defined by the user on both ways and I'm actually handling their types safely.
I loved using FileHelpers library in order to read/write files on C# since it's fast, reliable and trustable, so I was wondering how could I perform this export operation using it, and reviewing questions like this one the evil part comes when needing to populate the class with the desired values, so I could write the file. All the related questions are focusing on reading registries and I need to write them.
Am I right thinking that I might need to use Reflection so I could roam this new type and its properties or is there any way to "add a record" specifying the value while creating the fields?
This FileHelpers way was an option and of course the second one was doing this manually, but I was curious if there is an easier way.
var builder = new DelimitedClassBuilder("DynamicDocument", ";");
builder.AddField("Date", typeof(DateTime));
var dynamicType = builder.CreateRecordClass();
//...
Using the class builders is the best way to do this with FileHelpers. You do need to keep a copy of the type that is created so it can be used by your generic classes.
Just remember, that you must do all the work before calling CreateRecordClass() as that then generates the type.
Here is a link to another S/O question with a whole bunch of code that shows how to do it: FileHelpers.Dynamic.ClassBuilder.CreateRecordClass Error
Now, if you are working purely with properly formatted files, you can let FileHelpers do all that work for you as long as they are always properly delimited and you handle any type conversion based on the column name.
I need a way to insert (or use an already implemented property that could serve as) a unique identifier into a Microsoft.Office.Interop.Excel.ListObject instance.
The problem is that when I'm creating a new ListObject as:
var excelTable = worksheet.ListObjects.Add(ExcelInterop.XlListObjectSourceType.xlSrcExternal, DUMMY_CONNECTIONSTRING, false, true, cellRange);
I cannot rely on the Name property of excelTable to browse for it in the collection since the user could change the value of that property anytime afterwards.
After browsing trough the object properties I found nothing I could use out of the box (like a Tag property for example, which exists in a Microsoft.Office.Tools.Excel.ListObjecttype of object I cannot use at this point due to dependencies) ...and other weird stuff like a DisplayName that appears not only unable to be set directly but also to reflect the exact same value that the Name property has at all times (Why would you want to have 2 properties that reflect the same value at any time?).
I've thought on either creating my own implementation of this class or probably use the Comment property to store a GUID (which I don't know why kinda feels wrong):
excelTable.Comment = Guid.NewGuid().ToString();
Can you suggest of another way to accomplish this task?
Thanks a lot!
It is quite frustrating that there is no "Tag" (or similar) property that you could set on Excel objects. I'm facing the same issues as you. Here are two options that you can use:
alternative text property (for the table it is only visible by right clicking the table, selecting table and alternative text). This is probably a bit cleaner than Comment since the UI for comment is always visible.
you could also generate a wrapper object that contains a direct reference to the ListObject. So one wrapper object for each created ListObject. This works fine until you save / open the workbook again. If you need to be able to identify the table again after reopening the workbook you would still need to write some id to Comment or Alternative text. You could probably do a clean implementation by using events like BeforeSave and AfterSave (add alternative text before save so it saves to disk, then remove it again after save so that the user doesn't see it. When the workbook opens you load up your wrapper objects and remove the alternative text).
I've got an object called "Communication" that has a method to "CreatePdfFromTemplate". This method is going to be called from a Windows Service that has a SqlDependancy on a table that will notify when a new row is added by a method on a website.
Into my method, I pass a list of custom objects that have an "Id" and a "Name". The name, is the name of the object I need to load using reflection. For example, "Instruction". The "Id" is the Id of the object referred to in "Name" that needs to be loaded from the database. This object is not referenced or available in the runtime of my "Communication" DLL.
I'm currently falling at the first hurdle. I am trying to do the following as a first step:
// Load object information using Reflection
Type objectType = Assembly.GetExecutingAssembly().GetType(queueObject.Name);
int objectId = queueObject.Id;
I have found some info from my searches for answers that say there is a way to load a DLL by making it available in the application cache or the GAC, but I wasn't sure if this was the best way to go.
I've never used Reflection before so if you have any advice on it, or any advice on the way I have chosen to structure this in general (i.e. website adds row to DB table, SqlDependancy in Windows Service fires, calls to Communication service DLL to create PDF).
Just to give you some more information, the reason I have chosen to do it like this, is because my templates contain tags such as {Instruction.CreatedDate} where "Instruction" is the name of the object and "CreatedDate" is the name of a property, the value of which will replace the tag.
Any help on how to load this "Instruction" object in my Reflection or just on my structure in general is much appreciated. Let me know if I haven't given enough info or if what I've said isn't clear enough (this is my first StackOverflow question, although I am a long time lurker).
Thanks.
--UPDATE--
Ok, using the idea put forward from Maarten, I have managed to load my assembly and get a type from it, but I've done it slightly differently. I wasn't able to put in a specific path using the Assembly.LoadFile method, so I've done it like this:
Assembly executingAssembly = Assembly.GetExecutingAssembly();
Assembly objectAssembly = Assembly.Load(executingAssembly
.GetReferencedAssemblies()
.Where(a => a.Name == "Common")
.FirstOrDefault());
This works because the Type I am trying to get, is part of a referenced assembly in my Communication service called "Common" (which is an installed package using nuget to help keep it up to date, as it changes quite often).
Any further posts on how I'm doing this and if it's the right or wrong way would be appreciated though!
Load the assembly using Assembly.LoadFile or another overload.
Get the type using Assembly.GetType.
Use the Activator.CreateInstance once you have the type.
Cast it to dynamic, and call your method, or set your property. I'm assuming you are using .net 4.0.
var myAssembly = Assembly.LoadFile(...);
var myType = myAssembly.GetType(...);
dynamic myObject = Activator.CreateInstance(myType);
if (myObject != null) {
var createdDate = myObject.CreatedDate;
}