Viser opslag med etiketten json. Vis alle opslag
Viser opslag med etiketten json. Vis alle opslag

onsdag den 4. april 2012

REST, JSON and WCF

Representational State Transfer (or REST) has seen a rise in popularity in the last few years. I think this has to do with the webbrowser becomming a platform in its own and the need for an easy to use and read web service has increased. Today you might have mobile apps, clientside applications, websites or even embedded software that needs to gather data from a single service.

SOAP has it's uses but when it comes to humanreadability, ease of implementation and it's lightweightness there is nothing better than REST.

There are hundreds of ways to implement a REST service, im a .NET developer and such will use those tools to build it. You can emulate a lot of the REST behaviour using the MVC framework but i will be creating a real REST service in WCF.NET4.

Start by creating a standard WCF Service in Visual Studio. By default it will be setup to use SOAP. So the first thing we have to do is change it to REST. To do that right-click your .svc file and choose "view markup". At the end of the line (inside the tag) add:

Factory="System.ServiceModel.Activation.WebServiceHostFactory"

It should look somewhat similiar to this:

<%ServiceHost 
    language=c#
    Debug="true"
    Service="Microsoft.Samples.Service"
    Factory=System.ServiceModel.Activation.WebServiceHostFactory%>

You can now add your methods to your service interface. A couple of annotations need to be present for the service to know what you want to do. The following example of a method, takes a JSON string as a parameter and returns JSON as the result.
[OperationContract]
        [WebInvoke(
            BodyStyle = WebMessageBodyStyle.Bare,
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
            UriTemplate = "/ReportService?request={json}")]
        void ReportService(String json);

You can go ahead and implement it in your svc class now. Im using JSON.Net for my serializing and deserializing needs when it comes to JSON. You can get it here: http://json.codeplex.com/ or via NuGET, which ever you prefer.
This sample method deserializes the json request, works with the data and serializes objects for the json response.

        public string ForecastService(string json)
        {
            if (String.IsNullOrEmpty(json))
            {
                throw new ArgumentNullException("json", "request cannot be null or empty");
            }

            var request = JsonConvert.DeserializeObject(json, typeof(Model.ForecastServiceRequestObject));
            var response = new ForecastServiceResponseObject();
            
            //Do something with the request

            var jsonResponse = JsonConvert.SerializeObject(response, Formatting.Indented);

            HttpContext.Current.Response.ContentType = "application/json; charset=utf-8";
            HttpContext.Current.Response.Write(jsonResponse);
        }

Lines 15 and 16 use the basic ways to communicate via the HTTP protocol. By writing to the response and setting the ContentType mime we give browsers and applications optimal chance of understanding what we are sending. This is also why our return type is "void". We are not returning anything, were writing a response like any webpage would.

Running the service now will most likely result in an error. Seeing as we are using HttpContext the service will need certain tools from ASP.NET. This is fixed easily. Simply add the following to your web.config

 

  
    
  


Optionally decorate your service with the following annotation to force it through.

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

That's it, you are now ready to deliver data to the world.

torsdag den 22. marts 2012

Working with Facebook Graph API

Facebook is fast becomming the most updated source of information on a lot of companies, especially in the entertainment industry. This post will help you get event data from Facebook onto your own site.

First thing you need to do is get familiar with Graph API Explorer: https://developers.facebook.com/tools/explorer

It's a wonderful tool that will help you construct your API calls. For this tutorial we will only work with events. Events are however one of the most "fragmented" types of data Facebook offers. To get a full list of events, including all data, for a given page we need to make quite a few requests.

Next thing to do is to setup access to an accesstoken. Facebook requires this token for all API calls outside of Graph Explorer. Basicly what we need is ClientSecret and ClientID. Both of those can be obtained from your Facebook App. If you dont have a Facebook App you should read this article: https://developers.facebook.com/docs/authentication/server-side/

Now we have all our basics in place. I will be using a nightclub called Fabric London for this tutorial.

We will be making a lot of call to Facebook, so the first thing we need to create is a method that can call a URL and return the JSON string.

/// 
        /// Gets stream of data from a given website URL
        /// 
        /// URL of the website        /// String
        public static String GetWebStream(String url)
        {
                // used to build entire input
                var sb = new StringBuilder();

                // used on each read operation
                byte[] buf = new byte[8192];

                // prepare the web page we will be asking for
                var request = (HttpWebRequest)
                    WebRequest.Create(url);

                HttpWebResponse response = null;
                try
                {
                // execute the request
                response = (HttpWebResponse)
                    request.GetResponse();
                }
                catch (Exception e)
                {
                    //Handle error
                }

                // we will read data via the response stream
                var resStream = response.GetResponseStream();

                string tempString = null;
                var count = 0;

                do
                {
                    // fill the buffer with data
                    count = resStream.Read(buf, 0, buf.Length);

                    // make sure we read some data
                    if (count != 0)
                    {
                        // translate from bytes to ASCII text
                        tempString = Encoding.ASCII.GetString(buf, 0, count);

                        // continue building the string
                        sb.Append(tempString);
                    }
                }
                while (count > 0); // any more data to read?

                return sb.ToString();
        }

