Fation Hadri Fation Hadri - 6 months ago 239
AngularJS Question

c# Convert Dictionary<Object, List<Object>> to JSON

I have two tables in

database
with one to many relationship.State have many Cities.I get those data from database and convert their
relationship
to the logic of object in
c#
.

Convert
Dictionary<State, List<City>>
to JSON and display then using
AngularJs
.

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static Dictionary<State, List<City>> GetCitiesState()
{
List<State> stateList = new List<State>();
stateList = StateList();
List<City> cityList = new List<City>();
cityList = CityList();
List<City> currentList = new List<City>();

Dictionary<State, List<City>> dictionary = new Dictionary<State, List<City>>();
bool found = false;
foreach (State state in stateList)
{
foreach (City city in cityList)
{
if (state.Id == city.StateId)
{
found = true;
currentList.Add(city);
}
}
if (found)
{
dictionary.Add(state, currentList);
}
}
return dictionary;
}


It give me 500 Internal Server Error


{"Message":"Type
\u0027System.Collections.Generic.Dictionary2[[AngularWeb.State,
AngularWeb, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null],[System.Collections.Generic.List1[[AngularWeb.City,
AngularWeb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]],
mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089]]\u0027 is not supported for
serialization/deserialization of a dictionary, keys must be strings or
objects.","StackTrace":" at
System.Web.Script.Serialization.JavaScriptSerializer.SerializeDictionary(IDictionary
o, StringBuilder sb, Int32 depth, Hashtable objectsInUse,
SerializationFormat serializationFormat)\r\n at
System.Web.Script.Serialization.JavaScriptSerializer.SerializeValueInternal(Object
o, StringBuilder sb, Int32 depth, Hashtable objectsInUse,
SerializationFormat serializationFormat, MemberInfo currentMember)\r\n
at
System.Web.Script.Serialization.JavaScriptSerializer.SerializeValue(Object
o, StringBuilder sb, Int32 depth, Hashtable objectsInUse,
SerializationFormat serializationFormat, MemberInfo currentMember)\r\n
at
System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object
obj, StringBuilder output, SerializationFormat
serializationFormat)\r\n at
System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object
obj, SerializationFormat serializationFormat)\r\n at
System.Web.Script.Services.RestHandler.InvokeMethod(HttpContext
context, WebServiceMethodData methodData, IDictionary`2 rawParams)\r\n
at
System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext
context, WebServiceMethodData
methodData)","ExceptionType":"System.ArgumentException"}


I am not sure the correct syntax of json ,but I want to dispaly something like this:

STATE
CITY
CITY
CITY
STATE
CITY
CITY
CITY
......


Thank You!

Answer

While it's okay in C# to have Dictionary<object, object>, the Serialization Guide states that:

When serializing a dictionary, the keys of the dictionary are converted to strings and used as the JSON object property names. The string written for a key can be customized by either overriding ToString() for the key type or by implementing a TypeConverter. A TypeConverter will also support converting a custom string back again when deserializing a dictionary.

Essentially, it's saying that you can't use State as a key. You have several options.

  1. Send the states and cities as a Dictionary<string, object> and have the front end take care of the relationship for you.
  2. Create an anonymous class that takes care of the relationship in the backend.

Both methods are documented here.

Method 1: Send as a Dictionary<string, object>

[WebMethod]
public static string GetCitiesState()
{
    Dictionary<string, object> result = new Dictionary<string, object>();

    List<State> states = StateList();
    List<City> cities = CityList();

    result.Add("states", states);
    result.Add("cities", cities);

    return new JavaScriptSerializer().Serialize(result);
}

Method 2: Send as a List<Anonymous Class>

The basic idea is to create a list of anonymous typed objects (or you can make your own class). You can call new List<object>();.

[WebMethod]
public static string GetCitiesState()
{
    var result = new List<object>();

    //get stateList and cityList
    //etc... your code here etc...
    boolean found=false;
    foreach(State state in stateList)
    {
        var currentState = new {
            id = state.Id,
            state = state.State,
            stateName = state.Name,
            cities = new List<City>()
        };

        foreach(City city in cityList)
        {
            if(city.StateId == state.Id)
            {
                found=true;
                currentState.cities.Add(city);
            }
        }

        if(found )
        { 
        //add it to the running state list,only states that have cities.
        //on this situation it does not make sense because every states have  
        //cities but for extra info                                                                                              
        result.Add(currentState);
        }
    }

    return new JavaScriptSerializer().Serialize(result);
}
Comments