Parsing JSON Array in .NET 2.0 - c#

I am using JSON.NET to parse some JSON returned by my server. I feel kind of dumb, because I feel like I'm trying to do something simple. Yet, the code doesn't work. Currently, I'm getting some JSON bck from the server that looks like this:
[
{ id:'1', description:'Some kind of description' },
{ id:'2', description:'Another description' },
{ id:'3', description:'Here is another' }
]
Currently, I'm trying to take this JSON in C# and convert it to a Dictionary<string, string>. My (failing) attempt looks like this:
private Dictionary<string, string> ParseResults(string json)
{
Dictionary<string, string> dictionary = new Dictionary<string, string>();
string descriptionPropertyName = "description";
string descriptionPropertyValue = null;
bool isDescriptionProperty = false;
string idPropertyName = "id";
string idPropertyValue = null;
bool isIdProperty = false;
JsonTextReader jsonReader = new JsonTextReader(new StringReader(json));
while (jsonReader.Read())
{
if (jsonReader.TokenType == JsonToken.PropertyName)
{
if (descriptionPropertyName.Equals(jsonReader.Value))
{
isDescriptionProperty = true;
}
else if (idPropertyName.Equals(jsonReader.Value))
{
isIdProperty = true;
}
}
else
{
if ((isDescriptionProperty == true) && (descriptionPropertyValue == null))
{
if (jsonReader.TokenType == JsonToken.String)
{
if (jsonReader.Value != null)
{
descriptionPropertyValue = jsonReader.Value.ToString();
}
}
}
else if ((isIdProperty == true) && (idPropertyValue == null))
{
if (jsonReader.TokenType == JsonToken.String)
{
if (jsonReader.Value != null)
{
idPropertyValue = jsonReader.Value.ToString();
}
}
}
}
if ((isDescriptionProperty == true) && (isIdProperty == true) && (descriptionPropertyValue != null) && (idPropertyValue != null))
{
dictionary.Add(idPropertyValue, descriptionPropertyValue);
}
}
return dictionary;
}
That's a lot of code for something that seems so simple. I feel I have to do something wrong. In fact, its not working, so something has to be wrong. I just can't determine what.
Thank you for any help you may be able to provide. Please remember, this is based on the .NET 2.0 framework.

You don't have to parse the json string manually.
You can deserialize it in a strongly typed collection using JSON.NET
class MyClass
{
public string id { get; set; }
public string description { get; set; }
}
then
string json = #"[
{ id:'1', description:'Some kind of description' },
{ id:'2', description:'Another description' },
{ id:'3', description:'Here is another' }
]";
List<MyClass> collection = JsonConvert.DeserializeObject<List<MyClass>>(json);
foreach (var item in collection)
Console.WriteLine(item.id + " - " + item.description);
Or you can convert it to a dictionary
Dictionary<string, string> dict = collection.ToDictionary(e => e.id, e => e.description);

Related

Searching through an array of an array that has a key value object

