Search code examples
c#asp.netasp.net-mvcparsingfilehelpers

How to issue GET request and parse result to list


Data contains place_id and other columns:

place_id    name    city    address ..
133 place1  Laagri  Born 12 ..
161 place2  Mourdi  Karve 12  ..

Data is avaliable in 5 different formats. All those urls return same data:

http://www.smartpost.ee/places.html
http://www.smartpost.ee/places.xml
http://www.smartpost.ee/places.csv
http://www.smartpost.ee/places.js
http://www.smartpost.ee/places.php

One of urls should selected to get data. Data may change so it should not cached. How to issue http GET requet and create two element List: first element is place_id from first column and second element is concatenated name, city and address field. Something like:

class DeliveryList {
   public string Id, Address;
  }

List<DeliveryList> res= GetAndParse("http://www.smartpost.ee/places.csv", 
    "place_id, name+\" \"+ city +\" \" + address" );

How to implement GetAndParse ? Should http request saved to sting and filehelpers used to parse it ? Expression "place_id, name+\" \"+ city +\" \" + address" can hard-coded in code instead of passing as parameter.

Using ASP.NET MVC4, .NET 4, C# . Code should run in MVC4 controller in server.


Solution

  • I suggest you to use XML endpoint and implement deserialization to array of places as implemented below:

    public static class PlacesHelper
    {
        private const string EndpointUrl = "http://www.smartpost.ee/places.xml";
    
        /// <summary> Load array of places </summary>
        public static async Task<Places> LoadPlacesAsync()
        {
            var xmlString = await HttpRequestHelper.DownloadStringAsync(EndpointUrl);
            return SerializationHelper.DeserializeXmlString<Places>(xmlString);
        }
    }
    
    public static class SerializationHelper
    {
        /// <summary> Deserializes Xml string of type T. </summary>
        public static T DeserializeXmlString<T>(string xmlString)
        {
            T tempObject = default(T);
    
            using (var memoryStream = new MemoryStream(StringToUTF8ByteArray(xmlString)))
            {
                var xs = new XmlSerializer(typeof (T));
                var xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
    
                tempObject = (T) xs.Deserialize(memoryStream);
            }
    
            return tempObject;
        }
    
        /// <summary> Convert String to Array </summary>
        private static Byte[] StringToUTF8ByteArray(String xmlString)
        {
            return new UTF8Encoding().GetBytes(xmlString);
        }
    }
    
    public static class HttpRequestHelper
    {
        /// <summary> Download String Async </summary>
        public static async Task<string> DownloadStringAsync(string uri)
        {
            var client = new WebClient();
            return await client.DownloadStringTaskAsync(uri);
        }
    }
    
    [Serializable]
    [XmlRoot("places_info", Namespace = "")]
    public class Places
    {
        [XmlElement("place", typeof(Place), Form = XmlSchemaForm.Unqualified, IsNullable = false)]
        public Place[] Place { get; set; }
    }
    
    [Serializable]
    public class Place
    {
        [XmlElement("place_id")]
        public string Id { get; set; }
    
        [XmlElement("name")]
        public string Name { get; set; }
    
        [XmlElement("city")]
        public string City { get; set; }
    
        [XmlElement("address")]
        public string Address { get; set; }
    }
    

    Usage:

    var arrayOfPlaces = await PlacesHelper.LoadPlacesAsync();
    

    So, you will get an array of places (id, name, city, address).

    UPDATE:

    For .NET Framework 4 Microsoft released the Async Targeting Pack (Microsoft.Bcl.Async) through Nuget. So Install the package 'Microsoft Async' from Nuget and you will be able to use async/await.

    Example implementation of controller action:

    public class TestController : Controller
    {
        public async Task<object> GetPlaces()
        {
            return Json(await PlacesHelper.LoadPlacesAsync(), JsonRequestBehavior.AllowGet);
        }
    }