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

tirsdag den 20. marts 2012

Caching JSONP requests in MVC3

JSONP is quite nice for situations where you have a large number of client running from different domains, and they all need data from you.

MVC3 does not support JSONP natively. An employee from Microsoft called Ranju has blogged his approach to adding JSONP to MVC3. I like his implementation and it's a pretty straight forward copy/paste to use in your projects. Check it out here: blogorama.nerdworks.in

However if the data takes too long to generate you might want to cache the output.

This is where you run into problems when the client uses standard ways to request JSONP data. The callback parameter has to be made static.

This is the standard jQuery behaviour to fetch JSONP:
$.getJSON("http://YourSite/Controller/GetJSONP?callback=?")

The '?' is automaticly set to a unique value by jQuery which will result in either 2 things for a normal Cacheoutput

  • Your cache is bypassed since your parameters are changing by each request
  • The client breaks because the callback you return isnt the one it stated in it's URL
This is one way to fix these issues:
Instead of using $.getJSON() use $.getScript() instead. With getScript you can specify a static callback parameter.
$.getScript(" http://YourSite/Controller/GetJSONP?callback=DataDownloaded", function(data) {
alert('done'); 
});

function  DataDownloaded (data)
{
alert('done');  
} 

jQuery still adds a unique ID to the actual URL but we can work past that.

This is our method in our controller:
[OutputCache(Duration = 60*30 /* 30mins */, VaryByParam = "callback")]
public JsonpResult GetJSONP(String _, String callback)
{
//Your code here
}
It takes 2 parameters. '_' is generated by jQuery as a unique id. Callback is what we manually set to a static value.

I then added the OutputCache annotation, set the duration to 30 minutes and set it to vary only by "callback".

The result is a cache is built for every unique callback parameter, but jquerys '_' parameter is ignored.

Our result is a slender, fast and working cache that works with JSONP

Update 4/4-2012.
Another way to aproach the problem is to deal with it clientside. By using jQuery.ajax and it's cache setting you can remove the timestamp property alltogether.

cacheBoolean
Default: true, false for dataType 'script' and 'jsonp'
If set to false, it will force requested pages not to be cached by the browser. Setting cache to false also appends a query string parameter, "_=[TIMESTAMP]", to the URL.
More info here: http://api.jquery.com/jQuery.ajax/
Thank you Marc Brooks for this information

mandag den 19. marts 2012

Localizing enums in MVC3

Enums are great for a developer to easily remember and set various constants. Sometimes you also need to present the enum to your user. Often this is done with a Listbox or a Combobox where the user chooses between the enums. By default .Net4 doesn't support localizing or even changing the text values to make it readable and understandable by your users.

Here's how you can create an enum, localize it and present it i your view.

Create your Enum:
public enum FacebookModules
        {
            Feed = 1,
            Posts,
            Events,
            Gallery
        }
Create an extension to the enum class and add a new description value to it:
public class LocalizedEnumAttribute : DescriptionAttribute
    {
        private PropertyInfo _nameProperty;
        private Type _resourceType;

        public LocalizedEnumAttribute(string displayNameKey)
            : base(displayNameKey)
        {

        }

        public Type NameResourceType
        {
            get
            {
                return _resourceType;
            }
            set
            {
                _resourceType = value;

                _nameProperty = _resourceType.GetProperty(this.Description, BindingFlags.Static | BindingFlags.Public);
            }
        }

        public override string Description
        {
            get
            {
                //check if nameProperty is null and return original display name value
                if (_nameProperty == null)
                {
                    return base.Description;
                }

                return (string)_nameProperty.GetValue(_nameProperty.DeclaringType, null);
            }
        }
    }

    public static class EnumExtender
    {
        public static string GetLocalizedDescription(this Enum @enum)
        {
            if (@enum == null)
                return null;

            string description = @enum.ToString();

            FieldInfo fieldInfo = @enum.GetType().GetField(description);
            DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);

            if (attributes.Any())
                return attributes[0].Description;

            return description;
        }
    }

You can now add your new attribute to your enums by using this annotation:
[LocalizedEnum("Facebook_Feed", NameResourceType = typeof(Resources.Resources))]

Your enum should look a bit like this:
public enum FacebookModules
        {
            [LocalizedEnum("Facebook_Feed", NameResourceType = typeof(Resources.Resources))]
            Feed = 1,

            [LocalizedEnum("Facebook_Posts", NameResourceType = typeof(Resources.Resources))]
            Posts,

            [LocalizedEnum("Facebook_Events", NameResourceType = typeof(Resources.Resources))]
            Events,

            [LocalizedEnum("Facebook_Gallery", NameResourceType = typeof(Resources.Resources))]
            Gallery
        }