I am consuming an API that returns JSON that looks like this:
{
"lookup_table_data": [
[
{
"key": "id",
"value": 0
},
{
"key" : "label",
"value" : "something"
}
],
[
{
"key": "id",
"value": 1
},
{
"key" : "label",
"value" : "something_else"
}
]
]
}
I made a class that I deserialize the json object into that looks like this:
public class LookupResponseModel
{
public Lookup_Table_Data[][] Lookup_table_data { get; set; }
public class Lookup_Table_Data
{
public string Key { get; set; }
public object Value { get; set; }
}
}
Now imagine that the JSON response has over 1,000 records instead of the 2 that I gave in my example.
I am wanting to search through my model and be able to find where the value of the key "id" is equal to 1 - because I want to use the label key value of "something_else".
How would I be able to grab the label "something_else" with an id of 1 with this model?
var lookup = model.lookupTableData.Select(data => new { key = (long)data.First(kvp => kvp.Key == "id").Value, value = (string)data.First(kvp => kvp.Key == "label").Value).ToDictionary(kvp => kvp.key, kvp => kvp.value)
var displayText = lookup[1]; // "something_else"
My attempt from a phone, might not be 100% correct syntax.
I would suggest an approach like this:
public class LookupResponseModel
{
public Lookup_Table_Data[][] Lookup_table_data { get; set; }
public class Lookup_Table_Data
{
public string Key { get; set; }
public object Value { get; set; }
}
}
// This will help compare the values and convert if necessary
// This part was missing from my original answer and made it not work
bool ObjectCompare(object a, object b)
{
if (object.Equals(a, b))
{
return true;
}
else
{
var altB = Convert.ChangeType(b, Type.GetTypeCode(a.GetType()));
return object.Equals(a, altB);
}
}
// This will break the result up into an Array of Dictionaries
// that are easier to work with
Dictionary<string, object>[] MakeTables(LookupResponseModel lrm)
{
return lrm.Lookup_table_data.Select( entry => entry.ToDictionary( e => e.Key, e => e.Value ) ).ToArray();
}
// This will help you find the dictionary that has the values you want
Dictionary<string, object> FindTable( Dictionary<string, object>[] tables, string key, object value )
{
return tables.Where( dict => dict.TryGetValue(key, out object val) && ObjectCompare(value, val) ).FirstOrDefault();
}
// Here is how you might use them together
string GetLabel()
{
var lrm = JsonConvert.DeserializeObject<LookupResponseModel>(json);
var lookup = MakeTables(lrm);
var table = FindTable( lookup, "id", 1 );
return table["label"].ToString(); // Returns "something_else"
}
Data :
LookupResponseModel model = new LookupResponseModel();
model.Lookup_table_data = new LookupResponseModel.Lookup_Table_Data[][]
{
new LookupResponseModel.Lookup_Table_Data[]
{
new LookupResponseModel.Lookup_Table_Data(){Key = "id", Value = "0"},
new LookupResponseModel.Lookup_Table_Data(){Key = "label", Value = "hello"},
new LookupResponseModel.Lookup_Table_Data(){Key = "textbox", Value = "bye"}
},
new LookupResponseModel.Lookup_Table_Data[]
{
new LookupResponseModel.Lookup_Table_Data(){Key = "id", Value = "1"},
new LookupResponseModel.Lookup_Table_Data(){Key = "label", Value = "banana"},
new LookupResponseModel.Lookup_Table_Data(){Key = "textbox", Value = "potatoe"}
},
new LookupResponseModel.Lookup_Table_Data[]
{
new LookupResponseModel.Lookup_Table_Data(){Key = "id", Value = "2"},
new LookupResponseModel.Lookup_Table_Data(){Key = "label", Value = "cat"},
new LookupResponseModel.Lookup_Table_Data(){Key = "textbox", Value = "bydog"}
}
};
This query gives us second set (all 3 Lookup_Table_Data where key is ID and value is 1) It still [][] and it can contain more than one result :
var _result = model.Lookup_table_data.Where(x => x.Any(y => y.Key == "id" && y.Value.Equals("1")));
And this one gives you exactly value of "label" key from previous set (Key = "label", Value = "banana") :
var _exactlyLabel = _result.Select(x => x.Where(y => y.Key == "label"));
Or you can make _result.SelectMany(... for [] not for [][]
The simple answer is, you say something like this
public class LookupResponseModel
{
public LookupTableData[][] lookupTableData { get; set; }
public class LookupTableData
{
public string Key { get; set; }
public object Value { get; set; }
}
public LookupTableData[] FindById( int id )
{
if (this.lookupTableData == null) throw new InvalidOperationException();
foreach ( LookupTableData[] entry in lookupTableData )
{
if (entry != null)
{
foreach( LookupTableData item in entry )
{
bool isMatch = "id".Equals( item.Key ?? "", StringComparison.Ordinal )
&& item.Value is int
&& ((int)item.Value) == id
;
if ( isMatch )
{
return entry;
}
}
}
}
return null;
}
}

Get json properties by attributes c#

I have a Json Object like the one below.
"log": {
"Response": [
{
"#type": "Authentication",
"Status": "True",
"Token": "cc622e9c-0d56-4774-8d79-543c525471b4"
},
{
"#type": "GetApplication",
"AppId": 100,
"Available": "True"
}]}
I need to access the appId property. I have tried the below code which gives the null reference error. Please help me figure out the mistake.
dynamic JsonText = JObject.Parse(result);
string AppId= JsonText ["log"]["Response #type='GetApplication'"]["AppId"].Tostring();
Here dotNetFiddle
string json = #"{
""log"": {
""Response"": [{
""#type"": ""Authentication"",
""Status"": ""True"",
""Token"": ""cc622e9c-0d56-4774-8d79-543c525471b4""
}, {
""#type"": ""GetApplication"",
""AppId"": 100,
""Available"": ""True""
}]
}
}";
JObject result = JObject.Parse(json);
foreach(var item in result["log"]["Response"])
{
Console.WriteLine(item["#type"]);
Console.WriteLine(item["AppId"]);
}
You don't need to use dynamic, use JObject and after that loop in the Responses and take the #type
To to access the AppId property like the way you are showing in your example:
string AppId = JObject.Parse(result)["log"].SelectToken("$.Response[?(#.#type=='GetApplication')]")["AppId"].ToString();
You can use http://json2csharp.com/ and generate model class, using Newtonsoft.Json and LINQ get id as I show.
model class
public class Response
{ [JsonProperty("#type")]
public string Type { get; set; }
[JsonProperty("Status")]
public string Status { get; set; }
[JsonProperty("Token")]
public string Token { get; set; }
[JsonProperty("AppId")]
public int? AppId { get; set; }
[JsonProperty("Available")]
public string Available { get; set; }
}
public class Log
{
public List<Response> Response { get; set; }
}
public class RootObject
{
public Log log { get; set; }
}
.cs
var results = JsonConvert.DeserializeObject<RootObject>(json);
var id= results.log.Response.FirstOrDefault(d => d.Type == "GetApplication").AppId;
string json = #"{
""log"": {
""Response"": [{
""#type"": ""Authentication"",
""Status"": ""True"",
""Token"": ""cc622e9c-0d56-4774-8d79-543c525471b4""
}, {
""#type"": ""GetApplication"",
""AppId"": 100,
""Available"": ""True""
}]
}
}";
JObject obj = JObject.Parse(result);
string AppId = obj["log"]["Response"][1]["AppId"].ToString();
Console.WriteLine(AppId);
#user3064309 hi, if ("#type": "GetApplication") is the second and not change location. so you can use obj["log"]["Response"][1]["AppId"].ToString();
I have written an extension function that will be the third level of depth. You can make its depth as generic if you need, so the code below
public static object GetJsonPropValue(this object obj, params string[] props)
{
try
{
var jsonString = obj.ToString().Replace("=", ":");
var objects = JsonConvert.DeserializeObject<dynamic>(jsonString);
foreach (var o in objects)
{
JObject jo = JObject.Parse("{" + o.ToString().Replace("=", ":") + "}");
if (props.Count() == 1 && jo.SelectToken(props[0]) != null)
return jo.SelectToken(props[0]).ToString();
if (props.Count() == 2 && jo.SelectToken(props[0])?.SelectToken(props[1]) != null)
return jo.SelectToken(props[0])?.SelectToken(props[1]).ToString();
if (props.Count() == 2 && jo.SelectToken(props[0])?.SelectToken(props[1])?.SelectToken(props[2]) != null)
return jo.SelectToken(props[0])?.SelectToken(props[1])?.SelectToken(props[2]).ToString();
}
}
catch (Exception ex)
{
throw new ArgumentException("GetJsonPropValue : " + ex.Message);
}
return null;
}
Also i written an extension for normal c# objects, getting prop value dynamically
public static object GetPropValue(this object obj, Type typeName, string propName)
{
try
{
IList<PropertyInfo> props = new List<PropertyInfo>(typeName.GetProperties());
foreach (PropertyInfo prop in props)
{
if (prop.Name == propName)
{
object propValue = prop.GetValue(obj, null);
return propValue;
}
}
}
catch (Exception ex)
{
throw new ArgumentException("GetPropValue : " + ex.Message);
}
return null;
}

