Retrieve class name hierarchy as string - c#

Our system complexity has risen to the point that we need to make permission names tied to the client from the database more specific. In the client, permissions are referenced from a static class since a lot of client functionality is dependent on the permissions each user has and the roles have a ton of variety. I've referenced this post as an example, but I'm looking for a more specific use case. Take for instance this reference, where PermissionAlpha would be a const string:
return HasPermission(PermissionNames.PermissionAlpha);
Which is great, except now that things are growing more complex the classes are being structured like this:
public static class PermissionNames
{
public static class PermissionAlpha
{
public const string SubPermission = "PermissionAlpha.SubPermission";
}
}
I'm trying to find an easy way to reference PermissionAlpha in this new setup that will act similar to the first declaration above. Would the only way to do this be to resort to pulling the value of the class name like in the example below? I'm trying to keep all the names in one place that can be reference anywhere in the application.
public static class PermissionAlpha
{
public static string Name { get { return typeof(PermissionAlpha).Name; } }
}
** Edit ** - Added missing permission name.

Maybe this would be too big of a change for you with the size of your project, but we have all of our business objects split into partial classes. One is for manual changes and one gets generated. During code-generation, we write the permission keys into the generated side of the partial classes from our "single source of truth". We're using a set of classes as our source of truth and CodeDom to generate, but you could also use a database as your source and use T4, CodeSmith, or others to generate.

Why not create reflectable attribute(s) on the classes in question? That way one can add all the extra information required. I provide a way of divining attributes on my blog article entitled:
C# Using Extended Attribute Information on Objects
HTH

Related

How to reuse classes when generating an OpenAPI client?

Let's say I have this class defined:
public class Animal
{
public int RegId {get;set;}
public string Name {get;set;}
}
And I need to expose it to an remote part of my system ( a client app in another location, for example ) and I decided to use OpenAPI to make the communication.
The controller code is something like:
[HttpGet("GetLivingCargo")]
public async Task<IEnumerable<Animal>> GetLivingCargo()
{
return await pFacade.GetLivingCargo();
}
Swagger generates the documentation all well.
When I generate the API client to use in the remote app, all times I have that class duplicated (so there's my original class and the generated client's exactly equal class).
How I can avoid it, without having to manually write the API client myself to use my original class?
Finally I found a way to make NSwagStudio reuse my Model classes.
Step-by-Step:
Get the OpenAPI spec URL
Make it create an local copy to double check if is the correct spec
Mark "C# Client" on Outputs section of the screen (cannot put an image now because the firewall blocks ImgUr.com)
On Settings tab, two configuration need to be changed:
Additional Namespace Usages: put the namespace list of the classes you want to reuse (comma-separated)
Generate DTO Types: UNCHECK
Generate.
For those who do not want an all-or-nothing approach, with Generate DTO Types checked, you can exclude certain types by filling the (comma-separated) list of types to be excluded in Exclude Type Names configuration setting.

Alternatives to reference to parent class

