Turn Your Google Drive Folder In An Online Album Viewer

4. May 2014 15:09

API ASP.NET MVC C# Projects Web 

Working with Google Drive API is fun. The documentation is good and will let you get started with the API pretty quickly. I have my whole complete family album on OneDrive, but the API is still a bit hard to use as compared to Google Drive API or maybe it is just for me. But while playing around with Drive API I ended up creating a small razor based web page application which will allow you to show your folder as an online web album. I have the source code at Github.

To get started register your application on the Google Developer Console. Here is a complete guide on how to use the Google APIs.

Copy the API keys and save it on the notepad. The basic usage example on the Google Drive API reference page uses a file called client_secrets.json which actually holds the API key. You can find this file in the bin folder.

{
  "installed": {
    "client_id": "524339914714.apps.googleusercontent.com",
    "client_secret": "_Lq8D_Ai-T2IbhU8m2zXlQa"
  } 
}

You also have to enable the Drive API before you start using it.

I created a wrapper around the Google Drive API so I can use it in my other projects. Here is the complete code of my GoogleDrive class.

using System;
using System.Collections.Generic;
using System.Web;
using Google;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Download;
using Google.Apis.Drive.v2;
using Google.Apis.Drive.v2.Data;
using Google.Apis.Logging;
using Google.Apis.Services;
using System.Threading.Tasks;
using System.Threading;
//using Google.Apis.Upload;

public class GoogleDrive
{
    DriveService service = null;
    public GoogleDrive()
    {
        Run().Wait();
    }


    private File GetFileByID(string fileID, DriveService service)
    {
        File file = service.Files.Get(fileID).Execute();
        if (file.ExplicitlyTrashed == null)
            return file;
        return null;
    }

    public string GetFolderID(string FolderName)
    {
        FilesResource.ListRequest request = service.Files.List();
        request.Q = "title = '" + FolderName + "'";
        FileList files = request.Execute();
        return files.Items[0].Id;
    }
    public List<File> ListFolderContent(string FolderID)
    {
        ChildrenResource.ListRequest request = service.Children.List(FolderID);
        List<File> files = new List<File>();
        //request.Q = "mimeType = 'image/jpeg'";

        request.Q = "'" + FolderID + "' in parents";

        do
        {
            try
            {
                ChildList children = request.Execute();

                foreach (ChildReference child in children.Items)
                {
                    files.Add(GetFileByID(child.Id, service));
                }

                request.PageToken = children.NextPageToken;

            }
            catch (Exception e)
            {
                request.PageToken = null;
            }
        } while (!String.IsNullOrEmpty(request.PageToken));
        return files;
    }

    public List<File> ListRootFileFolders()
    {
        List<File> result = new List<File>();
        FilesResource.ListRequest request = service.Files.List();
        do
        {
            try
            {
                FileList files = request.Execute();

                result.AddRange(files.Items);
                request.PageToken = files.NextPageToken;
            }
            catch (Exception e)
            {
                request.PageToken = null;
            }
        } while (!String.IsNullOrEmpty(request.PageToken));
        return result;
    }

    public byte[] DownloadFile(string fileID)
    {
        File file = service.Files.Get(fileID).Execute();
        var bytes = service.HttpClient.GetByteArrayAsync(file.DownloadUrl);
        return  bytes.Result;
    }


    private async Task Run()
    {
        try
        {
            GoogleWebAuthorizationBroker.Folder = "Files";
            UserCredential credential;
            using (var stream = new System.IO.FileStream("client_secrets.json",
                System.IO.FileMode.Open, System.IO.FileAccess.Read))
            {
                credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets, DriveConstants.Scopes, "user", CancellationToken.None);
            }

            var drvService = new DriveService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = "Drive API Sample",

            });

            if (drvService != null)
            {
                service = drvService;
            }
        }
        catch { }
    }
}

The Storage class uses Biggy for the document storage. You have to manually add the names of the folder (considered as albums) on settings page. This will get added/appended in settings.json file in the Data folder which is in the web root of DriveGallery. Here is my settings file.

{"AlbumName":"Atlassian"}
{"AlbumName":"DivX"}
{"AlbumName":"Envato"}
{"AlbumName":"Disqus"}

Settings page from where I can add the names of folders/albums. No view and delete options as of now, but I will soon add it.

