Model binding to Dictionary<string,string> in Nancy - c#

I can't bind JSON to Dictionary<string,string> in Nancy.
This route:
Get["testGet"] = _ =>
{
var dictionary = new Dictionary<string, string>
{
{"hello", "world"},
{"foo", "bar"}
};
return Response.AsJson(dictionary);
};
returns the following JSON, as expected:
{
"hello": "world",
"foo": "bar"
}
When I try and post this exact JSON back to this route:
Post["testPost"] = _ =>
{
var data = this.Bind<Dictionary<string, string>>();
return null;
};
I get the exception:
The value "[Hello, world]" is not of type "System.String" and cannot
be used in this generic collection.
Is it possible to bind to Dictionary<string,string> using Nancys default model binding and, if so, what am I doing wrong here?

Nancy doesn't have a built-in converter for dictionaries. Because of this you'd need to use BindTo<T>() like so
var data = this.BindTo(new Dictionary<string, string>());
which will use the CollectionConverter. The issue with doing it like this is it will only add string values, so if you send
{
"hello": "world",
"foo": 123
}
your result will only contain the key hello.
If you want to capture all the values as strings, even if they aren't supplied as such, then you'll need to use a custom IModelBinder.
This will convert all the values to strings and return a Dictionary<string, string>.
public class StringDictionaryBinder : IModelBinder
{
public object Bind(NancyContext context, Type modelType, object instance, BindingConfig configuration, params string[] blackList)
{
var result = (instance as Dictionary<string, string>) ?? new Dictionary<string, string>();
IDictionary<string, object> formData = (DynamicDictionary) context.Request.Form;
foreach (var item in formData)
{
var itemValue = Convert.ChangeType(item.Value, typeof (string)) as string;
result.Add(item.Key, itemValue);
}
return result;
}
public bool CanBind(Type modelType)
{
// http://stackoverflow.com/a/16956978/39605
if (modelType.IsGenericType && modelType.GetGenericTypeDefinition() == typeof (Dictionary<,>))
{
if (modelType.GetGenericArguments()[0] == typeof (string) &&
modelType.GetGenericArguments()[1] == typeof (string))
{
return true;
}
}
return false;
}
}
Nancy will auto register this for you and you can bind your models as you normally would.
var data1 = this.Bind<Dictionary<string, string>>();
var data2 = this.BindTo(new Dictionary<string, string>());

Related

Custom OAuth in Unity linking to Parse Server

