c# pattern to avoid using switch statement for repeated similar logic - c#

I have a c# application where I need to return translated keypair value for different views.
For example, these are some of my views:
login
admin account
admin settings
admin employee
admin holiday
and so on.
Then every view call the same method for returning a dictionary of translation strings.
public ActionResult GetTranslations(string viewName)
{
// THIS IS A SAMPLE OF HOW TO GET THE TRANSLATIONS
Dictionary<string, string> translations = new Dictionary<string, string>
{
{ "usernamerequired", HttpContext.GetText("The user name is required","") },
{ "passrequired", HttpContext.GetText("The password is required", "") },
};
string json = JsonConvert.SerializeObject(points, Formatting.Indented);
var response = new JsonResponse
{
data = translations ,
message = "",
num = 0,
success = true,
code = null
};
return Json(response, JsonRequestBehavior.AllowGet);
}
So in order to avoid using "n" amount of Switch statements like:
Dictionary<string, string> translations = null;
switch(viewName)
{
case "login":
// specific translation for login
translations = new Dictionary<string, string>
{
{ "usernamerequired", HttpContext.GetText("The user name is required","") },
{ "passrequired", HttpContext.GetText("The password is required", "") },
};
break;
// HERE OTHER CASES FOR THE OTHER VIEWS
}
Instead I would like to use a cleaner way, I was thinkin on having an interface like:
// Interface
interface ITranslation
{
Dictionary<string, string> GetViewTranslations();
}
// Login translation class
class LoginTranslation: ITranslation
{
public Dictionary<string, string> GetViewTranslations()
{
// here the dictrionary generation code..
}
}
// Admin Settings translation class
class AdminSettingsTranslation: ITranslation
{
public Dictionary<string, string> GetViewTranslations()
{
// here the dictrionary generation code..
}
}
Of maybe there is a better and cleaner way, any advice or clue?

Related