The added albums will be listed on the main/default page. The user will then have to click the name of the album to view the contents which should only images. At the moment there is no check which prevents it to show other files rather than only image files.

Google Drive is slow when it comes to handle high amount of data. Google Drive storage is not like Azure or Amazon storage. It’s different and will not get you large results in appropriate time. If you want to use Drive Gallery make sure that you don’t use more than 25-50 images in a folder. Querying 25-50 files in a single go will be long but not more than if you have more than 50. Better option is to break your folder in parts like volume I & II or Part 1 or 2.

I will try to make it look more attractive but for the moment it solves the purpose for me. Click on the View button to view the album. The View page accepts a query string name, which has the name of the folder/album. Google Drive API does not understand the name of the folder, so I have to get the folder id from the name. I will use the GetFolderID method of the GoogleDrive class which gives me the folder id. The received folder id is then passed to ListFolderContent method which will list all the files in the folder.

Please note that, for the moment there is no check to retrieve only images from the folder. GoogleDrive.cs class is a generic version of the class I am using in my other projects. You just need to be sure that you have only images in the folder and not any other file.

Click the View button to view the full size image in the browser else click the Download button to download it directly. Basically Drive API does not have any property which holds the value of the URL to view the image online. So I tweaked the thumbnail URL in the ViewURL property so I can view the images online without having to download it.

public class Albums
{
    public string Id { get; set; }
    public string Title { get; set; }
    public string AlbumName { get; set; }
    public string DownloadURL { get; set; }
    public string ViewURL
    {
        get
        {
            return ThumbnailLink.Replace("=s220", "=s4000");
        }
    }
    public string ThumbnailLink { get; set; }
}

Taking the ThumbnailLink property and replace the =s220 to =s4000 does the trick.

Note: The URLs are not permanent, it will change when the request expires.

Properties of the Album class:

  • Id: File/Image id.
  • Tilte: Title of the image/file.
  • AlbumName: Name of the album/folder.
  • DownloadURL: Download URL of the image/file. Original Drive API property name: DownloadUrl.
  • ViewURL: URL which allows user to view the image in the browser.
  • ThumbnailLink: URL of the thumbnail image. Original Drive API property name: ThumbnailLink.

The duration of the operation depends on the amount of images you have in your folder. The lesser the number of images the fast the query will get executed. Here just for fun I have used Biggy JSON store to save the content details of the folder. If you want to remove it from your implementation, please do so. You may have to change some functions in order to get all other things working fine.

You can download the complete source code from Github. I am still working on it to make it more flexible and good looking. As I am not a designer and I seriously lack when it comes to web designs. Thanks to Twitter bootstrap to make it look a bit good.

Currently rated 5.0 by 1 person

JSON Based Document Storage Using Biggy In ASP.NET MVC

3. May 2014 13:51

API ASP.NET MVC C# Web 

While working with a small web based project many developers will take advantage of web.config and XML files to read settings for the application. Using web.config is a good way but you cannot change the settings from within the application and when done manually it causes the website to restart. XML is good but many of us has a problem when it comes to update the details in XML. Biggy is an awesome library developed by Rob Conery to work with document storage. It does a lot well more than you can think of if you are not following the project closely on Github. For now I am just going to show you how you can use Biggy to save your application data in JSON based document storage. 

The library is not available on NuGet, so you have to download or fork the whole solution from Github and then build it. Create a new MVC application and add the reference of the Biggy assemblies you just build. 

Remove Newtonsoft.Json assembly that is added in your project by default when it is created by Visual Studio. The version of assembly seems to be incompatible with Biggy. Instead use the one which accompanies Biggy. 

Add a new model in your application and name it settings. The settings may depend on your application, as I am using it for my blog I have settings like blog name, blog description, posts per page and disable comments after 'x' days. 

public class Settings
{
    public string BlogName { get; set; }
    public string BlogDescription { get; set; }
    public string PostsPerPage { get; set; }
    public string CommentDays { get; set; }
}
I am manually building my view but you can use scaffolding if you wish to save your time. On submit of the form, the details will be sent to the server where my controller method will save the settings in the JSON file. Here is my view and controller code.
@model BiggyJSONDataStore.Models.Settings
@{
    ViewBag.Title = "Settings Page";
   }

