I have the following two objects (which I do not control and can not change):
[Serializable]
[DataContract]
public class AddressContactType : BaseModel
{
public AddressContactType();
[DataMember]
public string AddressContactTypeName { get; set; }
}
[Serializable]
[DataContract]
public abstract class BaseModel
{
protected BaseModel();
[DataMember]
public int Id { get; set; }
[DataMember]
public string NativePMSID { get; set; }
[DataMember]
public string PMCID { get; set; }
}
I am using RestClient to make a GET call to retrieve this data in JSON. The request succeeds. The returned JSON is:
[{"Id":0,"NativePMSID":"1","PMCID":"1020","AddressContactTypeName":"Home"},{"Id":0,"NativePMSID":"2","PMCID":"1020","AddressContactTypeName":"Apartment"},{"Id":0,"NativePMSID":"3","PMCID":"1020","AddressContactTypeName":"Vacation"},{"Id":0,"NativePMSID":"3","PMCID":"1020","AddressContactTypeName":"Other"}]
From that point I attempt to deserialize the data in three different ways.
My code:
var request = new RestRequest("AddressContactType", Method.GET);
request.AddHeader("Accept", "application/json");
request.AddParameter("PMCID", "1020");
#region JSON Deserialization
// ---- Attempt #1
var response = client.Execute<AddressContactType>(request);
// ---- Attempt #2
var myResults = response.Content;
var ms = new MemoryStream(Encoding.UTF8.GetBytes(myResults));
var ser = new DataContractJsonSerializer(typeof(AddressContactType));
var result = (AddressContactType)ser.ReadObject(ms);
// ---- Attempt #3
var jsonSettings = new JsonSerializerSettings()
{
Formatting = Formatting.Indented,
DateFormatHandling = DateFormatHandling.MicrosoftDateFormat,
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
PreserveReferencesHandling = PreserveReferencesHandling.Objects
};
var result2 = new AddressContactType();
result2 = JsonConvert.DeserializeObject<AddressContactType>(new StreamReader(ms).ReadToEnd(), jsonSettings);
#endregion
Under attempt 1, the RestClient attempt returns the error: "Unable to cast object of type 'RestSharp.JsonArray' to type 'System.Collections.Generic.IDictionary`2[System.String,System.Object]'."
Under attempt 2, the object result is shown with the correct properties (Id, NativePMSID, PMCID and AddressContactTypeName) but they are all null and only one instance of each is shown.
Attempt 3 just returns a null value for result2.
Any suggestions?
Thanks.
It appears the solution to my problem is:
List<AddressContactType> myResults2;
using (Stream ms2 = new MemoryStream(Encoding.UTF8.GetBytes(myResults)))
{
myResults2 = JsonConvert.DeserializeObject<List<AddressContactType>>(new StreamReader(ms2).ReadToEnd());
}
I was close with one of the previous steps, but this gave me a complete list.
Related
I'm working with a REST API, that returns 2 different kinds of XML responses for the same request.
For example if I ask for a ticket using some ticket number, say 12345 to this API, it either returns:
The ticket:
Or says that it doesn't have the ticket:
(I couldn't format my XML for some reason so just pasted the screenshot.)
Note that the status code comes to be Ok in both the cases. I'm aware that it's a bad api design but we can't change anything about it.
With some help from this JSON2Csharp website, I came up with these classes to represent the response:
The Ticket class:
[XmlRoot(ElementName = "Tickets")]
public class TicketsResponse
{
public List<Ticket> Tickets { get; set; } = new List<Ticket>();
public bool HasTickets() => Tickets.Any();
}
[XmlRoot(ElementName = "Ticket")]
public class Ticket
{
[XmlElement(ElementName = "Field1", IsNullable = true)]
public string Field1 { get; set; }
public bool ShouldSerializeField1() { return Field1 != null; }
[XmlElement(ElementName = "TicketNumber")]
public int TicketNumber { get; set; }
[XmlElement(ElementName = "SomeOtherDetails")]
public SomeOtherDetails SomeOtherDetails { get; set; }
[XmlElement(ElementName = "Accessorials")]
public object Accessorials { get; set; }
}
[XmlRoot(ElementName = "SomeOtherDetails")]
public class SomeOtherDetails
{
[XmlElement(ElementName = "SomeOtherField1", IsNullable = true)]
public string SomeOtherField1 { get; set; }
public bool ShouldSerializeSomeOtherField1() { return SomeOtherField1 != null; }
}
The Error class:
[XmlRoot(ElementName = "response")]
public class ErrorResponse
{
public byte requestId { get; set; }
public byte errorCode { get; set; }
public string errorDesc { get; set; }
public ErrorResponseBody body { get; set; }
public bool HasErrors()
{
var hasTopLevelError = errorCode != 0;
var hasErrorBody = body?.errors?.Any() ?? false;
if (hasTopLevelError || hasErrorBody)
{
return true;
}
return false;
}
public string ErrorMessage()
{
var hasTopLevelError = errorCode != 0;
var hasErrorBody = body?.errors?.Any() ?? false;
if (hasTopLevelError)
{
return errorDesc;
}
else if (hasErrorBody)
{
return string.Join(", ", body.errors.Select(e => e.errorDescription));
}
return null;
}
}
[XmlRoot(ElementName = "body")]
public class ErrorResponseBody
{
[XmlElement("errors")]
public List<Error> errors { get; set; }
}
[XmlRoot(ElementName = "Error")]
public class Error
{
public byte errorId { get; set; }
public string errorDescription { get; set; }
public string errorObjectId { get; set; }
}
I then call the API using a TicketNumber that exists.
I'm using RestSharp for calling the api:
public async void SendRequestAndReceiveResponse()
{
var restClient = new RestClient("https://someapiaddress.net");
var requestXMLBody = "<request><request_id>1</request_id><operation>retrieve</operation><method /><entity>ticket</entity><user>someuser</user><password>somepassword</password><body><ticket><TicketNumber>12345</TicketNumber></ticket></body></request>";
var request = new RestRequest("somexmlwebservice!process.action", Method.POST);
request.AddParameter("xmlRequest", requestXMLBody, "text/xml", ParameterType.QueryString);
var response = await restClient.ExecuteAsync<TicketsResponse>(request);
// Do other stuffs with this response...
}
Now this works very well. Because I know my response will have the ticket and that will correctly deserialize to TicketsResponse object.
But if I call the API using a TicketNumber that doesn't exist, I simply get TicketsResponse object that has an empty list of Tickets because this time I'm getting error response. The status code comes to be OK in this case too.
What I want to do here is that I want to capture the error message from the error response. (Response of either Ticket or Error applies to bunch of other processes as well, so it's important to grab this information in a single call.)
And if I knew this ticket doesn't exist, I could simply call the API this way and capture the errors. But that's not ideal nor even a good idea:
var response = await restClient.ExecuteAsync<ErrorResponse>(request);
So I thought of combining TicketsResponse and ErrorResponse, like this:
[XmlRoot]
public class CombinedResponse
{
[XmlElement(ElementName = "Tickets")]
public TicketsResponse Data { get; set; }
[XmlElement(ElementName = "response")]
public ErrorResponse NonData { get; set; }
}
And get the response using that class:
var response = await restClient.ExecuteAsync<CombinedResponse>(request);
The Status code comes OK (when it returns either data or error message) and I get my correct response in response.Content, but the deserialization doesn't work, so my response.Data will show 2 fields Data and NonData both as null. Ideally I should have gotten either my Ticket data or Error data in response.Data.
So my question is:
Is it possible to make this work using a single class for deserialization?
I have spent too much time on this so any help is appreciated.
Also please look at my model classes and suggest if there's better way of doing things.
This is how I solved this issue.
I'm posting here so others may find it helpful.
If there's a better way of doing this, please advise.
I created a method to call the API and deserialize the response to multiple types:
public async Task<(T1, T2)> SendRequestAndReceiveResponse<T1, T2>(RestRequest request)
{
// This can be done in the constructor so we don't instantiate new client for every request.
var restClient = new RestClient("https://someapiaddress.net");
// Get response:
var response = await restClient.ExecuteAsync(request);
// Log request and response here if you want.
if (response.ErrorException != null)
{
var message = $"An error occured during this request. Check request response entries for more details.";
var newException = new Exception(message, response.ErrorException);
throw newException;
}
else
{
var xmlDeserilizer = new RestSharp.Deserializers.XmlDeserializer();
var data = xmlDeserilizer.Deserialize<T1>(response);
var nonData = xmlDeserilizer.Deserialize<T2>(response);
return (data, nonData);
}
}
And used it, by sending the types I need:
public async Task<IEnumerable<Ticket>> FetchTickets()
{
var xmlRequestBody = "<request><request_id>1</request_id><operation>retrieve</operation><method /><entity>ticket</entity><user>someuser</user><password>somepassword</password><body><ticket><TicketNumber>12345</TicketNumber></ticket></body></request>";
var request = new RestRequest("somexmlwebservice!process.action", Method.POST);
request.AddParameter("xmlRequest", xmlRequestBody, "text/xml", ParameterType.QueryString);
var apiCallResult = await SendRequestAndReceiveResponse<TicketsResponse, ErrorResponse>(request);
if (apiCallResult.Item1 != null && apiCallResult.Item1.HasTickets())
{
// Do something with the tickets...
}
else if (apiCallResult.Item2 != null && apiCallResult.Item2.HasErrors())
{
// Do something with the errors...
}
// And so on...
}
My complete solution. If you just need the answer, please take a look at the accepted answer.
This is more like a documentation of the whole process for anyone who deals with RestSharp and XML.
Request:
To form a request body that looks like this, we need few classes like below:
[XmlRoot(ElementName = "request")]
[XmlInclude(typeof(RequestBodyWithTicketNumberOnly))] // To make sure 'body' can be serialized to RequestBodyWithTicketNumberOnly
public class TicketRequestBase
{
public byte request_id { get; set; }
public string operation { get; set; }
public string method { get; set; }
public string entity { get; set; }
public string user { get; set; }
public string password { get; set; }
// body can have different shapes, so not giving it any specific class name.
public object body { get; set; }
}
[XmlRoot(ElementName = "body")]
public class RequestBodyWithTicketNumberOnly
{
public TicketWithTicketNumberOnly ticket { get; set; }
}
[XmlRoot(ElementName = "ticket")]
public class TicketWithTicketNumberOnly
{
public string TicketNumber { get; set; }
}
A method to convert C# objects into XML strings, like so:
public static string ToXml<T>(T obj)
{
var settings = new XmlWriterSettings
{
Indent = false,
OmitXmlDeclaration = true,
NewLineHandling = NewLineHandling.None,
NewLineOnAttributes = false
};
var objType = obj.GetType();
var serializer = new XmlSerializer(objType);
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, settings))
{
serializer.Serialize(writer, obj, emptyNamespaces);
return stream.ToString();
}
}
A method to return request body as XML string:
public static string GetTicketFetchRequestBody(string ticketNumber)
{
if (ticketNumber== null) throw new ArgumentNullException(nameof(ticketNumber));
var singleTicketRequest = new TicketRequestBase()
{
request_id = 1,
operation = "retrieve",
method = string.Empty,
entity = "ticket",
user = "sauser",
password = "sapassword",
body = new RequestBodyWithTicketNumberOnly() { ticket = new TicketWithTicketNumberOnly { TicketNumber = ticketNumber} }
};
return ToXml(singleTicketRequest);
}
Response:
All the classes for the response are already documented in this question. Please take a look at them.
The top level method that gets the Ticket:
public static async Task<IEnumerable<Ticket>> FetchTickets()
{
var xmlRequestBody = GetTicketFetchRequestBody("12345");
var request = new RestRequest("somexmlwebservice!process.action", Method.POST);
request.AddParameter("xmlRequest", xmlRequestBody, "text/xml", ParameterType.QueryString);
var apiCallResult = await SendRequestAndReceiveResponse<TicketsResponse, ErrorResponse>(request);
if (apiCallResult.Item1 != null && apiCallResult.Item1.HasTickets())
{
// Do something with the tickets...
}
else if (apiCallResult.Item2 != null && apiCallResult.Item2.HasErrors())
{
// Do something with the errors...
}
// And so on...
}
The method that actually calls the API uses Proxy, logs requests and responses, and executes request using Polly retry policy:
public async Task<(T1, T2)> SendRequestAndReceiveResponse<T1, T2>(RestRequest request, bool useProxy = true)
{
// This can be done in the constructor so we don't instantiate new client for every request.
var restClient = new RestClient("https://someapiaddress.net");
if (useProxy) // This variable can even be initialized in the constructor of this RestClient
{
var proxy = GetWebProxy();
restClient.Proxy = proxy;
}
// Request Logging Part:
var requestAsJSONString = GetRequestForLogging(request, restClient);
// Log it using your logging provider.
// Response Part:
var response = await ExecuteAsyncWithPolicy(request, restClient);
// Response Logging Part:
var responseAsString = response.Content;
// Log it using your logging provider.
if (response.ErrorException != null)
{
var message = $"An error occured during this request. Check request response entries for more details.";
var newException = new Exception(message, response.ErrorException);
throw newException;
}
else
{
var xmlDeserilizer = new RestSharp.Deserializers.XmlDeserializer();
var data = xmlDeserilizer.Deserialize<T1>(response);
var nonData = xmlDeserilizer.Deserialize<T2>(response);
return (data, nonData);
}
}
Create Web proxy like so:
private static WebProxy GetWebProxy()
{
var proxyUrl = "http://proxy.companyname.com:9090/";
return new WebProxy()
{
Address = new Uri(proxyUrl),
BypassProxyOnLocal = false,
//UseDefaultCredentials = true, // This uses: Credentials = CredentialCache.DefaultCredentials
//*** These creds are given to the proxy server, not the web server ***
Credentials = CredentialCache.DefaultNetworkCredentials
//Credentials = new NetworkCredential("proxyUserName", "proxyPassword")
};
}
Create the request string with all the parameters like so:
private string GetRequestForLogging(IRestRequest request, IRestClient client)
{
var serializer = new JsonSerializer();
var requestToLog = new
{
// This will generate the actual Uri used in the request
RequestUri = client.BuildUri(request),
// Parameters are custom anonymous objects in order to have the parameter type as a nice string
// otherwise it will just show the enum value
parameters = request.Parameters.Select(parameter => new
{
name = parameter.Name,
value = parameter.Value,
type = parameter.Type.ToString()
}),
// ToString() here to have the method as a nice string otherwise it will just show the enum value
method = request.Method.ToString()
};
return serializer.Serialize(requestToLog);
}
Polly retry policy:
private AsyncPolicy<IRestResponse> GetRetryPolicy()
{
var policy = Polly.Policy.HandleResult<IRestResponse>((response) =>
{
return response.ResponseStatus != ResponseStatus.Completed;
})
//.Or<SomeKindOfCustomException>()
.RetryAsync();
return policy;
}
Call the API using the retry policy:
private async Task<IRestResponse> ExecuteAsyncWithPolicy(IRestRequest request, IRestClient restClient)
{
var policy = GetRetryPolicy();
var policyResult = await policy.ExecuteAndCaptureAsync(async () => await restClient.ExecuteAsync(request));
return (policyResult.Outcome == OutcomeType.Successful) ? policyResult.Result : new RestResponse
{
Request = request,
ErrorException = policyResult.FinalException
};
}
Hope this was helpful.
This is one of my first ventures into WCF/JSON. I created a WCF Web Service. This is one of my methods. It is how I serialize the datable to JSON.
public string GetPrayers()
{
DataTable myDt = new DataTable();
myDt = sprocToDT("LoadPrayers");
string JSONString = string.Empty;
JSONString = JsonConvert.SerializeObject(myDt, Formatting.None);
return JSONString;
}
This returns a nice JSON Dataset:
{"GetPrayersResult":"[{\"prayerid\":2,\"prayer\":\"Please pray for my
dog Rusty. He has cancer
:(\",\"prayerCategory\":\"General\",\"prayerDate\":\"2017-06-10T21:24:16.1\",\"handle\":\"GuruJee\",\"country\":\"USA\"},{\"prayerid\":1,\"prayer\":\"Help
Me I need a appendectomy
STAT\",\"prayerCategory\":\"Sports\",\"prayerDate\":\"2017-04-10T20:30:39.77\",\"handle\":\"GuruJee\",\"country\":\"USA\"}]"}
When I go to deserialize it I get all nulls. Here is the classes I created:
public class PrayUpPrayers
{
public string prayer { get; set; }
public string prayerid { get; set; }
public string prayerCategory { get; set; }
public string prayerCategoryID { get; set; }
public string prayerDate { get; set; }
public string handle { get; set; }
public string country { get; set; }
}
public class ThePrayer
{
public PrayUpPrayers prayers { get; set; }
}
}
This is how I am retrieving the JSON:
void getData()
{
var request = HttpWebRequest.Create(string.Format(#"URLGoesHere"));
request.ContentType = "application/json";
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
Console.Out.WriteLine("Error fetching data. Server returned status code: {0}", response.StatusCode);
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var content = reader.ReadToEnd();
string foo = content.ToString();
var testing = JsonConvert.DeserializeObject<prayupapp.ModelClasses.PrayUpPrayers>(foo,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
});
Testing is always null? Is the issue that I am serializing it wrong, could it be the class structure, or is it related to how I am deserializing it. One important note: I checked my JSON on one of these JSONClassesFromC# sites and it only returns the GetPrayersResult as the only class item. Ignoring completely my entire structure.
You didn't provide the code for sprocToDT, but it should create ThePrayer object witch should contain list of PrayUpPrayers
public class ThePrayer
{
public List<PrayUpPrayers> prayers { get; set; }
}
And then you should deserialize ThePrayer object, not PrayUpPrayers.
For example
PrayUpPrayers prayUpPrayers1 = new PrayUpPrayers
{
prayer = "Please pray for my dog Rusty. He has cancer",
prayerid = "2",
prayerCategory = "General",
prayerDate = "2017-06-10T21:24:16.1",
handle = "GuruJee",
country = "USA"
};
PrayUpPrayers prayUpPrayers2 = new PrayUpPrayers
{
prayer = "Help Me I need a appendectomy STAT",
prayerid = "1",
prayerCategory = "Sports",
prayerDate = "2017-04-10T20:30:39.77",
handle = "GuruJee",
country = "USA"
};
ThePrayer thePrayer = new ThePrayer
{
prayers = new List<PrayUpPrayers>
{
prayUpPrayers1, prayUpPrayers2
}
};
myDt in your code should be the same as thePrayer instance in my code.
JSONString = JsonConvert.SerializeObject(myDt, Formatting.None);
will provide Json that looks like
"{\"prayers\":[{\"prayer\":\"Please pray for my dog Rusty. He has
cancer\",\"prayerid\":\"2\",\"prayerCategory\":\"General\",\"prayerCategoryID\":null,\"prayerDate\":\"2017-06-10T21:24:16.1\",\"handle\":\"GuruJee\",\"country\":\"USA\"},{\"prayer\":\"Help
Me I need a appendectomy
STAT\",\"prayerid\":\"1\",\"prayerCategory\":\"Sports\",\"prayerCategoryID\":null,\"prayerDate\":\"2017-04-10T20:30:39.77\",\"handle\":\"GuruJee\",\"country\":\"USA\"}]}"
And deserialize will look like
var testing = JsonConvert.DeserializeObject<prayupapp.ModelClasses.ThePrayer>(foo,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
});
that's simple. you should deserilze the output twice. try this:
var output= DeserializeObject<string>(foo);
var testing = JsonConvert.DeserializeObject<prayupapp.ModelClasses.PrayUpPrayers>(output,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
});
[{
"channel_id":299,
"requests":[{
"order_id":3975,
"action":"REQUEST_LABELS"
}]
}]
How to create the above request in c# the requests can be multiple.
I am new to c# i tried the below:
Dictionary<long, List<object>> requestObject = new Dictionary<long, List<object>>();
List<object> listrequestObjects = new List<object>();
Request requestOb = new Request();
requestOb.order_id = 2372;
requestOb.action = "REQUEST_LABELS";
listrequestObjects.Add(requestOb);
requestObject.Add(2352635, listrequestObjects);
string requesttest = JsonConvert.SerializeObject(requestObject);
But getting a weird request. Please help.
The structure should look like :
public class Request
{
public int order_id { get; set; }
public string action { get; set; }
}
public class RootObject
{
public int channel_id { get; set; }
public List<Request> requests { get; set; }
}
You need to declare the root object also:
[Serializable]
public class Root {
public int channel_id;
public Request[] requests;
}
Then assign the value and serialize it:
var root = new Root();
root.channel_id = 299;
root.requests = listrequestObjects.ToArray();
string requesttest = JsonConvert.SerializeObject(root);
You can use Newtonsoft.Json.
try this
private JArray GetResponse()
{
var main_array = new JArray();
var channel_id = new JObject();
channel_id.Add("channel_id",299);
var request = new JArray();
var order_id = new JObject();
order_id.Add("order_id",3975);
var action = new JObject();
action.Add("action","REQUEST_LABELS");
request.Add(order_id);
request.Add(action);
main_array.Add(channel_id);
main_array.Add(request);
return main_array;
}
Please try the JavaScriptSerializer class available in namespace
using System.Web.Script.Serialization
JavaScriptSerializer js = new JavaScriptSerializer();
string result = js.Serialize(requestObject);
The requestObject list is your custom class with all necessary properties.
Thanks
I am new to RestSharp. I have a Restful Service writtein in python which returns a Json message. I wrote a C# client using RestSharp to deserialize the json message to object.
The response content is
"\"[{\\"coupon\\": 4.5, \\"cusip\\": \\"912810QB7\\", \\"currface\\": 1000000, \\"origface\\": 1000000}]\""
response.data is null.
The inner Exception in response object is
"Unable to cast object of type 'System.String' to type 'System.Collections.Generic.IDictionary`2[System.String,System.Object]'."
Below are my code:
public class QuartzServiceAdapter
{
const string BaseUrl = "http://localhost:7666/ahs/";
public QuartzServiceAdapter() { }
public T Execute<T>(RestRequest request) where T : new()
{
var client = new RestClient();
client.BaseUrl = BaseUrl;
var response = client.Execute<T>(request);
return response.Data;
}
public List<RootObject> GetBond()
{
var request = new RestRequest(Method.GET);
request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; };
request.Resource = "getabond";
//request.RootElement = "RootObject";
return Execute<List<RootObject>>(request);
}
}
i created the following object using http://json2csharp.com/
public class RootObject
{
public double coupon { get; set; }
public string cusip { get; set; }
public int currface { get; set; }
public int origface { get; set; }
}
Any ideas on why the deserialization is failing?
Thank you in advance!
I'm trying to deserialize a rest uri located at http://ws.geonames.org/countryInfo?lang=it&country=DE and keep getting error (There is an error in XML document (1, 1)). Plug http://ws.geonames.org/countryInfo?lang=it&country=DE into the browser and you can see the result.
I have a class
public class Country
{
public string CountryName {get;set;}
public string CountryCode {get;set;}
}
and the method in my console app is as follows:
static void DeserializeTheXML()
{
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "countryName";
xRoot.IsNullable = true;
XmlSerializer ser = new XmlSerializer(typeof(Country), xRoot);
XmlReader xRdr = XmlReader.Create(new StringReader("http://ws.geonames.org/countryInfo?lang=it&country=DE"));
Country tvd = new Country();
tvd = (Country)ser.Deserialize(xRdr);
Console.WriteLine("Country Name = " + tvd.CountryName);
Console.ReadKey();
}
any ideas on how to deserialize this rest service? thanks..
For serialization to work successfully you need to decorate your objects with the proper serialization attributes or use the XmlAttributeOverrides constructor. Also don't forget that XML is case sensitive and your objects must reflect the XML structure you are deserializing:
public class GeoNames
{
[XmlElement("country")]
public Country[] Countries { get; set; }
}
public class Country
{
[XmlElement("countryName")]
public string CountryName { get; set; }
[XmlElement("countryCode")]
public string CountryCode { get; set; }
}
class Program
{
static void Main()
{
var url = "http://ws.geonames.org/countryInfo?lang=it&country=DE";
var serializer = new XmlSerializer(typeof(GeoNames), new XmlRootAttribute("geonames"));
using (var client = new WebClient())
using (var stream = client.OpenRead(url))
{
var geoNames = (GeoNames)serializer.Deserialize(stream);
foreach (var country in geoNames.Countries)
{
Console.WriteLine(
"code: {0}, name: {1}",
country.CountryCode,
country.CountryName
);
}
}
}
}