I am using Unity with Parse Server and now wants to be able to link a user with OAuth.
This is what I am trying so far, but with no luck.
[System.Serializable]
public class DGUOAuth
{
public string dguId = "";
public string access_token = "";
}
DGUOAuth auth = new DGUOAuth()
{
access_token = "F12w06Ddqx1k5qj75JQWRZmzh16Zgf05wHExNnHAnh8",
dguId = "25-1999"
};
System.Threading.CancellationToken canceltoken;
Dictionary<string, object> data = new Dictionary<string, object>();
data.Add("authData", auth);
Debug.Log("Ready for linking the user!");
DataManager.user.LinkWithAsync("DGU", data, canceltoken).ContinueWith(t =>
{
if (t.IsFaulted)
{
Debug.Log("Faulted: " + t.Exception);
// Errors from Parse Cloud and network interactions
using (IEnumerator<Exception> enumerator = t.Exception.InnerExceptions.GetEnumerator())
{
if (enumerator.MoveNext())
{
ParseException error = (ParseException)enumerator.Current;
Debug.Log(error.Message);
// error.Message will contain an error message
// error.Code will return "OtherCause"
}
}
}
else
{
Debug.Log("User is linked");
}
});
Nothing happens and I only get "Ready for linking the user!" but no logs after that?! The documentation for LinkWithAsync and Unity is almost not existing...
Really hope someone can help me on this. Any help is appreciated and thanks in advance :-)
----- EDIT -----
Now, added a Debug.Log just after t.isFaulted and get this log:
System.AggregateException: One or more errors occurred. ---> System.ArgumentException: Unable to encode objects of type DGUOAuth
Not sure how to solve this. I do not get any error logs in the Parse server logs.
Issue
The error is basically coming from JsonUtility.Encode
public static string Encode(IDictionary<string, object> dict)
{
if (dict == null)
throw new ArgumentNullException();
if (dict.Count == 0)
return "{}";
StringBuilder builder = new StringBuilder("{");
foreach (KeyValuePair<string, object> pair in dict)
{
builder.Append(Encode(pair.Key));
builder.Append(":");
builder.Append(Encode(pair.Value));
builder.Append(",");
}
builder[builder.Length - 1] = '}';
return builder.ToString();
}
where builder.Append(Encode(pair.Value)); then tries to call Encode(object)
public static string Encode(object obj)
{
if (obj is IDictionary<string, object> dict)
return Encode(dict);
if (obj is IList<object> list)
return Encode(list);
if (obj is string str)
{
str = escapePattern.Replace(str, m =>
{
switch (m.Value[0])
{
case '\\':
return "\\\\";
case '\"':
return "\\\"";
case '\b':
return "\\b";
case '\f':
return "\\f";
case '\n':
return "\\n";
case '\r':
return "\\r";
case '\t':
return "\\t";
default:
return "\\u" + ((ushort) m.Value[0]).ToString("x4");
}
});
return "\"" + str + "\"";
}
if (obj is null)
return "null";
if (obj is bool)
return (bool) obj ? "true" : "false";
if (!obj.GetType().GetTypeInfo().IsPrimitive)
throw new ArgumentException("Unable to encode objects of type " + obj.GetType());
return Convert.ToString(obj, CultureInfo.InvariantCulture);
}
so without knowing that thing at all it looks like it simply expects an IDictionary<string, object> where the value can only be of the types
IDictionary<string, object> (where the value type again underlies the same type restrictions)
IList<object> (where the element type again underlies the same restrictions)
string
bool
primitive types (int, short, ulong, float, etc)
your given class DGUOAuth is neither of these => ArgumentException.
Solution(s)
So I would simply not use your DGUOAuth class at all but simply construct according dictionary either directly as
var data = new Dictionary<string, object>
{
{"authData" , "{\"access_token\" : \"F12w06Ddqx1k5qj75JQWRZmzh16Zgf05wHExNnHAnh8\", \"dguId\" : \"25-1999\"}"}
};
or if you want to as
var data = new Dictionary<string, object>
{
{"authData" , new Dictionary<string, object>
{
{"access_token", "F12w06Ddqx1k5qj75JQWRZmzh16Zgf05wHExNnHAnh8"},
{"dguId", "25-1999"}
}
}
};
where of course you can fill in the values also dynamically from variables if needed.
The alternative would be to make sure that your DGUOAuth returns such a dictionary this makes it maybe easier for you if you need to pass this around a lot or configure it via the Inspector
[System.Serializable]
public class DGUOAuth
{
public string dguId = "";
public string access_token = "";
public DGUOauth(string id, string token)
{
dguId = id;
access_token = token;
}
public IDictionary<string, object> ToDictionary()
{
return new Dictionary<string, object>
{
{"access_token", access_token},
{"dguId", dguId}
};
}
}
and then use it like
var data = new Dictionary<string, object>
{
{"authData", new DGUOauth("25-1999", "F12w06Ddqx1k5qj75JQWRZmzh16Zgf05wHExNnHAnh8").ToDictionary()}
};
or actually implements according interface IDictionary<string, object> which in my eyes is a lot of overkill for this little task.
I'm not even sure if you need that field name authData there or if it rather simply would expect
var data = new Dictionary<string, object>
{
{"access_token", "F12w06Ddqx1k5qj75JQWRZmzh16Zgf05wHExNnHAnh8"},
{"dguId", "25-1999"}
};
but that's something you will have to try.

How to modify HttpContext.Request.Form in asp.net core