<div class="row">
    @using (Html.BeginForm("Settings", "Home", FormMethod.Post))
    {
        <label>Blog Name</label>
        @Html.TextBoxFor(m => m.BlogName, new { @id = "blogname" })
        <br />
        <label>Blog Description</label>
        @Html.TextBoxFor(m => m.BlogDescription, new { @id = "blogdesc" })
        <br />
        <label>Posts per Page</label>
        @Html.TextBoxFor(m => m.PostsPerPage, new { @id = "postsperpage" })
        <br />
        <label>Disable comments after</label>
        @Html.TextBoxFor(m => m.CommentDays, new { @id = "commentdays" })
        <label>days</label><br />
        <input id="btnSave" type="submit" value="Save Settings" />
    }
</div>
When the first time the page is loaded I want to check if there are settings in the file or not. If settings are there then render my view with settings. So the default GET view will look like this.
IBiggyStore<Settings> settingStore = new JsonStore<Settings>(dbPath: HttpRuntime.AppDomainAppPath);
try
{
    var data = settingStore.Load().Single();
    return View(data);
}
catch { }

return View();
The settingStore object is being created and creates a new file in the Data folder in the application root. the dbPath parameter specifies where the file (JSON file in this case) is saved, which is the web root. The Load() method of the settingStore will load all the data in the JSOn file. In this case I have only single set of setting so I will use the Single() method to get the single setting record and not IEnumerable<Settings>.
IBiggyStore<Settings> settingStore = new JsonStore<Settings>(dbPath: HttpRuntime.AppDomainAppPath);

var store = new BiggyList<Settings>(settingStore);

var newSettings = new Settings();

newSettings.BlogName = setting.BlogName;
newSettings.BlogDescription = setting.BlogDescription;
newSettings.PostsPerPage = setting.PostsPerPage;
newSettings.CommentDays = setting.CommentDays;

store.Add(newSettings);
store.Update(setting);

return View();
The above code will add a new settings to the JSON file.
{"BlogName":"Midnight Programmer","BlogDescription":"Programming For Fun","PostsPerPage":"10","CommentDays":"90"}

At this point if you keep pressing save button by entering different values a new entry will be added to the JSON file. To avoid this you have to update the details instead of adding it over and over again in the JSON file.

IBiggyStore<Settings> settingStore = new JsonStore<Settings>(dbPath: HttpRuntime.AppDomainAppPath);

var store = new BiggyList<Settings>(settingStore);

var newSettings = new Settings();

Settings data = null;
try
{
    data = settingStore.Load().Single();
}
catch { }


if (data != null)
{
    data.BlogName = setting.BlogName;
    data.BlogDescription = setting.BlogDescription;
    data.PostsPerPage = setting.PostsPerPage;
    data.CommentDays = setting.CommentDays;
    store.Update(data);
}
else
{
    newSettings.BlogName = setting.BlogName;
    newSettings.BlogDescription = setting.BlogDescription;
    newSettings.PostsPerPage = setting.PostsPerPage;
    newSettings.CommentDays = setting.CommentDays;
    store.Add(newSettings);
    store.Update(setting);
}

return View();

As you can see that the store object Add method is not called but only the Update method is called in case if the data object is not null.  

If you plan to save multiple records in the file, then make sure you use identifier in order to get the required details.

References:

Biggy - Github

Currently rated 5.0 by 1 person

Building MVC Application With Multiple Database Support Using Ninject

13. May 2013 14:33

API ASP.NET MVC C# 

I used to have BlogEngine.NET as my blogging platform before switching to WordPress, and that is because of my poor hosting provider who can’t afford few MBs on the shared hosting plans. I like BlogEngine.NET a lot because it is in .NET and on the other hand WordPress is on PHP which I don’t know. BlogEngine.NET is still evolving and is getting better with every release. BlogEngine.NET supports multiple databases like SQL Server, SQL Server CE, MySQL, XML file, VistaDB and may be few more. As it is open-source, I jumped into the code and found it to be a bit hard to get through its implementation. To be frank, I didn’t look into that deep!! but it is not implementing what I was expecting it was. What I was expecting was the use of dependency injection (DI).

I am constantly working on new projects open-source and freelanced and few of them are for fun. The application I am working on right now requires a multiple DB support. The main problem I am going to face is not writing different functions for different DB operations, but having them integrated at the time when the user selects the database. BlogEngine.NET implements it pretty impressively, but I was expecting something else. For my project I will be using Ninject. If you want to do for your application, then this is how you can do it.