Finding a JSON entry and add a nested element

I have a .json file that looks like this:
[
{
"username": "John",
"currency": 8,
"pulls":
[
{
"character": "person"
},
{
"character": "loved one"
}
]
},
{
"username": "Mike",
"currency": 2,
"pulls":
[
{
"character": "noone"
}
]
},
{
"username": "Clara",
"currency": 5,
"pulls":
[
{
"character": "someone"
}
]
}
]
What I managed to do so far is modify "currency":
bool userExists = false;
string jsonPointsString = File.ReadAllText(userPath);
dynamic jsonObjects = JsonConvert.DeserializeObject(jsonPointsString);
foreach (var jsonObject in jsonObjects)
{
if (jsonObject["username"] == user)
{
jsonObject["currency"] += value;
string output = JsonConvert.SerializeObject(jsonObjects, Formatting.Indented);
File.WriteAllText(userPath, output);
userExists = true;
}
}
As well as add a completely new entry from scratch:
JsonCollection.User user = new JsonCollection.User();
user.username = username;
user.currency = 10;
using (StreamReader r = new StreamReader(userPath))
{
string json = r.ReadToEnd();
List<JsonCollection.User> users = JsonConvert.DeserializeObject<List<JsonCollection.User>>(json);
users.Add(user);
newJson = JsonConvert.SerializeObject(users, Formatting.Indented);
}
File.WriteAllText(userPath, newJson);
However, no matter what I try I can not add another element to "pulls". The idea is that I call a function with a username and a pull, two strings. Based on the username variable I have to find the corresponding Json Entry and create a new entry within the "pulls" tree based on the pull variable. This is what I could come up with:
public void AddPullToUser(string user, string newPull)
{
user = "Mike"; //test value
string jsonPointsString = File.ReadAllText(userPath);
dynamic jsonObjects = JsonConvert.DeserializeObject(jsonPointsString);
foreach (var jsonObject in jsonObjects)
{
if (jsonObject["username"] == user)
{
//jsonObject["pulls"] = newPull;
JsonCollection.Character pull = new JsonCollection.Character();
pull.character = newPull;
jsonObject["pulls"] = pull;
string output = JsonConvert.SerializeObject(jsonObjects, Formatting.Indented);
File.WriteAllText(userPath, output);
}
}
}
If I do it like this the system can't convert the JsonCollection to the JArray but without using the JArray I don't understand how to find the specific users tree.
In step two this will have to be expanded even further to not create duplicated "pulls", but first of all this has to work in general.
Any help would be greatly appreciated.
Something like this -
var json = "[{'username':'John','currency':8,'pulls':[{'character':'person'},{'character':'loved one'}]},{'username':'Mike','currency':2,'pulls':[{'character':'noone'}]},{'username':'Clara','currency':5,'pulls':[{'character':'someone'}]}]";
var obj = JsonConvert.DeserializeObject<List<RootObject>>(json);
var o = obj.FindIndex(a => a.username == "Mike");
obj[o].pulls.AddRange(new List<Pull>{
new Pull{
character = "Modified"
}
});
Console.WriteLine(JsonConvert.SerializeObject(obj));
Where
public class Pull
{
public string character { get; set; }
}
public class RootObject
{
public string username { get; set; }
public int currency { get; set; }
public List<Pull> pulls { get; set; }
}
alternatively, you might be interested in JSON Merge
A possible solution looks like -
var json = "[{'username':'John','currency':8,'pulls':[{'character':'person'},{'character':'loved one'}]},{'username':'Mike','currency':2,'pulls':[{'character':'noone'}]},{'username':'Clara','currency':5,'pulls':[{'character':'someone'}]}]";
var obj = JArray.Parse(json);
var idx = obj.IndexOf(obj.FirstOrDefault(a => a["username"].ToString() == "Mike"));
((JArray)obj[idx]["pulls"]).Add(JObject.Parse(#"{
'character': 'new one'
}"));
Console.WriteLine(obj[idx]);
/*output -
{
"username": "Mike",
"currency": 2,
"pulls": [
{
"character": "noone"
},
{
"character": "new one"
}
]
} */
After a bit more research and your help I was able to first of all change all the interaction with Json to the same code-style.
New entry has changed to this:
public void CreateUser(string username)
{
try
{
string jsonUserString = File.ReadAllText(userPath);
var users = JsonConvert.DeserializeObject<List<JsonCollection.User>>(jsonUserString);
users.AddRange(new List<JsonCollection.User> { new JsonCollection.User { username = username, currency = 10, pulls = new List<JsonCollection.Character> { new JsonCollection.Character { character = "TemmieHYPE" } } } });
string output = JsonConvert.SerializeObject(users, Formatting.Indented);
File.WriteAllText(userPath, output);
}
catch
{
Console.WriteLine("Error on CreateUser");
}
}
Update has changed to this:
public void UpdateUserStats(string username, decimal value, int selection)
{
try
{
string jsonUserString = File.ReadAllText(userPath);
var users = JsonConvert.DeserializeObject<List<JsonCollection.User>>(jsonUserString);
int user = users.FindIndex(a => (a.username == username));
if (user != -1)
{
switch (selection)
{
case 1:
users[user].currency += value;
break;
case 2:
users[user].secondsOnline += value;
break;
default:
break;
}
string output = JsonConvert.SerializeObject(users, Formatting.Indented);
File.WriteAllText(userPath, output);
//AddPullToUser(username, DateTime.Now.ToString()); //remove on live
}
else
{
CreateUser(username);
}
}
catch
{
Console.WriteLine("Error on UpdateCurrency");
}
}
Most importantly the Add Pull command to add a nested element to the Json now works with the following code:
public void AddPullToUser(string username, string pulledCharacter)
{
string jsonUserString = File.ReadAllText(userPath);
var users = JsonConvert.DeserializeObject<List<JsonCollection.User>>(jsonUserString);
int alreadyPulled = users.FindIndex(a => (a.username == username) && (a.pulls.FindIndex(b => b.character == pulledCharacter) > 0));
if (alreadyPulled == -1)
{
int user = users.FindIndex(a => (a.username == username));
users[user].pulls.AddRange(new List<JsonCollection.Character> { new JsonCollection.Character { character = pulledCharacter } });
string output = JsonConvert.SerializeObject(users, Formatting.Indented);
File.WriteAllText(userPath, output);
}
}
With the addition of the "if (alreadyPulled == -1)" duplicated pulls don't get added to the Json files either.

How to save more values in XML

I have a textfield where user can fill in strings under each other. But how to save now the different strings. Because now it is one long string. And not seperated strings
This is the class for Serialize and Deserialize:
public class PreConditionSettings
{
[Display(Name = "PreConditionResidentsOnly", ResourceType = typeof(Resources.Entity.Product))]
public bool ResidentsOnly { get; set; }
[Display(Name = "PreConditionMinimumAge", ResourceType = typeof(Resources.Entity.Product))]
public int MinimumAge { get; set; }
[SfsHelpers.PreConditionRedirectValidation(ErrorMessageResourceType = typeof(Resources.Entity.Product), ErrorMessageResourceName="PreConditionRedirectUrlValidation")]
[Display(Name = "PreConditionRedirectUrl", ResourceType = typeof(Resources.Entity.Product))]
public string RedirectUrl { get; set; }
[Display(Name = "PreConditionIpAddress", ResourceType = typeof(Resources.Entity.Product))]
public string IpAddress { get; set; }
public PreConditionSettings() {
this.ResidentsOnly = false;
this.MinimumAge = 0;
this.RedirectUrl = null;
this.IpAddress = null;
}
internal string Serialize(EditProductModel model) {
if (this.ResidentsOnly == false && this.MinimumAge == 0)
return model.Product.AuthenticationSettings;
XElement settings = XElement.Parse(model.Product.AuthenticationSettings ?? "<settings/>");
if (settings == null || settings.Attribute("authenticationrequired") == null || settings.Attribute("authenticationrequired").Value != "true")
return model.Product.AuthenticationSettings;
settings.Add(
new XElement("preconditions",
new XElement("residentsonly", this.ResidentsOnly ? "1" : "0"),
new XElement("minimumage", this.MinimumAge),
new XElement("redirecturl", this.RedirectUrl),
new XElement("ipaddress", this.IpAddress)
)
);
return settings.ToString();
}
internal void Deserialize(EditProductModel model) {
Deserialize(model.Product);
}
internal void Deserialize(Product product) {
XElement settings = XElement.Parse(product.AuthenticationSettings ?? "<settings/>");
if (settings == null || settings.Attribute("authenticationrequired") == null || settings.Attribute("authenticationrequired").Value != "true")
return;
XElement conditions = settings.Element("preconditions");
if (conditions == null)
return;
XElement condition = conditions.Element("residentsonly");
if (condition!= null)
this.ResidentsOnly = (condition.Value == "1");
condition = conditions.Element("minimumage");
if (condition != null) {
int age = 0;
if (Int32.TryParse(condition.Value, out age))
this.MinimumAge = age;
}
condition = conditions.Element("redirecturl");
if (condition != null) {
this.RedirectUrl = condition.Value;
}
condition = conditions.Element("ipaddress");
if (condition != null) {
this.IpAddress = condition.Value;
}
}
And it is about the propertie: IpAddress. The output of this is:
<settings authenticationrequired="true">
<accesslevel>level10</accesslevel>
<profile>test</profile>
<preconditions>
<residentsonly>1</residentsonly>
<minimumage>55</minimumage>
<redirecturl>/page/newpage</redirecturl>
<ipaddress>88888888
999999999</ipaddress>
</preconditions>
</settings>
But you see that it is one string, and not two strings: 88888888 and 999999999.
Thank you
I try it like this:
condition = conditions.Element("ipaddress");
if (condition != null) {
string[] lines = IpAddress.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
this.IpAddress = condition.Value;
}
I try it something like this:
condition = conditions.Element("ipaddress");
if (condition != null) {
string[] lines = IpAddress.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
string lines = string.Join("\n",condition.Value);
//this.IpAddress = condition.Value;
}
If I try this:
condition = conditions.Element("ipaddress");
if (condition != null) {
string[] lines = IpAddress.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
for (int i = 0; i < lines.Length; i++) {
lines[i] = condition.Value.ToString();
//lines = string.Join("\n", condition.Value.ToArray());
}
//lines = string.Join("\n",condition.Value);
//this.IpAddress = condition.Value;
}
I get this error:
Object reference not set to an instance of an object.
on this line:
string[] lines = IpAddress.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
You should split your string IpAddress by \n or Environment.NewLine and save as array of strings.
After your edits :
condition = conditions.Element("ipaddress");
if (condition != null) {
string[] lines = condition.Value.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
this.IpAddress = new XElement("ipaddresses", lines.Select(o=> new XElement("item", o))).ToString();
}
I would recommend you to either change the property to an ICollection or create a custom type IpAddresses, implementing ICollection and custom serialization/business logic.
This would bring the following change to your xml file:
<ipaddresses>
<item>88888888</item>
<item>99999999</item>
</ipaddresses>

How do you get a user's country name in C#?

I am currently using geolocation to get the user's country name. Here is my code:
navigator.geolocation.getCurrentPosition(function (pos) {
var latlng = pos.coords.latitude + "," + pos.coords.longitude;
var apiurl = 'http://maps.google.com/maps/geo?output=json&sensor=false&q=' + latlng;
var yqlqry = encodeURIComponent('select * from json where url="' + apiurl + '"');
var yqlurl = 'http://query.yahooapis.com/v1/public/yql?q=' + yqlqry + '&format=json&callback=?';
$.getJSON(yqlurl, function (data) {
var countryName = data.query.results.json.Placemark.AddressDetails.Country.CountryName;
var newCountryName = countryName.toLowerCase();
if (newCountryName == "united states")
newCountryName = "us";
else if (newCountryName == "england" || newCountryName == "ireland" || newCountryName == "scotland" || newCountryName == "wales" || newCountryName == "northern ireland")
newCountryName = "uk";
else if (newCountryName == "australia")
newCountryName = "au";
else if (newCountryName == "canada")
newCountryName = "ca";
else
newCountryName = "world";
$('a[title = "' + newCountryName + '"]').trigger('click');
});
});
I would rather use something on the server side. Does anyone know if you can get the user's country name in C#?
On the server side, the only thing you can reply upon is the IP address, which you can use to perform a location lookup. There are free databases out there of IP address-to-location mappings, or you can use HostIP.info.
Look at https://stackoverflow.com/questions/372591/how-to-get-city-country-and-country-code-for-a-particular-ip-address-in-asp-ne for more info.
I did this for WP7, but code is almost the same in standard.net framework: http://www.felicepollano.com/2012/01/11/AnImplementationOfICivicAddressResolverForWP7.aspx
the class doing the job is below. Just remove ICivicAddressResolver that is a WP7 dependency and create your own interface.
public class AddressResolver:ICivicAddressResolver
{
string language = "en-GB";
public AddressResolver()
{
}
public AddressResolver(string language)
{
this.language = language;
}
[DataContract]
public class AddressInfo
{
[DataMember(Name = "formatted_address")]
public string FormattedAddress { get; set; }
}
[DataContract]
public class ResultInfo
{
[DataMember(Name = "results")]
public AddressInfo[] Info { get; set; }
}
readonly string URITemplate = "http://maps.googleapis.com/maps/api/geocode/json?latlng={0},{1}&sensor=true&language={2}";
#region ICivicAddressResolver Members
public CivicAddress ResolveAddress(GeoCoordinate coordinate)
{
throw new NotImplementedException("Use async version instead");
}
public void ResolveAddressAsync(GeoCoordinate coordinate)
{
WebClient client = new WebClient();
client.Encoding = Encoding.UTF8;
client.DownloadStringCompleted += (s, e) =>
{
if (e.Error == null)
{
var ainfo = ReadToObject<ResultInfo>(e.Result);
ResolveAddressCompleted(this, new ResolveAddressCompletedEventArgs(ToCivic(ainfo),e.Error,false,null));
}
else
{
ResolveAddressCompleted(this, new ResolveAddressCompletedEventArgs(new CivicAddress(), e.Error, false, null));
}
};
client.DownloadStringAsync(new Uri(GetFormattedUri(coordinate)));
}
private CivicAddress ToCivic(ResultInfo ainfo)
{
List<string> res = new List<string>();
foreach (var single in ainfo.Info)
{
res.Add(single.FormattedAddress);
}
if (res.Count > 0)
return new CivicAddress() { AddressLine1 = res[0] };
else
return new CivicAddress() { AddressLine1 = "#UNKNOWN#" };
}
public event EventHandler<ResolveAddressCompletedEventArgs> ResolveAddressCompleted = delegate { };
#endregion
private string GetFormattedUri(GeoCoordinate coord)
{
return string.Format(CultureInfo.InvariantCulture, URITemplate, coord.Latitude, coord.Longitude,language);
}
public static T ReadToObject<T>(string json) where T : class
{
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json));
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
T res = ser.ReadObject(ms) as T;
ms.Close();
return res;
}
}
Why don't you try IP2Location's API ?
You could just pass your ipaddress like this.
http://api.ip2location.com/?ip=145.228.219.221&key=demo
More info at
http://www.ip2location.com/ip-country-web-service.aspx
Don't know if this will help but in local this
CultureInfo.CurrentCulture.Name
return something like "en-GB" or "fr-FR" depending of your current locale

Categories

Resources