I have two enums, the source one is with responses from api and another one is what I want to send to frontend.
public enum ApiResponse
{
A=1,
B=2,
C=3,
D=4
}
public enum DestEnum
{
A=1,
BCD=2
}
What I am trying to do is:
public class ExampleViewModel
{
public DestEnum foo { get; set; }
}
var response = ApiResponse.C;
result = new ExampleViewModel()
{
foo = response
};
And I want foo value to be DestEnum.BCD
Is it possible to do with automapper or some custom attributes?
Assuming you've set your serializer up to send strings already you seem to be just looking for a way to map an X to a Y
How about:
public static class EnumExtensions{
static Dictionary<ApiResponse,DestEnum> _mapDest =
new() {
[ApiResponse.A] = DestEnum.A,
[ApiResponse.B] = DestEnum.BCD,
[ApiResponse.C] = DestEnum.BCD,
[ApiResponse.D] = DestEnum.BCD,
};
public static DestEnum AsDest(this ApiResponse x) => _mapDest[x];
}
And then you can convert the ApiRespnse you got to a Dest like:
return new BlahViewModel{
DestEnumProperty = apiResponseEnumValueIGot.AsDest(),
OtherProp = ...
}
Warning, the lookup will blow up if you get any values that aren't mapped; if you think this will ever be possible, consider having an Unknown value in your DestEnum and doing something like:
=> _mapDest.TryGetValue(x, out var r) ? r : DestEnum.Unknown
I'm getting an irregular JSON array from the Census Bureau's public api.
The variable names are all in the first element, and I'm having trouble deserializing it.
http://api.census.gov/data/2014/pep/agesex?get=AGE,POP,SEX&for=us:*&DATE=7
gives me JSON like this:
[["AGE","POP","SEX","DATE","us"],
["0","3948350","0","7","1"],
["1","3962123","0","7","1"],
["2","3957772","0","7","1"],
["3","4005190","0","7","1"],
["4","4003448","0","7","1"],
["5","4004858","0","7","1"],
["6","4134352","0","7","1"],
["7","4154000","0","7","1"]]
I can successfully deserialize this using:
var test1 = JsonConvert.DeserializeObject<String[][]>(jsonStr);
However, I'm trying to deserialize it to a class like this:
public class TestClass
{
public string AGE { get; set; }
public string POP { get; set; }
public string SEX { get; set; }
public string DATE { get; set; }
public string us { get; set; }
}
I'm trying to do this:
var test2 = JsonConvert.DeserializeObject<TestClass[]>(jsonStr);
But I'm getting the following exception:
An exception of type 'Newtonsoft.Json.JsonSerializationException'
occurred in Newtonsoft.Json.dll but was not handled in user code
Additional information: Cannot create and populate list type
TestClass. Path '[0]', line 1, position
2.
There's two parts to this.
First is turning the JSON in to data usable in C#, and the second is turning that data in to nice objects.
Here's a working dotNetFiddle.net example of the following code: https://dotnetfiddle.net/Cr0aRL
Each row in your JSON is made up of an array of strings.
So that's an array of an array of strings.
In C# that can be written as string[][].
So to turn the JSON in to usable data with JSON.Net you can do:
var json = "[[\"AGE\",\"POP\",\"SEX\",\"DATE\",\"us\"],[\"0\",\"3948350\",\"0\",\"7\",\"1\"],[\"1\",\"3962123\",\"0\",\"7\",\"1\"],[\"2\",\"3957772\",\"0\",\"7\",\"1\"],[\"3\",\"4005190\",\"0\",\"7\",\"1\"],[\"4\",\"4003448\",\"0\",\"7\",\"1\"],[\"5\",\"4004858\",\"0\",\"7\",\"1\"],[\"6\",\"4134352\",\"0\",\"7\",\"1\"],[\"7\",\"4154000\",\"0\",\"7\",\"1\"]]";
var rawData = JsonConvert.DeserializeObject<string[][]>(json);
Next up is is turning that data in to objects.
The first row is the header, containing the column names, so we want to grab that, and then figure out the column index for each column name.
var headerRow = rawData.First();
var ageIndex = Array.IndexOf(headerRow, "AGE");
var popIndex = Array.IndexOf(headerRow, "POP");
var sexIndex = Array.IndexOf(headerRow, "SEX");
var dateIndex = Array.IndexOf(headerRow, "DATE");
var usIndex = Array.IndexOf(headerRow, "us");
Now we have the indexes, we need to take each row, and convert it in to the appropriate object. I've used LINQ for this as it's very good at representing data processing in a clear way.
var testData = rawData
.Skip(1) //The first row is a header, not data
.Select(dataRow => new TestClass()
{
AGE = dataRow[ageIndex],
POP = dataRow[popIndex],
SEX = dataRow[sexIndex],
DATE = dataRow[dateIndex],
us = dataRow[usIndex]
});
Finally a bit of testing, to make sure you have the data you're expecting.
//Get the second data row as an example
var example = testData.Skip(1).First();
//Output example POP to check value
Console.WriteLine(example.POP);
Everything above is very manual.
You have to know what headers you expect, then you manually find the indexes, then you manually map the rows to objects.
It's quite possible for a simple use case that doing that is fine. But in larger and/or more complex systems you might want/need to automate those steps.
Automating those steps is possible, but is beyond the scope of this answer as how you approach it can depend on a lot of different factors.
You could make a custom JsonConverter to handle this conversion during deserialization. The conversion code is really not much different than other answers here, except that it is encapsulated into a separate class so that you don't muddy up your main code with the conversion details. From the point of view of your main code it "just works".
Here is how to write the converter:
public class TestClassArrayConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(TestClass[]));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JArray table = JArray.Load(reader);
TestClass[] items = new TestClass[table.Count - 1];
for (int i = 1; i < table.Count; i++)
{
JArray row = (JArray)table[i];
items[i - 1] = new TestClass
{
AGE = (string)row[0],
POP = (string)row[1],
SEX = (string)row[2],
DATE = (string)row[3],
us = (string)row[4]
};
}
return items;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
And here is how you would use it:
var test2 = JsonConvert.DeserializeObject<TestClass[]>(jsonStr, new TestClassArrayConverter());
Fiddle: https://dotnetfiddle.net/68Q0KT
You have to do the processing on your own, as there is no way the json deserializer can know, how to put the values into the respecitve variables.
If you know, this will be exactly this structure, you could for instance add an appropriate constructor
public TestClass(string[] values) {
AGE = values[0];
...
}
to your class. Then serialize your result to array of arrays of string and then pass the inner arrays to your constructor.
var t1 = JsonConvert.DeserializeObject<string[][]>(jsonStr);
//skip the first entry, as this contains the headers
var t2 = t1.Skip(1).Select(x=> new TestClass(x));
If your structure varies, you'll have to write some more complicated mapping code.
You will have to do some custom mapping as your Json does not have any naming conventions so you will have to work with the data in array and index formats. This will work:
var jsonStr = "[[\"AGE\",\"POP\",\"SEX\",\"DATE\",\"us\"], [\"0\",\"3948350\",\"0\",\"7\",\"1\"], [\"1\",\"3962123\",\"0\",\"7\",\"1\"], [\"2\",\"3957772\",\"0\",\"7\",\"1\"], [\"3\",\"4005190\",\"0\",\"7\",\"1\"], [\"4\",\"4003448\",\"0\",\"7\",\"1\"], [\"5\",\"4004858\",\"0\",\"7\",\"1\"], [\"6\",\"4134352\",\"0\",\"7\",\"1\"], [\"7\",\"4154000\",\"0\",\"7\",\"1\"]]";
var test2 = JsonConvert.DeserializeObject<string[][]>(jsonStr);
var test3 = test2.Select(x => new TestClass()
{
AGE = x[0].ToString(),
POP = x[1].ToString(),
SEX = x[2].ToString(),
DATE = x[3].ToString(),
us = x[4].ToString()
}).ToList();
//test Case
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
namespace ApiController.Test
{
[TestClass]
public class DownloadIrregularJsonStringObjects
{
string ApiKey => "YourPersonalCensusKey";
/// <summary>
/// You have to get your own ApiKey from the Census Website
/// </summary>
[TestMethod]
public void TestGetItem()
{
string url = $"http://api.census.gov/data/timeseries/healthins/sahie?get=NIC_PT,NAME,NUI_PT&for=county:*&in=state:*&time=2015&key={YourPersonalCensusKey}";
string expected = "Autauga County, AL";
IList<HealthData> actual = ApiController.DownloadIrregularJsonStringObjects.GetCensusHealthData(url);
Assert.AreEqual(actual[0].NAME, expected);
}
}
}
///Actual Assembly
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
namespace ApiController
{
public class DownloadIrregularJsonStringObjects
{
public static IList<HealthData> GetCensusHealthData(string url)
{
var json = GetData(url);
var rawData = JsonConvert.DeserializeObject<string[][]>(json);
var headerRow = rawData.First();
var nic_pt_Index = Array.IndexOf(headerRow, "NIC_PT");
var name_Index = Array.IndexOf(headerRow, "NAME");
var nui_pt_Index = Array.IndexOf(headerRow, "NUI_PT");
IList<HealthData> retVal = new List<HealthData>();
foreach (var r in rawData.Skip(1))
{
HealthData dataRow = new HealthData();
dataRow.NIC_PT = r[nic_pt_Index];
dataRow.NAME = r[name_Index];
dataRow.NUI_PT = r[nui_pt_Index];
retVal.Add(dataRow);
}
return retVal;
}
private static string GetData(string url)
{
using (var w = new WebClient())
{
var jsonData = string.Empty;
jsonData = w.DownloadString(url);
return jsonData;
}
}
}
public class HealthData
{
public string NIC_PT { get; set; }
public string NAME { get; set; }
public string NUI_PT { get; set; }
}
}
I am building a model with Entity Framework and purchased responsive CSS.
The built in fixed icons comes with CSS. Like as follows (Name and Icon Class Value)
I need a way to keep the names of icons as fixed enums to access it from the VS intellisense. Currently we can't store as a entity table in entity framework (as it require relationship with tables difficult to maintain) and enum doesn't allows string type.
Code that did not work:
public sealed class IconType
{
public static readonly IconType Rupee_Icon = new IconType("rupee-icons");
public static readonly IconType Doller_Icon = new IconType("doller-icon");
private IconType(int EnumID,string EnumObjectValue)
{
IconValue = EnumObjectValue;
}
public string IconValue { get; private set; }
}
More code that did not work (CSS class names contains whitespaces like ui bell icon):
public enum Icon
{
NotSet=0,
Idea Icon=1,
Bell Icon =2
}
Is there any other ways to use names / objects as enums or constants in EF for easy intellisense in Visual Studio?
You could:
Omit the white spaces in the enums:
public enum Icon
{
NotSet = 0,
IdeaIcon = 1,
BellIcon = 2
}
Add a description or name (Or even some custom attribute) attributes to the enums:
public enum Icon
{
NotSet = 0,
[Description("ui idea icon")]
IdeaIcon = 1,
[Description("ui bell icon")]
BellIcon = 2
}
When needed get the description name. Example method to get the description attribute value:
public static string GetDescription<T>(this T enumerationValue)
where T : struct, IConvertible
{
var type = enumerationValue.GetType();
if (!type.IsEnum)
{
throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
}
// Tries to find a DescriptionAttribute for a potential friendly name for the enum
var memberInfo = type.GetMember(enumerationValue.ToString(CultureInfo.InvariantCulture));
if (memberInfo.Length > 0)
{
var attributes = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Length > 0)
{
// Pull out the description value
return ((DescriptionAttribute)attributes[0]).Description;
}
}
// If we have no description attribute, just return the ToString of the enum
return enumerationValue.ToString(CultureInfo.InvariantCulture);
}
Did you consider using string constants?
public static class IconType
{
public const string RUPEE_ICON = "rupee-icon";
public const string DOLLER_ICON = "doller-icon";
// ...
}
Store the icon's as plain old objects. Why make use of entity framework at all?
public static class Icons
{
public enum Type
{
IdeaIcon = 1,
BellIcon =2
}
public static Icon Get(Type type)
{
return IconCollection.Single(icon => icon.Type == type);
}
static IEnumerable<Icon> IconCollection
{
get
{
return new List<Icon>
{
new Icon(Type.IdeaIcon, "Idea Icon", "icon idea-icon"),
new Icon(Type.BellIcon, "Bell Icon", "icon bell-icon"),
};
}
}
public class Icon
{
public Icon(Type type, string description, string cssClass)
{
Type = type;
Description = description;
CssClass = cssClass;
}
public Type Type { get; private set; }
public string Description { get; private set; }
public string CssClass { get; private set; }
}
}
Use in code:
public class Class1
{
public void Method1()
{
var ideaIcon = Icons.Get(Icons.Type.IdeaIcon);
var x = ideaIcon.CssClass;
var y = ideaIcon.Description;
var bellIcon = Icons.Get(Icons.Type.BellIcon);
// etc...
}
}
Razor view:
#Icons.Get(Icons.Type.BellIcon).CssClass
If you needed to enumerate over the icon collection you could easily add another static accessor to the Icons class.