Create a new MVC internet application. First thing that we need to do is to add Ninject reference to the project by firing the below Nuget command. Remember that for MVC application you need to use Ninject.MVC3 and for other applications you need to use Ninject only: Install-Package Ninject

Install-Package Ninject.MVC3

When the library is installed successfully, you will notice a file under App_Start folder named NinjectWebCommon.cs. This is a very important file and we will look into it this later when we are done with other things.

What I am trying to achieve here is that my application would be able to support multiple databases and I also want to keep my code clean. I don’t want to handle it using some if..else conditions. Ninject does the work for me pretty well here. I will create an interface that will have all the functions which my wrapper classes will implement. For the sake of simplicity for this example I am going to perform basis CRUD operations, I will be writing code to implement two database support and will be using a custom written ORM called Dapper to communicate to the DB (you can use EF if you wish). I will name my interface IDBProvider.

public interface IDBProvider
{
    bool Add(Friends friend);
    bool Update(int Id, Friends friend);
    bool Delete(int Id);
    IEnumerable ListFriends();
    Friends ListFriend(int Id);
}

As you can see from the above code that I am using Friends model to save details of my friend. So here is my model.

public class Friends
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Skype { get; set; }
}

After this I am going to have support for two databases, SQL Server and SQL Server CE (4.0). For this I will create 2 classes which will implement the IDBProvider interface naming SQLHelper.cs and SQLCEHelper.cs respectively.

SQLHelper.cs

public class SQLHelper : IDBProvider
{
    string ConStr = ConfigurationManager.ConnectionStrings["Con"].ConnectionString;
 
    public bool Add(Friends friend)
    {
        bool Added = false;
 
        try
        {
            using (SqlConnection con = new SqlConnection(ConStr))
            {
                string insertSQL = "INSERT INTO Friends(Name, Email, Skype) VALUES (@Name, @Email, @Skype)";
                con.Open();
                con.Execute(insertSQL, new
                {
                    friend.Name,
                    friend.Email,
                    friend.Skype
                });
 
                Added = true;
            }
        }
        catch (Exception x)
        {
            throw x;
        }
 
        return Added;
    }
 
    public IEnumerable ListFriends()
    {
        try
        {
            using (SqlConnection con = new SqlConnection(ConStr))
            {
                string strQuery = "Select Id, Name, Email, Skype FROM Friends";
                con.Open();
                var AllFriends = con.Query(strQuery);
 
                return AllFriends;
            }
        }
        catch (Exception x)
        {
            throw x;
        }
    }
 
    public Friends ListFriend(int Id)
    {
        try
        {
            using (SqlConnection con = new SqlConnection(ConStr))
            {
                string strQuery = "SELECT Id, Name, Email, Skype FROM Friends WHERE Id=" + Id;
                con.Open();
                var friend = con.Query(strQuery).Single();
                return friend;
            }
        }
        catch (Exception x)
        {
            throw x;
        }
    }
 
    public bool Update(int Id, Friends friend)
    {
        bool Update = false;
        try
        {
            using (SqlConnection con = new SqlConnection(ConStr))
            {
                string strUpdate = "UPDATE Friends SET Name = @Name, Email = @Email, Skype = @Skype WHERE Id = " + Id;
                con.Open();
                con.Execute(strUpdate, new
                {
                    friend.Name,
                    friend.Email,
                    friend.Skype
                });
 
                Update = true;
            }
 
        }
        catch (Exception x)
        {
            throw x;
        }
 
        return Update;
    }
 
    public bool Delete(int Id)
    {
        bool Deleted = false;
        try
        {
            using (SqlConnection con = new SqlConnection(ConStr))
            {
                string strDelete = "DELETE FROM Friends WHERE Id = " + Id;
                con.Open();
                int i = con.Execute(strDelete);
                if (i > 0)
                    Deleted = true;
            }
        }
        catch (Exception x)
        {
            throw x;
        }
 
        return Deleted;
    }
}

SQLCEHelper.cs

public class SQLCEHelper : IDBProvider
{
    string ConStr = ConfigurationManager.ConnectionStrings["Con"].ConnectionString;
 