from here on we can obtain our access token using GetWebStream method
//Get a new and valid authtoken
                var AuthToken =
                    WebStream.GetWebStream("https://graph.facebook.com/oauth/access_token?grant_type=client_credentials&client_id=" +
                                 AppID + "&client_secret=" + AppSecret);

With a valid access token we can now get the first part of our event stream. I have added a few extra parameters to limit it to current events (from today and 1 month forward). We also only want the next 10.

var stream = WebStream.GetWebStream("https://graph.facebook.com/FabricLondon/events?since=today&until=1 month&limit=10&" + AuthToken);

You should now have your stream variable containing a lightweight list of Events held at FabricLondon. But these events are missing certain parameters such as the image, description and how many have signed up already. To dig further into the events we will need to serialize the JSON stream into C# objects. Since MVC3 doesn't ship with a JSON serializer for this sort of task you will need to find one. I personally am very fond of JSON.NET (http://json.codeplex.com/) which makes it very easy to serialize and deserialize between C# objects and JSON.

To serialize we will need to recreate the JSON in C# Classes. You can use the following for events:
private class AttendingCollection
        {
            public List<attending> data { get; set; }
        }

        private class Attending
        {
            public String name { get; set; }
            public String id { get; set; }
            public String attending { get; set; }
        }

        private class LightEventCollection
        {
            public List<lightevent> data { get; set; }
        }

        private class LightEvent
        {
            public String name { get; set; }
            public String start_time { get; set; }
            public String end_time { get; set; }
            public String location { get; set; }
            public String id { get; set; }
        }

        private class Event
        {
            public String id { get; set; }
            public String name { get; set; }
            public String description { get; set; }
            public String start_time { get; set; }
            public String end_time { get; set; }
            public String location { get; set; }
            public String ImageURL { get; set; }

            public Venue venue { get; set; }
            public int Attendees { get; set; }
        }

        private class Venue
        {
            public String latitude { get; set; }
            public String longitude { get; set; }
            public String id { get; set; }
        }

        private class EventViewModel
        {
            public String ID { get; set; }
            public String Description { get; set; }
            public String StartTime { get; set; }
            public String EndTime { get; set; }
            public String ImageURL { get; set; }
            public String Name { get; set; }
            public Venue Venue { get; set; }
            public int Attendees { get; set; }
        }

        private class EventViewModelCollection
        {
            public List<eventviewmodel> events { get; set; }
        }
The ViewModels are our custom made Events that hold all the event info we gather from Facebook.


The stream we got from facebook only contains lightweight events, and we will need to serialize those and get the full events for each of the lightweights:
var lightWeightEvents = JsonConvert.DeserializeObject<lighteventcollection>(stream);
var events = GetEventsGraph(lightWeightEvents.data.ToList(), authToken);

private static IEnumerable<event> GetEventsGraph(IEnumerable<lightevent> lightEvents, String authToken)
        {
            var events = new List<event>();
            foreach (var lightEvent in lightEvents)
            {
                var stream = WebStream.GetWebStream("https://graph.facebook.com/" + lightEvent.id + "&" + authToken); 
                var detailedEvent = JsonConvert.DeserializeObject<event>(stream);

                //Get the amount of people signed up for the event
                var attendee = WebStream.GetWebStream("https://graph.facebook.com/" + lightEvent.id + "/attending?limit=999999&" + authToken);
                var attendees = JsonConvert.DeserializeObject<attendingcollection>(attendee);
                detailedEvent.Attendees = attendees.data.Select(m => m.attending == "attending").Count();
                
                events.Add(detailedEvent);
            }
            return events;
        }
What this method does is iterate across all our lightweights, calling facebook for the full details aswell as getting the list of attendees. Once it's un we can return our full list of events and start creating our custom class.

Here we have our full method:

public static String GetEventViewModels(String stream, String authToken)
        {
            var lightWeightEvents = JsonConvert.DeserializeObject<lighteventcollection>(stream);
            var events = GetEventsGraph(lightWeightEvents.data.ToList(), authToken);
            var viewModels = events.Select(item => new EventViewModel()
                                                       {
                                                           ID = item.id, 
                                                           Description = item.description, 
                                                           StartTime = item.start_time, 
                                                           EndTime = item.end_time, 
                                                           Name = item.name, 
                                                           ImageURL = item.ImageURL, 
                                                           Venue = item.venue,
                                                           Attendees = item.Attendees
                                                       }).ToList();
             viewModels.Sort((x, y) => DateTime.Parse(x.StartTime).CompareTo(DateTime.Parse(y.StartTime)));
            var col = new EventViewModelCollection()
                       {
                           events = viewModels
                       };

            return JsonConvert.SerializeObject(col);
        }
We end it up by serializing the data back into JSON, ready to send to your view or client.

For the full FacebookEvent class see this pastebin: http://pastebin.com/jXheywqi