I am creating an inf file parser (windows drivers, in theory similar to infs, in reality quite different).
I have a parent InfFile class which contains the structured but unparsed data in the form of Sections and Keys (I call it unparsed because it's not been converted into anything more useful than just Sections and Keys, as oppose to the rest of the data that comes after), but also gives access to some parsed data, such as SupportedOperatingSystems, Folders, Folder.Files etc.
The problem I'm facing is that in inf file can reference 4 types of Folders: default, X86, Ia64 and Amd64. So, it felt logical to me to try to shift all of the folder related code to a InfFolders class, with properties Default, X86, Ia64 and Amd64 (I can't simply merge them).
However, in order to figure out which folders are referenced in it, I need access to both the Sections and Keys properties of the InfFile class. That means either:
my InfFolders class contains a reference to its parent (which I think is probably not the best solution),
InfFile parses the data first and then passes it to the InfFolders as part of the constructor, but that means all of the Folder logic now lives in the InfFile class again,
I pass the needed Sections and Keys to InfFolders as part of the constructor, and have the logic to sort them into usable objects in there.
What is the best way to do this and what is best practice in situations like this?
An idea of what the InfFolders class looks like is this:
public class InfFolders
{
public IReadOnlyCollection<InfSourceFolder> Default()
{
return GetFolders("SourceDiskNames").ToList().AsReadOnly();
}
public IReadOnlyCollection<InfSourceFolder> X86()
{
return GetFolders("SourceDiskNames.X86").ToList().AsReadOnly();
}
public IReadOnlyCollection<InfSourceFolder> Ia64()
{
return GetFolders("SourceDisksNames.Ia64").ToList().AsReadOnly();
}
public IReadOnlyCollection<InfSourceFolder> Amd64()
{
return GetFolders("SourceDisksNames.Amd64").ToList().AsReadOnly();
}
private IEnumerable<InfSourceFolder> GetFolders(string sectionName)
{
return <InfFile reference>[sectionName]?.Keys?.Select(
x =>
new InfSourceFolder(Convert.ToInt32(x.Name),
new FileInfo(<InfFile reference>.FilePath).DirectoryName + x.Values.ElementAtOrDefault(3)));
}
}
As you can see in the method GetFolders() there are 2 places where a reference to the parent is needed.
I could shift all of this code to InfClass and remove the InfFolders class altogether, but don't think that makes for a very good model either. The way I see it is there 4 properties all relate to the same thing, so they should be grouped together.

AutoFixture & AutoMoq: Overriding object generation behavior

I'm proposing using AutoFixture and AutoFixture.xUnit at our company, and have gotten the mandate that for certain objects and fields they want random data that is formatted in an expected way. For example, they want PersonName to only populate with realistic names (instead of GUIDs) and PhoneNumber to only make strings that look like phone numbers. But they DON'T want to add data annotations to the actual objects enforcing this, they would just like the test data generated by AutoFixture to be pretty.
I've dealt a bit with ICustomize classes to implement greedy constructor behavior on a few classes. Is there a similar way to override the data generation for specific objects? To (for example) pull names from a list, or generate data to follow a certain regular expression? (keeping in mind that I can't actually add those regular expressions as attributes on the model)
Ok, solved my problem.
Object generation for a given class type can be accomplished via the Fixture.Register method. You can make a method that returns the type you want to override and that will be used instead of the default.
To get meaningful data I just used Faker.Net.
I got the solution Mark pointed out working, and really liked it for general POJOs, but in my case many of my objects had properties that could only be set via the constructor or aggregate setters (like ChangeContactInfo), so unfortunately I needed something a bit more targeted. Here is an example of my solution implementing a name and address generation override:
public class CustomObjectGeneration : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Register(GenerateAddress);
fixture.Register(GeneratePersonName);
}
private Address GenerateAddress()
{
return new Address(Faker.Address.StreetAddress(), Faker.Address.SecondaryAddress(), Faker.Address.City(),
Faker.Address.ZipCode(), Faker.Address.UsState(), Faker.Address.Country());
}
private PersonName GeneratePersonName()
{
return new PersonName(Faker.Name.Prefix(), Faker.Name.First(), Faker.Name.First(), Faker.Name.Last(), Faker.Name.Suffix());
}
}

Dynamic localization of messages