    public bool Add(Friends friend)
    {
        bool Added = false;
 
        try
        {
            using (SqlCeConnection con = new SqlCeConnection(ConStr))
            {
                string insertSQL = "INSERT INTO Friends(Name, Email, Skype) VALUES (@Name, @Email, @Skype)";
                con.Open();
                con.Execute(insertSQL, new
                {
                    friend.Name,
                    friend.Email,
                    friend.Skype
                });
 
                Added = true;
            }
        }
        catch (Exception x)
        {
            throw x;
        }
 
        return Added;
 
    }
 
    public bool Update(int Id, Friends friend)
    {
        bool Update = false;
        try
        {
            using (SqlCeConnection con = new SqlCeConnection(ConStr))
            {
                string strUpdate = "UPDATE Friends SET Name = @Name, Email = @Email, Skype = @Skype WHERE Id = "+Id;
                con.Open();
                con.Execute(strUpdate, new
                {
                    friend.Name,
                    friend.Email,
                    friend.Skype
                });
 
                Update = true;
            }
 
        }
        catch (Exception x)
        {
            throw x;
        }
 
        return Update;
    }
 
    public bool Delete(int Id)
    {
         bool Deleted = false;
         try
         {
             using (SqlCeConnection con = new SqlCeConnection(ConStr))
             {
                 string strDelete = "DELETE FROM Friends WHERE Id = " + Id;
                 con.Open();
                 int i = con.Execute(strDelete);
                 if (i > 0)
                     Deleted = true;
             }
         }
         catch (Exception x)
         {
             throw x;
         }
 
         return Deleted;
    }
 
    public IEnumerable ListFriends()
    {
        try
        {
            using (SqlCeConnection con = new SqlCeConnection(ConStr))
            {
                string strQuery = "Select Id, Name, Email, Skype FROM Friends";
                con.Open();
                var AllFriends = con.Query(strQuery);
 
                return AllFriends;
            }
        }
        catch (Exception x)
        {
            throw x;
        }
    }
 
    public Friends ListFriend(int Id)
    {
        try
        {
            using (SqlCeConnection con = new SqlCeConnection(ConStr))
            {
                string strQuery = "SELECT Id, Name, Email, Skype FROM Friends WHERE Id=" + Id;
                con.Open();
                var friend = con.Query(strQuery).Single();
                return friend;
            }
        }
        catch (Exception x)
        {
            throw x;
        }
    }
}

The question now here is that how would the application will know which DB to use as a data store? For this I made few settings in my web.config file. In the appSettings section I added a setting that will hold the value which we use as an identifier and connect to the DB. You can have different approach to achieve this, it is not at all necessary to use what I have used here. My app setting in web.config looks something like this:

<add key="DBProvider" value="SQL"/>

When reading this settings I will be dynamically calling or injecting the code on the basis of the value of DBProvider in my app settings. In this case I will bind SQLHelper when the value is SQL and SQLCEHelper when the value is SQLCE. In the start of the tutorial I mentioned about the NinjectWebCommon.cs file in the App_Start folder. Here we will be looking into CreateKernel method as this is the place where I implement my helper classes.

private static IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
    kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
 
    if (ConfigurationManager.AppSettings["DBProvider"].ToString().ToLower() == "sql")
    {
        kernel.Bind<IDBProvider>().To<SQLHelper>();
    }
    else
    {
        kernel.Bind<IDBProvider>().To<SQLCEHelper>();
    }
 
    RegisterServices(kernel);
    return kernel;
}

Notice the highlighted code. I am conditionally binding the implementation on the basis of the settings in my web.config file. What exactly is happening here is that the code is being injected depending on the conditions and this is why we call it dependency injection.

To get the benefit of this, we need to make few changes to our controller.

private readonly IDBProvider _dbProvider;
 
public HomeController(IDBProvider dbProvider)
{
    this._dbProvider = dbProvider;
}

I have a default constructor which takes the IDBProvider as a parameter. The IDBProvider object is all we need which provides us all its implementation. To add a friend to DB you just have to call the Add method like _dbProvider.Add(friend). Same for edit, update, delete and list all the friends. You noticed that no where in the code I have made use of the SQLHelper.cs or SQLCEHelper.cs classes. This is the awesomeness of DI.

This is all it and now your application is flexible enough to use multiple databases. I strongly recommend you to read the documentation on Ninject at Ninject.org as it is vast and can be a life saver in many scenarios.

 No Rating

ASYNC Controller In MVC 4

30. April 2013 22:17

.NET Framework ASP.NET MVC C# Visual Studio 