Append to list in DynamoDB(C#)

I have a Dynamo table of US states and each state has a list of businesses. The structure is as follows:
{"Name": {S: "Ohio"},"Businesses":{"L": [ { M: {"Name":{"S":"McDonalds"}}, { M: {"Name":{"S":"IHOP"}} ] }
My goal is to write a function that can take a list of businesses and IF they don't exist already append them to the list of businesses, I have gotten this far:
public async Task UpdateStatesBusinessList(Buisness buisness)
{
var dynamoRequest = new UpdateItemRequest
{
Key = new Dictionary<string, AttributeValue>
{
{"Name", new AttributeValue{S = buisness.Name}}
},
ExpressionAttributeNames = new Dictionary<string, string>
{
{"#B", "Businesses" }
},
ExpressionAttributeValues = new Dictionary<string, AttributeValue>
{
{":B", new AttributeValue{L = business.Businesses}};
}
}
}
Public class Business
{
public string Name {get; set;}
}
We can pretend I have a hard coded list of businesses like:
BusinessList = new List<Business>
{
new Buisness {Name = "Chilis"}, new Buisness {Name = "BurgerKing"},etc...
}
I know I need to use an update expression with SET and use the if_not_exists() with list_append(). I need help constructing the request because my ExpressionAttributeValue is not correct... Any advise would be great, I have looked through all the AWS documentation and countless websites and have not been able to get it to work.

Map [name,value] string values to class without reflection

I'm having a huge performance issue about mapping string property names and string property values to classes using reflection.
My issue now:
public class Person
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public string Property4 { get; set; }
// My class has around 100 properties
public string Property100 { get; set; }
}
I am mapping a key value pair collection to the class using reflection
[{"Property1": "some value"}, {"Property2": "something else"},{"Property3","Property4","value" }.....{"Property100","val"}]
It got to the point that I am now mapping around 10 000 class instances using reflection and the performance is to say it lightly bad.
Any ideas for eliminating the reflection would be greatly appreciated.
I see two options, if you need to avoid reflection for tasks like this(when code could be programatically generated).
First is Expressions I use it often, e.g. I saw some people write something like this
public class A
{
public Prop1 ...
....
public Prop100
public override ToString() => $"{nameof(Prop1)}={Prop1};...";
and so for all 100 properties, and always doing this manually.
And with Expression it can be easily automated, you just need to generate Expression for String.Concat and pass list of properties and names there.
For your example, it is not clear what are your data. How do you do lookup in the list?
Let's assume there is a dictionary<string,string>(you can transform your list of tuples to a dictionary), and all properties are strings as well.
Then we would need to generate a list assignment expressions like this
if(data.ContainsKey("Prop1")) result.Prop1 = data["Prop1"];
And the code would be complicated, anyway it would look like this
private static class CompiledDelegate<T>
{
public static Action<T, Dictionary<string, string>> initObject;
static CompiledDelegate()
{
var i = Expression.Parameter(typeof(Dictionary<string, string>), "i");
var v = Expression.Parameter(typeof(T), "v");
var propertyInfos = typeof(T).GetProperties().ToArray();
var t = new Dictionary<string, string>();
var contains = typeof(Dictionary<string, string>).GetMethod(nameof(Dictionary<string, string>.ContainsKey));
var getter = typeof(Dictionary<string, string>).GetProperties().First(x => x.GetIndexParameters().Length > 0);
var result = new List<Expression>();
foreach (var propertyInfo in propertyInfos)
{
var cst = Expression.Constant(propertyInfo.Name);
var assignExpression =
Expression.IfThen(Expression.Call(i, contains, cst),
Expression.Assign(Expression.PropertyOrField(v, propertyInfo.Name), Expression.MakeIndex(i, getter, new[] { cst })));
result.Add(assignExpression);
}
var block = Expression.Block(result);
initObject = Expression.Lambda<Action<T, Dictionary<string, string>>>(block, new ParameterExpression[] { v, i }).Compile();
}
}
It is an example, it would fail if there were non-string properties.
And it could be used like this
static void Main(string[] args)
{
var tst = new Test();
CompiledDelegate<Test>.initObject(tst, new Dictionary<string, string>
{
{ "S3", "Value3" },
{ "S2", "Value2" },
});
CompiledDelegate<Test>.initObject(tst, new Dictionary<string, string>
{
{ "S3", "Value3" },
{ "S1", "Value1" },
});
Console.ReadKey();
}
The second option is, actually, what it should be ideally imlemented like Using source generators I think such things do have to be done just in build time.
There is a lot of articles on msdn, for instance with samples. But it turned out to be not very easy to implement, even just a sample.
I can say, it didn't work for me, while I tried to do it according to samples.
In order to get it work I had to change TargetFramework to netstandard2.0, do something else...
But after all, when build was green, Visual Studio still showed an error.
Ok, it disappeared after VS restart, but still, that doesn't look very usable.
So, this is a generator, that creates a converter for every class with attribute.
It is again a sample, it doesn't check many things.
[Generator]
public class ConverterGenerator : ISourceGenerator
{
private static string mytemplate = #"using System.Collections.Generic;
using {2};
namespace GeneratedConverters
{{
public static class {0}Converter
{{
public static {0} Convert(Dictionary<string, string> data)
{{
var result = new {0}();
{1}
return result;
}}
}}
}}";
public static string GetNamespaceFrom(SyntaxNode s)
{
if (s.Parent is NamespaceDeclarationSyntax namespaceDeclarationSyntax)
{
return namespaceDeclarationSyntax.Name.ToString();
}
if (s.Parent == null)
return "";
return GetNamespaceFrom(s.Parent);
}
public void Execute(GeneratorExecutionContext context)
{
GetMenuComponents(context, context.Compilation);
}
private static void GetMenuComponents(GeneratorExecutionContext context, Compilation compilation)
{
var allNodes = compilation.SyntaxTrees.SelectMany(s => s.GetRoot().DescendantNodes());
var allClasses = allNodes.Where(d => d.IsKind(SyntaxKind.ClassDeclaration)).OfType<ClassDeclarationSyntax>();
var classes = allClasses
.Where(c => c.AttributeLists.SelectMany(a => a.Attributes).Select(a => a.Name).Any(s => s.ToString().Contains("DictionaryConverter")))
.ToImmutableArray();
foreach (var item in classes.Distinct().Take(1))
{
context.AddSource(item.Identifier.Text + "Converter", String.Format(mytemplate, item.Identifier.Text, SourceText.From(GenerateProperties(item)), GetNamespaceFrom(item)));
}
}
private static string GenerateProperties(ClassDeclarationSyntax s)
{
var properties = s.Members.OfType<PropertyDeclarationSyntax>();
return String.Join(Environment.NewLine,
properties.Select(p =>
{
var name = p.Identifier.Text;
return $"if(data.ContainsKey(\"{name}\")) result.{name} = data[\"{name}\"];";
}));
}
public void Initialize(GeneratorInitializationContext context)
{
}
}
and
static void Main(string[] args)
{
var t1 = GeneratedConverters.TestConverter.Convert(new Dictionary<string, string>
{
{ "S3", "Value3" },
{ "S2", "Value2" },
});
}
Best performance without reflection would be manual mapping.
It seems your key/value pair collection is regular JSON. So you could use the JSONTextReader from JSON.NET and read the string. Then manually map the JSON properties to the class properties.
Like so:
JsonTextReader reader = new JsonTextReader(new StringReader(jsonString));
while (reader.Read())
{
if (reader.Value != null)
{
// check reader.Value.ToString() and assign to correct class property
}
}
More info can be found on the JSON.NET website : https://www.newtonsoft.com/json/help/html/ReadingWritingJSON.htm

Unsure how to define a C# class to handle JSON with variable property names

I am calling a REST api that returns their data in the following format:
{
"facets": [
{
"M": 100
},
{
"F": 210
}
]
}
I am not sure how to define a C# class that maps to this JSON since the M/F property name could be anything. This is currently a facet for gender, but for something else like language it might be "English", "Spanish", "Japanese", etc. Ideally I would like something like a dictionary.
Where the keys can vary, use a dictionary to represent the object:
public class Criteria
{
public List<Dictionary<string, int>> facets { get; set; }
}
(If the dictionary value isn't always an int, use object instead.)
Fiddle: https://dotnetfiddle.net/IwyXby
This is how I use json.net to both serialize and deserialize:
public static bool SerializeStudentsFile(string fileStorageLoc)
{
var jsonStudents = JsonConvert.SerializeObject(StudentsList);
System.IO.File.WriteAllText(fileStorageLoc, jsonStudents);
return true;
}
public static List<Student> DeserializeStudentsFile()
{
List<Student> studentList;
if (!System.IO.File.Exists(STUDENTS_FILENAME))
{
var studentFile = System.IO.File.Create(STUDENTS_FILENAME);
studentFile.Close();
}
var studentContentsFile = System.IO.File.ReadAllText(STUDENTS_FILENAME);
var studentContentsFileDeserialized = JsonConvert.DeserializeObject<List<Student>>(studentContentsFile);
if (null != studentContentsFileDeserialized) return studentContentsFileDeserialized;
studentList = new List<Student>();
return studentList;
}

How to get item from dictionary by value of property

I have a Dictionary<string, User>.
User is an object with the properties UID, UNIQUE KEY and more. My dictionary key is the UNIQUE KEY of the users.
Now, i want to get a User from my dictionary values by a UID and not the key, something like ContainsKey.. how its done with lambda expr or linq? is there a good solution for that?
Here's a working sample:
using System;
using System.Collections.Generic;
using System.Linq;
internal class User
{
public string ID { get; set; }
public string Name { get; set; }
}
internal class Program
{
private static void Main(string[] args)
{
Dictionary<string, User> dic = new Dictionary<string, User>();
dic.Add("1", new User { ID = "id1", Name = "name1" });
dic.Add("2", new User { ID = "id2", Name = "name2" });
dic.Add("3", new User { ID = "id3", Name = "name3" });
User user = dic.Where(z => z.Value.ID == "id2").FirstOrDefault().Value;
Console.ReadKey();
}
}
return dict.Single(x => x.Value.UID == target);
Of course, you might find that your design is questionable if it involves continually doing linear searches across a Dictionary.
Of course you'll loose the benefit of having a dictionary, but you can do someting like:
var user = dict.Values.FirstOrDefault(k=>k.UID==xxxx);
This should get the user for the UID from the dictionary:
public User GetUserForUid(Dictionary<string, User> dictionary, int uid)
{
return dictionary.Values.FirstOrDefault(u => u.UID == uid);
}

Refactoring Many Methods into One

I dont know how to name the question properly, so fell free to change it. My question is, I have around 10 methods that look like:
[WebMethod(EnableSession = true)]
public string ReadUserAdditional()
{
EUser user = (EUser)Session["user"];
var json = new { result = true, user.Image, user.Biography };
return new JavaScriptSerializer().Serialize(json);
}
[WebMethod(EnableSession = true)]
public string ReadUserBasicInformation()
{
EUser user = (EUser)Session["user"];
var json = new { result = true, user.Name, user.Username};
return new JavaScriptSerializer().Serialize(json);
}
The methods are very similar, but they return different fields. Im thinking about refactoring all methods into one, receveing the fields to return as parameters. Is it a good idea? How can I do that? Reflection?
First of all you need to know that object and dictionary are presented in json simmilar.
[WebMethod(EnableSession = true)]
public string ReadUserAdditional()
{
return GetUserInfo(new []
{
new FieldInfo {Name = "Image", u => u.Image},
new FieldInfo {Name = "Biography", u => u.Biography}
});
}
private string GetUserInfo(FieldInfo[] infos)
{
EUser user = (EUser)Session["user"];
var dict = new Dictionary<string, object>{ { "result", true } };
foreach(var info in infos)
{
dictionary.Add(info.Name, info.Accessor(user));
}
return new JavaScriptSerializer().Serialize(dict );
}
public class FieldInfo
{
public Func<EUser, object> Accessor { get; set; }
public string Name { get; set;}
}
I don't think it's a terrible idea, especially if you have tons of these methods and want to simplify your API.
A few downsides:
1) Reflection comes at a perf cost. This probably doesn't matter a whole lot unless you're the size of Twitter.
2) There would potentially be security concerns if the data had any properties you do NOT wanting users getting access to, such as some sort of internal database keys or what not. Make sure every property on your class is one you're totally okay becoming public information.
You can use a lambda to refactor away the duplication:. This would reduce all your methods to a single line of code:
[WebMethod(EnableSession = true)]
public string ReadUserAdditional()
{
return GetUserJSON(x => new { result = true, x.Image, x.Biography });
}
[WebMethod(EnableSession = true]
public string ReadUserBasicInformation()
{
return GetUserJSON(x => new { result = true, x.Name, x.UserName });
}
private string GetUserJSON(Func<EUser, string> jsonFields)
{
EUser user = (EUser)Session["user"];
var json = jsonFields(user);
return new JavaScriptSerializer().Serialize(json);
}
Another approach is to use Automapper or similar library to project your data.
[WebMethod(EnableSession = true)]
public string ReadUserAdditional()
{
return GetUserInfo<UserAdditionalDto>();
}
private string GetUserInfo<TDto>(FieldInfo[] infos)
{
EUser user = (EUser)Session["user"];
var dto = Mapper.Map<TDto>(user); // Mapper is Automapper entry class.
return new JavaScriptSerializer().Serialize(dto );
}
public class UserAdditionalDto
{
public string Image { get; set; }
public string Biography { get; set;}
}

Categories

Resources