From here on you can simply call the method MyEnumInstance.GetLocalizedDescription() to get your localized name. If no ressource file is setup or the value can't be found in it, it will default to the LocalizedEnum name.

Now if you want to use this in a standard combobox in your MVC view you can do something like this:

@Html.DropDownListFor(model => model.ContentType, Enum.GetValues(typeof(Enums.FacebookModules)).Cast<enums.facebookmodules>().Select(v => new SelectListItem
                       {
                           Text = v.GetLocalizedDescription(),
                           Value = v.ToString().Replace("_", " ")
                       }))

Thats it!

fredag den 26. november 2010

How to test applications written in JavaScript

Anyone who has tried to build a mobile application using JavaScript has been in a situation where they have tested their application as much as you can in your desktop browser but once you get it on your phone it doesnt work like its suppose to.

Well someone has tried that situation so many times that they finally did something about it. Introducing "Ripple" an extension to Chrome that allows you to test your web-app under a wide range of supported platforms. Once you select a platform you can setup what kind of device you want it it emulate. Say you want to test your web-app on an iPhone simply select that as well the orientation of the screen (portrait/landscape).

Your application is now being shown emulated on an iPhone. From here you have a bunch of tools at your disposal.

  • Accelerometer - Send input to your application from the emulated accelerometer, you could tell it, it's being tilted sideways and should adapt to landscape mode instead for instance. 
  • Geo Location - Does your application use input from the GPS? You can also send coordinates among other geo info to it.
  • Storage - Need to store something on the phone? Using the key/value storage you can do this as well.

Ripple also supports phonegap and could be used to test your application before compiling it to a real app on Android or iOS. For a list which parts of the phonegap API Ripple supports see this site

The only downside to Ripple is that it doesn't work with file system paths, so you need to set up a web server to use it. (more info here)

Since the Ripple homepage is remarkably empty of screenshots i have made one for you. It's the mobile twitter site running in phonegap on an iPhone

Screenshot of Twitter Mobile running in ripple
Ripple homepage: Ripple
Installing ripple: Installing Ripple

torsdag den 25. november 2010

Write once, Test, Build in the Cloud and Publish

In an earlier blogpost i wrote about a wonderous new technology called "Phonegap" that allowed you to publish apps written in Javascript to just about any mobile platform.

The biggest problem with Phonegap was that you had to install the SDK and IDE's unique to each platform which complicated the build process a whole lot.

They have tackled this problem with a new initiative. The concept is quite simple, why compile it yourself when you can have it done correctly and proffesionaly the first time on Phonegaps servers?

Build in the Cloud
With their new 'cloud-build' service all you have to do is write your Javascript/HTML5 against the generic Phonegap Javascript API. Once your done you upload your app in an zip file or similiar, select which platforms you wan't to publish to and hit done. When the server is finished you will get access to your platform specific apps ready to be added to the markets.

Market limitations
Not all platforms are currently supported, most notably iOS and WP7 aren't available yet. This is not a technological barrier, this is simply due to legal concerns with Apple and Microsoft. Issues that are currently being ironed out and hopefully means we will be able to get out apps built for those platforms as well.
PhoneGaps Cloud build server supports
Building apps for a mobile phone no longer requires tedious work installing IDE's or SDK, nor does it require any knowledge or experience in Java, Silverlight or ObjectC. Anyone with 30 minutes to learn the basics of JavaScript can get started. The mobile platform is truly wondrous.

Phonegap Cloud Build: http://build.phonegap.com/

mandag den 18. oktober 2010

How important have Apps become?

I have often asked myself how important Apps really are, are they worth spending time and money developing or even blogging about. There are a lot of statistics out there that try and answer this question but collating them all into something usable isn't easy.

Today i found the picture below on a site called SocialMediaGraphics.They manage to condense all these statistics into a really nice view into what kind of interrest you can hope to achieve with a given product. 

I won't be going into much detail or try to conclude anything from the poster, i will leave that up to you.

It is however nice to see Maps/Navigation so high up in the ranks. I work with GIS (Geographic Information Systems) and it just shows that this business is moving to the handheld device at a rapid pace. If i had a business that had products that fit into the first 5 of the most popular app types i would definitely consider the mobile platform as a place to expand and invest.

Click the poster to see it fullscreen