I have an HttpContext.Request object that has data in the Form that is wrong and I want to fix it up and send the correct HttpContext on its way.
HttpContext.Request.Form is readonly, but if it wasn't I would have simply done the following;
HttpContext.Request.Form["a"] = "the correct value for a";
So, where is the best place in the pipeline to do this.
Is it possible to make the HttpContext.Request.Form write accessable via reflection?
This was easier than I thought. I am doing this in my middleware which is there to correct bad form data that came in.
public async Task Invoke(HttpContext context)
{
....
NameValueCollection fcnvc = context.Request.Form.AsNameValueCollection();
fcnvc.Set("a", "the correct value of a");
fcnvc.Set("b", "a value the client forgot to post");
Dictionary<string, StringValues> dictValues = new Dictionary<string, StringValues>();
foreach (var key in fcnvc.AllKeys)
{
dictValues.Add(key, fcnvc.Get(key));
}
var fc = new FormCollection(dictValues);
context.Request.Form = fc;
....
await _next.Invoke(context);
}
Interestingly the FormCollection is readonly, but the HttpContext.Request object is not thus allowing me to replace the entire Form.
Here's a .NET Core/5 solution that worked for me without using the Identity Server package.
Basically you build a new dictionary of type <string, StringValues> out of the existing form collection, modify the values in the dictionary how you want, then create a new FormCollection from that dictionary and set it to context.Request.Form. The important thing to remember is that the value which is of type StringValues is just an array of strings!
This example demonstrates me removing a "client_id" field from the request form.
var formDictionary = new Dictionary<string, StringValues>();
var form = context.Request.Form;
foreach (var key in form.Keys)
{
// Only add if key is NOT client_id
if (key != "client_id")
{
form.TryGetValue(key, out StringValues formValues);
formDictionary.Add(key, formValues);
}
}
FormCollection formCollection = new FormCollection(formDictionary);
context.Request.Form = formCollection;
Here is another example of me changing the "client_id" field to "NewValue"
var formDictionary = new Dictionary<string, StringValues>();
var form = context.Request.Form;
foreach (var key in form.Keys)
{
form.TryGetValue(key, out StringValues formValues);
// Change client_id value to "NewValue"
if (key == "client_id")
{
formValues = new string[] { "NewValue" };
}
formDictionary.Add(key, formValues);
}
FormCollection formCollection = new FormCollection(formDictionary);
context.Request.Form = formCollection;
AsNameValueCollection is inside of IdentityServer4.dll.
public static class IReadableStringCollectionExtensions
{
[DebuggerStepThrough]
public static NameValueCollection AsNameValueCollection(this IDictionary<string, StringValues> collection)
{
NameValueCollection values = new NameValueCollection();
foreach (KeyValuePair<string, StringValues> pair in collection)
{
string introduced3 = pair.get_Key();
values.Add(introduced3, Enumerable.First<string>(pair.get_Value()));
}
return values;
}
[DebuggerStepThrough]
public static NameValueCollection AsNameValueCollection(this IEnumerable<KeyValuePair<string, StringValues>> collection)
{
NameValueCollection values = new NameValueCollection();
foreach (KeyValuePair<string, StringValues> pair in collection)
{
string introduced3 = pair.get_Key();
values.Add(introduced3, Enumerable.First<string>(pair.get_Value()));
}
return values;
}
}
I personally prefer to use an extended method to do this.
public static IFormCollection PushToForm(this IFormCollection form, Dictionary<string, StringValues> data)
{
var formDictionary = new Dictionary<string, StringValues>();
foreach (var k in form.Keys)
{
form.TryGetValue(k, out StringValues v);
formDictionary.Add(k, v);
}
foreach (var x in data) formDictionary.Add(x.Key, x.Value);
return new FormCollection(formDictionary);
}
Example:
Request.Form = Request.Form.PushToForm(new Dictionary<string, StringValues>()
{
{ "key1", new string[] { "value1" } },
{ "key2", new string[] { "value2" } },
{ "key3", new string[] { "value3" } },
...
});
A bit complex but shorter solution
var collection = HttpContext.Request.Form;
var propInfo = collection.GetType().GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
propInfo.SetValue(collection, false, new object[]{});
collection.Remove("a");
collection.Add("a", "the correct value for a");
System.Diagnostics.Debug.Write(HttpContext.Request["a"]); // the correct value for a
Enjoy!