I have made a simple localization of messages. All messages are stored in the static class Lng
public static partial class Lng
{
public static readonly string AppName = "My application";
public static class Category1
{
public static readonly string ConfirmDelete = "Are you sure want to delete?";
}
}
In code usage is as simple as referencing fields
MessageBox.Show(Lng.Category1.ConfirmDelete, ...
Then there is a manager, which does following:
language selection
load corresponding translation
updating fields via reflection
export currently selected language on application exit for an update (in case if default language is selected - to create first translation for any other language)
It's irrelevant of how language files looks likes, but here is a reflection part
TranslateLng("Lng.", typeof(Lng));
...
private static void TranslateLng(string parent, Type type)
{
foreach (Type nested in type.GetNestedTypes())
{
string child = string.Format("{0}{1}.", parent, nested.Name);
TranslateLng(child, nested);
foreach (var field in nested.GetFields())
{
string key = child + field.Name;
DefaultAdd(key, (string)field.GetValue(null)); // store value in default language dictionary (if not created yet)
field.SetValue(null, GetValue(key)); // get value for currently selected language
}
}
This system has one problem: all messages are defined in one class, which required manual management (deleting and updating messages when updating code which uses them).
And I was thinking to change manager to register strings dynamically and simplify usage to something like
MessageBox.Show(Lng.Text("Are you sure want to delete?"), ...
So that text is defined right where it used, duplicated text can be handled by manager and so on.
There are however 2 problems:
I will need a complete list of all messages at the end of application run to export complete list of messages (for currently selected language). What if some of Lng.Text() are never called at that run? Is there a way to register them as they are used in code (compile time?)? So that all calls will be registered somehow, even if peace of code is never used.
How to generate key. I could use CallerMemberName, but right key are more useful, as they are telling exact purpose. To example, Lng.Configuration.Appearance.CaptionText. I could call Lng.Text(key, message), but then I have to manage keys, ensure in their uniqueness, which doesn't appeals me.
I recently worked on a project with internationaliztion and we used Resources in con junction with the Sisulizer program with great success. Having the resources solves your key problem as you manually enter the key when you extract the resources. You also get great support from Resharper which makes the whole process a breeze.
Sisulizer is then used to extract resources as well as strings hard-coded in our Win Forms and WPF classes. It can export a CSV which you can give your translators and it also supports pseudo translation, which makes testing such apps very easy as well.

How to use the ConfigurationManager to store structured data?

I can use the .Net ConfigurationManager to store strings, but how can I store structured data?
For example, I can do this:
conf = ConfigurationManager.OpenExeConfiguration(...)
string s = "myval";
conf.AppSettings.Settings["mykey"].Value = s;
conf.Save(ConfigurationSaveMode.Modified);
And I would like to do this:
class myclass {
public string s;
int i;
... more elements
};
myclass c = new myclass(); c.s = "mystring"; c.i = 1234; ...
conf.AppSettings.Settings["mykey"] = cc;
conf.Save(ConfigurationSaveMode.Modified);
How do I store and retrieve structured data with the ConfigurationManager?
I implemented a solution as #sll suggested. But then difficulty was to create a new section to the configuration. Here is how this is done:
How to Write to a User.Config file through ConfigurationManager?
You can create own configuration section type by inheriting from ConfigurationSection class and use it to save/load any custom type information.
MSDN: How to: Create Custom Configuration Sections Using ConfigurationSection
BTW, One advice which might be helpful for you or others: One good thing is making custom configurations section class immutable (no public setters) so you can be sure that configuration cannot be changed on any stage of application life cycle, but then if you decide writing unit tests for code which relies on configuration section class and need section stub with some test values you might stuck with abilty to set property values since there is no setters. Solution is providing a new class which is inherited from your section class and specifying in constructor values using protected indexer like show below:
public class TestSectionClass: MyConfigurationSection
{
public TestSectionClass(string testUserName)
{
this["userName"] = testUserName;
}
}
Serialization.
There are numerous different ways of serializing data, so you'd need to pick one. But .NET provides a serialization API that suits a great many cases, and in working with web AJAX calls recently I find myself using JavaScriptSerializer heavily to turn things into JSON. However there are third party libraries such as protobuf-net, and so on.
The key here is to essentially turn your data into a byte or string representation that can later be deserialized back to its original structure at a later date, allowing you to store it in a medium between then, such as in configuration files or transmission over networks etc.
As per #sll's answer, .NET has another facet meaning it can handle serialization of data in and out of custom configuration sections; whether you want to begin specifying types explicitly for this purpose or not is your call. Bottom line is the same, serialize, somehow.

Categories