I have build many small applications so far in MVC to help myself in understanding the framework more deeply. Now I am planning to write a blog engine on MVC. It will not be an easy task but I will be going to learn a lot of things. As I was planning things ahead I came across a problem where I have to load my blog stats like FeedBurner readers, Facebook page likes, Google +1 count, twitter followers inside a div on the page. The problem I see here is that I am going to make multiple cross-domain calls in order to get the stats. I can’t avoid that though but this will cause my blog to load slowly. I know about Async and Task Parallel Library(TPL) but the question is how do I implement this in my application? I do a quick web search and found something which is called Async controller in MVC4. You can also have AsynController in MVC3 but that is not pretty if you start comparing it with MVC4.

For the simplicity of the tutorial I am going to make 2 calls: get twitter followers count and facebook page likes. In MVC3, if you want to perform Async operations then you have to inherit your controller with AsyncController like this.

public class HomeController : AsyncController

But MVC4 is much cleaner. Let’s take a look at the default implementation of the calls I am making to Twitter and Facebook to get the follower count and page likes respectively. Here are my 2 methods in HomeController.

private string GetTwitterFollowersCount(string Username)
{
    XDocument xdoc = XDocument.Load("http://api.twitter.com/1/users/show.xml?screen_name=" + Username + "&include_entities=false");
    return (from item in xdoc.Descendants("user")
            select item.Element("followers_count").Value)
            .SingleOrDefault();
}
 
private string GetFacebookLikes(string FaceBookPageURL)
{
    string uri = "https://api.facebook.com/method/fql.query?query=select%20%20like_count,%20total_count,%20share_count,%20click_count%20from%20link_stat%20where%20url=%22" + FaceBookPageURL + "%22";
    return Convert.ToString((from elem in XElement.Load(uri).Descendants()
                   where elem.Name.LocalName == "like_count"
                   select elem).First<XElement>().Value);
}

Nothing fancy in the above two methods. When I call these 2 methods one after the other, they will just get the data from a different source and render the result in the view. That’s fine as it’s my requirement. Now when I run my application it now takes a longer time to render the view. Before I explain this further take a look at my Index().

public ActionResult Index()
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    ViewBag.TwitterFollowers = GetTwitterFollowersCount("audi");
    ViewBag.FacebookLikes = GetFacebookLikes("http://facebook.com/audi");
    watch.Stop();
    Int64 elapsedTime = watch.ElapsedMilliseconds;
    ViewBag.Time = elapsedTime.ToString();
    return View();
}

This is because Controllers are synchronous by default and it will process the request one after the other i.e. it will wait for the first task to complete and then move on to the next task. In my case the controller will execute the GetFollowersCount method and only after the completion of this method it will shift to the next method GetFacebookLikes. This could be a long running task or just imagine if you are retrieving heavy data from different sources. The view or the page will not render till the execution of both the methods will not get completed. To get a rough idea of the time elapsed in making synchronous calls in the above controller, I have used StopWatch(System.Diagnostics) class. I don’t know how accurate, but I still used it to have an approximate idea of the time. This is the output of the above code.

It took 1588ms to complete 2 requests. Now if I implement async in the controller I will see a drastic improvement. It is not just the controller ActionResult which I have to change to support async calls but I also have to update the 2 methods which I am using to collect the stats. Here are my updated methods.

private Task<string> GetTwitterFollowersCountAsync(string Username)
{
    return Task.Run(() =>
    {
        XDocument xdoc = XDocument.Load("http://api.twitter.com/1/users/show.xml?screen_name=" + Username + "&include_entities=false");
        return (from item in xdoc.Descendants("user")
                select item.Element("followers_count").Value).SingleOrDefault();
    });
}
 
private Task<string> GetFacebookLikesAsync(string FaceBookPageURL)
{
    return Task.Run(() =>
    {
        string uri = "https://api.facebook.com/method/fql.query?query=select%20%20like_count,%20total_count,%20share_count,%20click_count%20from%20link_stat%20where%20url=%22" + FaceBookPageURL + "%22";
        return Convert.ToString((from elem in XElement.Load(uri).Descendants()
                                 where elem.Name.LocalName == "like_count"
                                 select elem).First<XElement>().Value);
    });
}