How to read index based json in c# and convert it into object?

It is the MVC 5 application consuming web service. Web service having the method to return the JSON data of string in following format.
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string GetCompanyData()
{
string jsonData = "[{\"1\":\"Message-Type\"},{\"28\":\"KEM\",\"3\":\"COMPANY1\",\"6\":\"218\",\"21\":\"6.8\",\"14\":\"33543\",\"16\":\"7188572.3\"},";
jsonData +="{\"28\":\"KEM\",\"3\":\"COMPANY2\",\"6\":\"224.5\",\"21\":\"4.5\",\"14\":\"19058\",\"16\":\"4246936\"},";
jsonData +="{\"28\":\"KEM\",\"3\":\"COMPANY3\",\"6\":\"79.9\",\"21\":\"3.4\",\"14\":\"81418\",\"16\":\"6320237.5\"},";
jsonData +="{\"28\":\"KEM\",\"3\":\"COMPANY4\",\"6\":\"87\",\"21\":\"2.5\",\"14\":\"42277\",\"16\":\"3654459\"},";
jsonData +="{\"28\":\"KEM\",\"3\":\"COMPANY5\",\"6\":\"103\",\"21\":\"2.3\",\"14\":\"1735\",\"16\":\"177450.4\"},";
jsonData +="{\"28\":\"KEM\",\"3\":\"COMPANY6\",\"6\":\"108.1\",\"21\":\"2.1\",\"14\":\"269165\",\"16\":\"29039148.4\"},";
jsonData +="{\"28\":\"KEM\",\"3\":\"COMPANY7\",\"6\":\"95.9\",\"21\":\"1.2\",\"14\":\"313\",\"16\":\"29479.7\"},";
jsonData +="{\"28\":\"KEM\",\"3\":\"COMPANY8\",\"6\":\"51.1\",\"21\":\"1\",\"14\":\"117208\",\"16\":\"5954460.6\"},";
jsonData +="{\"28\":\"KEM\",\"3\":\"COMPANY9\",\"6\":\"73.6\",\"21\":\"0.9\",\"14\":\"161593\",\"16\":\"11856197.6\"},";
jsonData +="{\"28\":\"KEM\",\"3\":\"COMPANY10\",\"6\":\"40.1\",\"21\":\"0.55\",\"14\":\"220241\",\"16\":\"8782243.3\"}]";
return jsonData;
}
Trying to convert this into the object list.
In controller :
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
var companyDataList = json_serializer.Deserialize<List<object>>(svc.GetCompanyData())
This is working fine. But there is iteration in JSON where, need to be perform the unboxing to custom object. Since keys are integer based unable to read data from JSON.
But generating JSON is having int as keys, so unable to read specific data.
How to read such JSON data.
Edited : Tried with Newtonsoft
object[] objectArray = JsonConvert.DeserializeObject<object[]>(JsonConvert.SerializeObject(companyDataList ));
But underlying list of data is resulting in immediate window like (for first ):
objIndex
{
"28": "KEM",
"3": "COMPANY1",
"6": "218",
"21": "6.8",
"14": "33543",
"16": "7188572.3"
}
base: {
"28": "KEM",
"3": "COMPANY1",
"6": "218",
"21": "6.8",
"14": "33543",
"16": "7188572.3"
}
Type: Object
ANSWER:
Added following class to extend :
public static class Extensions
{
public static T ToObject<T>(this IDictionary<string, object> source, Dictionary<string, string> sourceDictionary)
where T : class, new()
{
T someObject = new T();
Type someObjectType = someObject.GetType();
foreach (KeyValuePair<string, object> item in source)
{
if (sourceDictionary.Keys.Contains(item.Key) && (someObjectType.GetProperty(sourceDictionary[item.Key])!=null))
someObjectType.GetProperty(sourceDictionary[item.Key]).SetValue(someObject, item.Value, null);
}
return someObject;
}
public static IDictionary<string, object> AsDictionary(this object source, BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
{
return source.GetType().GetProperties(bindingAttr).ToDictionary
(
propInfo => propInfo.Name,
propInfo => propInfo.GetValue(source, null)
);
}
}
In Class method utilized this as :
var tempObjArray = json_serializer.Deserialize<object[]>(svc.GetTopByVolume());
List<Symbol> topByVolumeList = new List<Symbol>();
foreach (object tmpObject in tempObjArray)
{
Dictionary<string, object> diTopByVolumes = (Dictionary<string, object>)tmpObject;
Symbol someObject = diTopByVolumes.ToObject<Symbol>(StaticDictionary.TopByVolumeDictionary);
topByVolumeList.Add(someObject);
}
also in Global.asax in application start event specified added :
public static Dictionary<string, string> TopByVolumeDictionary = new Dictionary<string, string>();
TopByVolumeDictionary.Add("3", "SYMBOLID");
TopByVolumeDictionary.Add("6", "Property1");
TopByVolumeDictionary.Add("14", "Property2");
TopByVolumeDictionary.Add("16", "Property3");
TopByVolumeDictionary.Add("21", "Property4");
To expand on my comments a little,
You might be better off building a simple class or object that reflects what your JSON is supposed to look like and then making a List<companyObject> the you can convert to a JSON string.
A quick example that might not reflect the structure you want would be something like:
A Class:
public class Company
{
public Dictionary<string, string> companyObject =
new Dictionary<string, string>();
public Dictionary<string, string>
Add(string twentyEight, string three, string six,
string twentOne, string fourteen, string sixteen)
{
companyObject.Add("28", twentyEight);
companyObject.Add("3", three);
companyObject.Add("6", six);
companyObject.Add("21", twentOne);
companyObject.Add("14", fourteen);
companyObject.Add("16", sixteen);
return companyObject;
}
}
And then a little code (not elegant)
List<Company> companyList = new List<Company>();
Company c = new Company();
c.Add("KEM", "COMPANY1", "218", "6.8", "33543", "7188572.3");
companyList.Add(c);
string newJson = Newtonsoft.Json.JsonConvert.SerializeObject(companyList);
would create a JSON that looks like:
[{"companyObject":{"28":"KEM","3":"COMPANY1","6":"218","21":"6.8",
"14":"33543","16":"7188572.3"}}]
A list of two items would look like:
[{"companyObject":{"28":"KEM","3":"COMPANY1","6":"218","21":"6.8",
"14":"33543","16":"7188572.3"}},
{"companyObject":{"28":"KEM","3":"COMPANY2","6":"219","21":"7.2",
"14":"35200","16":"7188111.7"}}]
I'd tweak the class depending on what you really want, but as a quick rough concept I think it is a better approach.

Serialize some string values in a Dictionary as integers

Currently my Dictionary<string, string> is serialized as:
{
"Uri" : "/site/Default.aspx",
"time-taken" : "232"
}
I would like Json.net to serialize it as
{
"Uri" : "/site/Default.aspx",
"time-taken" : 232
}
What would be the easiest way to achieve this with Json.net? I don't want to make a new class with the correct types instead of the Dictionary since the keys are many and may change. I know the keys that will be int.
I think I would just make a helper method that copied the data from a dictionary to a JObject like this:
public static class JsonHelper
{
public static string SerializeDictionary(Dictionary<string, string> dict, IEnumerable<string> intKeys)
{
JObject obj = new JObject();
foreach (var kvp in dict)
{
int intValue;
if (intKeys.Contains(kvp.Key) && int.TryParse(kvp.Value, out intValue))
obj.Add(kvp.Key, intValue);
else
obj.Add(kvp.Key, kvp.Value);
}
return obj.ToString(Formatting.Indented);
}
}
Then use it like this:
var dict = new Dictionary<string, string>();
dict.Add("AnInt", "123");
dict.Add("AString", "abc");
dict.Add("AnotherInt", "456");
dict.Add("KeepThisAsString", "789");
dict.Add("NotAnInt", "xyz");
var intKeys = new string[] { "AnInt", "AnotherInt" };
string json = JsonHelper.SerializeDictionary(dict, intKeys);
Console.WriteLine(json);
Output:
{
"AnInt": 123,
"AString": "abc",
"AnotherInt": 456,
"KeepThisAsString": "789",
"NotAnInt": "xyz"
}
Fiddle: https://dotnetfiddle.net/xdnnb0

C# generic method returning different object instances [duplicate]

Are there any elegant quick way to map object to a dictionary and vice versa?
Example:
IDictionary<string,object> a = new Dictionary<string,object>();
a["Id"]=1;
a["Name"]="Ahmad";
// .....
becomes
SomeClass b = new SomeClass();
b.Id=1;
b.Name="Ahmad";
// ..........
Using some reflection and generics in two extension methods you can achieve that.
Right, others did mostly the same solution, but this uses less reflection which is more performance-wise and way more readable:
public static class ObjectExtensions
{
public static T ToObject<T>(this IDictionary<string, object> source)
where T : class, new()
{
var someObject = new T();
var someObjectType = someObject.GetType();
foreach (var item in source)
{
someObjectType
.GetProperty(item.Key)
.SetValue(someObject, item.Value, null);
}
return someObject;
}
public static IDictionary<string, object> AsDictionary(this object source, BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
{
return source.GetType().GetProperties(bindingAttr).ToDictionary
(
propInfo => propInfo.Name,
propInfo => propInfo.GetValue(source, null)
);
}
}
class A
{
public string Prop1
{
get;
set;
}
public int Prop2
{
get;
set;
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
dictionary.Add("Prop1", "hello world!");
dictionary.Add("Prop2", 3893);
A someObject = dictionary.ToObject<A>();
IDictionary<string, object> objectBackToDictionary = someObject.AsDictionary();
}
}
Convert the Dictionary to JSON string first with Newtonsoft.
var json = JsonConvert.SerializeObject(advancedSettingsDictionary, Newtonsoft.Json.Formatting.Indented);
Then deserialize the JSON string to your object
var myobject = JsonConvert.DeserializeObject<AOCAdvancedSettings>(json);
Seems reflection only help here.. I've done small example of converting object to dictionary and vise versa:
[TestMethod]
public void DictionaryTest()
{
var item = new SomeCLass { Id = "1", Name = "name1" };
IDictionary<string, object> dict = ObjectToDictionary<SomeCLass>(item);
var obj = ObjectFromDictionary<SomeCLass>(dict);
}
private T ObjectFromDictionary<T>(IDictionary<string, object> dict)
where T : class
{
Type type = typeof(T);
T result = (T)Activator.CreateInstance(type);
foreach (var item in dict)
{
type.GetProperty(item.Key).SetValue(result, item.Value, null);
}
return result;
}
private IDictionary<string, object> ObjectToDictionary<T>(T item)
where T: class
{
Type myObjectType = item.GetType();
IDictionary<string, object> dict = new Dictionary<string, object>();
var indexer = new object[0];
PropertyInfo[] properties = myObjectType.GetProperties();
foreach (var info in properties)
{
var value = info.GetValue(item, indexer);
dict.Add(info.Name, value);
}
return dict;
}
I'd highly recommend the Castle DictionaryAdapter, easily one of that project's best-kept secrets. You only need to define an interface with the properties you want, and in one line of code the adapter will generate an implementation, instantiate it, and synchronize its values with a dictionary you pass in. I use it to strongly-type my AppSettings in a web project:
var appSettings =
new DictionaryAdapterFactory().GetAdapter<IAppSettings>(ConfigurationManager.AppSettings);
Note that I did not need to create a class that implements IAppSettings - the adapter does that on the fly. Also, although in this case I'm only reading, in theory if I were setting property values on appSettings, the adapter would keep the underlying dictionary in sync with those changes.
I think you should use reflection. Something like this:
private T ConvertDictionaryTo<T>(IDictionary<string, object> dictionary) where T : new()
{
Type type = typeof (T);
T ret = new T();
foreach (var keyValue in dictionary)
{
type.GetProperty(keyValue.Key).SetValue(ret, keyValue.Value, null);
}
return ret;
}
It takes your dictionary and loops through it and sets the values. You should make it better but it's a start. You should call it like this:
SomeClass someClass = ConvertDictionaryTo<SomeClass>(a);
Reflection can take you from an object to a dictionary by iterating over the properties.
To go the other way, you'll have to use a dynamic ExpandoObject (which, in fact, already inherits from IDictionary, and so has done this for you) in C#, unless you can infer the type from the collection of entries in the dictionary somehow.
So, if you're in .NET 4.0 land, use an ExpandoObject, otherwise you've got a lot of work to do...
Building on Matías Fidemraizer's answer, here is a version that supports binding to object properties other than strings.
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace WebOpsApi.Shared.Helpers
{
public static class MappingExtension
{
public static T ToObject<T>(this IDictionary<string, object> source)
where T : class, new()
{
var someObject = new T();
var someObjectType = someObject.GetType();
foreach (var item in source)
{
var key = char.ToUpper(item.Key[0]) + item.Key.Substring(1);
var targetProperty = someObjectType.GetProperty(key);
//edited this line
if (targetProperty.PropertyType == item.Value.GetType())
{
targetProperty.SetValue(someObject, item.Value);
}
else
{
var parseMethod = targetProperty.PropertyType.GetMethod("TryParse",
BindingFlags.Public | BindingFlags.Static, null,
new[] {typeof (string), targetProperty.PropertyType.MakeByRefType()}, null);
if (parseMethod != null)
{
var parameters = new[] { item.Value, null };
var success = (bool)parseMethod.Invoke(null, parameters);
if (success)
{
targetProperty.SetValue(someObject, parameters[1]);
}
}
}
}
return someObject;
}
public static IDictionary<string, object> AsDictionary(this object source, BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
{
return source.GetType().GetProperties(bindingAttr).ToDictionary
(
propInfo => propInfo.Name,
propInfo => propInfo.GetValue(source, null)
);
}
}
}
public class SimpleObjectDictionaryMapper<TObject>
{
public static TObject GetObject(IDictionary<string, object> d)
{
PropertyInfo[] props = typeof(TObject).GetProperties();
TObject res = Activator.CreateInstance<TObject>();
for (int i = 0; i < props.Length; i++)
{
if (props[i].CanWrite && d.ContainsKey(props[i].Name))
{
props[i].SetValue(res, d[props[i].Name], null);
}
}
return res;
}
public static IDictionary<string, object> GetDictionary(TObject o)
{
IDictionary<string, object> res = new Dictionary<string, object>();
PropertyInfo[] props = typeof(TObject).GetProperties();
for (int i = 0; i < props.Length; i++)
{
if (props[i].CanRead)
{
res.Add(props[i].Name, props[i].GetValue(o, null));
}
}
return res;
}
}
If you are using Asp.Net MVC, then take a look at:
public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes);
which is a static public method on the System.Web.Mvc.HtmlHelper class.
public Dictionary<string, object> ToDictionary<T>(string key, T value)
{
try
{
var payload = new Dictionary<string, object>
{
{ key, value }
};
} catch (Exception e)
{
return null;
}
}
public T FromDictionary<T>(Dictionary<string, object> payload, string key)
{
try
{
JObject jObject = (JObject) payload[key];
T t = jObject.ToObject<T>();
return (t);
}
catch(Exception e) {
return default(T);
}
}

Categories