We will be getting data from a website and then showing it in our apps (Windows, Android or iOs etc). It can be done using ‘service’.
Question: How you can write a SERVICE that runs across Windows, Windows Phone, Android and iOs?
Answer: You can do this using ‘Portable Class Library’ in C#.
What is Portable Class Library?
Using the Portable Class Library project in visual studio, you can build portable assemblies that work without modification on the .NET Framework, Silverlight, Windows Phone 7, or Xbox 360 platforms. Without the Portable Class Library project, you must target a single platform and then manually rework the class library for other platforms. The Portable Class Library project supports a subset of assemblies from these platforms, and provides a Visual Studio template that makes it possible to build assemblies that run without modification on these platforms.
What does Portable class library do?
- Exposes a single method to request a RESTFULL client
REST (REpresentational State Transfer) is a simple stateless architecture that generally runs over HTTP. Stateless means there is no record of previous interactions and each interaction request has to be handled based entirely on information that comes with it. REST involves reading a designated Web page that contains an XML file. The XML file describes and includes the desired content.
REST is often used in mobile applications, social networking Web sites, mashup tools and automated business processes. The REST style emphasizes that interactions between clients and services is enhanced by having a limited number of operations (verbs). Flexibility is provided by assigning resources (nouns) their own unique universal resource indicators (URIs). Because each verb has a specific meaning (GET, POST, PUT and DELETE), REST avoids ambiguity.
- Retrieve JSON output
- Desacralize resultant string in objects
- Expose custom events that can be hooked by calling thread signaling either completion of routine or raising an error.
Let’s do it now!
Begin with File > New Project > Portable Class Library
http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-48-94/8475.1_2D00_-Portable-Class-Library
Note that the library will work well with Xamarin based iOS and Android apps as well.
http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-48-94/6648.2_2D00_-Add-Portable-Class-Library
Delete the existing class, Class1.cs and let us organize the project namespaces by introducing folders as follows,
– Client will contain the class that will request REST endpoint.
– Events will server Event Arguments classes for our custom defined event
– Response to host objects relative to JSON serialization
Now before we begin introducing classes, we know that upon requesting the weather RESTFUL API endpoint (http://api.openweathermap.org/data/2.5/weather?q=Lahore,pk) we’ll receive JSON output. We’ll have to deserialize JSON output in corresponding classes found in Response folder. Mr. Usman-ur-Rehman have covered the process of yielding JSON classes from JSON string in an article however in this post we’ll see how to include NewtonSoft’s JSON DLL using Library Package Manager Console.
Go to Library Package Manager Console from Menu,
Once the Package Manager Console is activated, execute following command,
PM> install-package Newtonsoft.Json
This will download the relative library, include reference to portable DLL in our project (since we’re working on Portable Class Library).
Let’s go ahead and introduce EventArgs and WeatherHttpClient classes in our solution. Here’s how the code of WeatherHttpClient looks like,
public delegate void RequestCompletedEventHandler(object sender, RequestEventArgs e); public delegate void RequestErrorEventHandler(object sender, RequestEventArgs e); public class WeatherHttpClient { public event RequestCompletedEventHandler RequestCompleted; public event RequestErrorEventHandler RequestError; public void Request(string location) { try { var request = HttpWebRequest.Create(@"http://api.openweathermap.org/data/2.5/weather?q=" + location); request.Method = "GET"; var result = (IAsyncResult)request.BeginGetResponse(ResponseCallback, request); } catch (Exception ex) { if (RequestError != null) { //Raise Request Error (with custom Exception during response call back) RequestError(this, new RequestEventArgs() { IsError = true, ErrorMessage = Constants.REQUEST_EXCEPTION, Exception = ex }); } } } private void ResponseCallback(IAsyncResult result) { try { var request = (HttpWebRequest)result.AsyncState; var response = request.EndGetResponse(result); using (var stream = response.GetResponseStream()) using (var reader = new StreamReader(stream)) { string contents = reader.ReadToEnd(); ParseJson(contents); } } catch (Exception ex) { if (RequestError != null) { //Raise Sync Error (Custom Exception during response call back) RequestError(this, new RequestEventArgs() { IsError = true, ErrorMessage = Constants.REQUEST_CALLBACK_EXCEPTION, Exception = ex }); } } } private void ParseJson(string jsonString) { try { RootObject rootObject = new RootObject(); rootObject = JsonConvert.DeserializeObject<RootObject>(jsonString); if(RequestCompleted!= null) { RequestCompleted(this, new RequestEventArgs() { IsError = false, ErrorMessage = string.Empty, Exception = new NotSupportedException(Constants.GRACEFUL_EXECUTION_MESSAGE), RootObject = rootObject }); } } catch (Exception ex) { if(RequestError!= null) { //Raise Sync Error (Custom Exception during parsing) RequestError(this, new RequestEventArgs() { IsError = true, ErrorMessage = Constants.REQUEST_PARSE_JSON_EXCEPTION, Exception = ex }); } } } }
Please note that in case of an exception or graceful execution we raise different event however a shared RequestEventArgs class is used
public class RequestEventArgs : EventArgs { public RequestEventArgs() { ErrorMessage = string.Empty; IsError = false; RootObject = new RootObject(); Exception = new NotImplementedException(Constants.NOT_IMPLEMENTED_EXCEPTION_MESSAGE); } /// <summary> /// Will denote whether the call was successful or not /// </summary> public bool IsError { get; set; } /// <summary> /// In case of an error, the error message /// </summary> public string ErrorMessage { get; set; } /// <summary> /// Refers to Inner exception within Weather Client (if any) /// </summary> public Exception Exception { get; set; } /// <summary> /// Root Object will host the JSON deserialized POCO classes in case of no error /// </summary> public RootObject RootObject { get; set; } }
Where Constants can be found in Constants.cs file kept on root of WeatherClient project,
public class Constants { public const string REQUEST_EXCEPTION = "Error while making http request."; public const string REQUEST_PARSE_JSON_EXCEPTION = "Error in parsing JSON output."; public const string REQUEST_CALLBACK_EXCEPTION = "Please ensure your device is connected with the internet."; public const string NOT_IMPLEMENTED_EXCEPTION_MESSAGE = "Request is unitialized"; public const string GRACEFUL_EXECUTION_MESSAGE = "The last request completed gracefully without any exception."; }
To keep the source code size small, other DLLs from Netwonsoft’s packages are deleted than referenced one (Newtonsoft.Json.6.0.1libportable-net40+sl5+wp80+win8+monotouch+monoandroid at the time of this writing).
Original post at Microsoft Pakistan Blog by Mr. Usman-Ur-Rehman