Pay attention to the GetTwitterFollwersCountAsync and GetFacebookLikesAsync return type. Previously they were only string, and now I have changed their return type to Task. I have put the code inside Task.Run() as it will queues the specified work to run on the Thread Pool and returns a Task(TResult) handle for that work. I have changed the ActionResult to handle the async feature. As you can see that this controller method does not return ActionResult instead it return Task. Here is my updated ActionResult.

public async Task<ActionResult> Index()
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    Task<string> twitterFollowers = GetTwitterFollowersCountAsync("audi");
    Task<string> facebookLikes = GetFacebookLikesAsync("http://facebook.com/audi");
    await Task.WhenAll(twitterFollowers, facebookLikes);
    ViewBag.TwitterFollowers = await twitterFollowers;
    ViewBag.FacebookLikes = await facebookLikes;
    watch.Stop();
    Int64 elapsedTime = watch.ElapsedMilliseconds;
    ViewBag.Time = elapsedTime.ToString();
    return View();
}

The code is almost the same but 3 lines are making a difference (highlighted). Task will hold the value returned from the updated async methods. MSDN defines the await operator as:

The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work.

Task.WhenAll() will creates a task that will complete when all of the supplied tasks have completed. This actually parallelize the request. Lets check the output and compare both.

The difference is noticeable…607ms!! is half way down and a huge performance benefit. This is a small example and the real performance can be noticed when you work with real scenarios. I have used MVC4 with .NET 4.5 to use awesomeness of asynchronous controller. I hope this gives you an idea on how you can use async controllers in MVC4.

 No Rating

Creating A Live Tile Application In Windows 8

1. January 2013 11:20

C# Windows 

Developing application for Windows 8 is fun. I love the UI and the idea of having a live tile for my application. So I try building a live tile application, but unfortunately I can’t find a simple written article or a blog post. I even found MSDN to be a bit difficult for the newbies to get the grasp in first go. There are lot of things to understand and to worked on for creating a live tile in Windows 8. For this post I am just covering the main points. First, create a new Windows store application.

Now to implement in the live tile, there are 2 different ways. For this post I am showing one way using the built-in classes and another way using the NotificationExtensions library from Microsoft. For the tile color, application splash screen, logo and other properties in the package.appxmanifest file. I am not making any changes to this file and using the default values.

For the simplest implementation I have added a button and the code to change image on my tile. There are different types of tiles that you can select with using TileTemplateType enumeration. To keep it simple I am using TileSquareImage which will just show an image in a square tile. Here is the simplest way of using it: Add the below namespaces:

using Windows.UI.Notifications;
using Windows.Data.Xml.Dom;

Add the below code on the click of the button:

XmlDocument xmltile = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquareImage);
XmlNodeList imgNode = xmltile.GetElementsByTagName("image");
imgNode[0].Attributes[1].NodeValue = "ms-appx:///Assets/pic.png";
TileNotification tileNotify = new TileNotification(xmltile);
TileUpdateManager.CreateTileUpdaterForApplication().Update(tileNotify);

At line number 1, I have used the enumeration TileTemplateType to select the tile type. After you choose the tile type the first line of code above will return the XML that will render the live tile. Depending on the type of tile you have selected the XML is generated and you need to supply the text and images to it to render it properly. You will face problem if you are not aware of the XML for the type of tile you have selected. I came up with a simple solution to overcome this. I declare a temporary string variable and then store the XML from the xmltile object using the GetXML() method. It look something like this:

string tempXml = xmltile.GetXml();

Put a breakpoint and get the XML. In my case where I am using TileSquareImage, therefore my XML looks something like this:

<tile>
<visual>
<binding template="TileSquareImage">
<image id="1" src=""/>
</binding>
</visual>
</tile>

The code at line 2 and 3 will first get the node and set the image to be displayed on the tile. If you look in the solution explorer, you will see a folder labelled Assets. You can place the image file for the tile in this folder and then set the path of the image in the above code. After setting the XML for the tile, it now time to update the tile. I will now use TileNotification class and then pass XmlDocument object  (xmltile) as a parameter and then finally call the TileUpdateManager class to update the tile. Below is my live tile in action:

If you right click the tile, notice the option turn live tile off. This means that the tile is a live tile and you can turn off the live notifications if you wish.

For this post, this is it. In the next post I will show how to update the live tile using Notification Extension library and how to animate a tile. I hope this post helps you to understand and gets you started in building a live tile application.

 No Rating