Integrating DISQUS to your SPA

I am building a single page application (SPA) using Durandal JS (with ServiceStack powered API layer). In one of the sections I wanted to have DISQUS discussion integrated. This blog post outlines problems I faced and solution to the problem I found.
In a normal web site, integration of DISQUS to your pages is easy, you sign up for DISQUS, get the JavaScript Universal Code for web sites, add it where you want your discussion thread to show up in your page. When web page loads, DISQUS loads the required Javascript and adds it to the section of your page. By default DISQUS will use the page url as the key to the discussion and manages unique thread ids for your posts and replies within that.

Now with this model we have a problem, in a SPA, there is no “pages” its all one “single” page with routes (by some convention) managing the loading of various views. So if you simply paste DISQUS code where you want the discussion to show up in your SPA view html page, result will be disappointing! At least it was for me the first time. Again to my defense, it was late in the night and I was not thinking clearly. When the page ran, it did not load anything…blank! Problem is that if you add a JS snippet to your view code, its not going to work in a SPA architecture.

Solution

We need to load the required JavaScript file just like you load any other piece of code that is required by your application. Here  is how you do it…

     function initDisqus() {
	window.disqus_shortname = 'your-app-name';
	var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
		dsq.src = '//' + window.disqus_shortname + '.disqus.com/embed.js';
		$.getScript(dsq.src)
			.done(function () {
		          //
			});

	}

This works, well mostly…If you run your page now, you will see your discussion initialized on the page. And you can start adding comments, I was happy to get to this point, and soon realized that all the comments were getting added to the root of the site, and if you reload the page, DISQUS failed to attach the comments back to this discussion. All those comments were kinda orphaned. Soon I realized that the presence of ‘#’ (hash) in my url is also messing up with how DISQUS works!! If you have a URL like http://www.mysite.com/#/blog/my-first-blog, DISQUS does not treat anything after the ‘#” as part of your Url and attaches the thread id after the ‘#’.

So what do you do? One way (at least what I think) is to change ‘#’ to ‘#!’, for example, the URL given before will change to http://www.mysite.com/#!/blog/my-first-blog. Durandal did not complain and loads the page, and DISQUS seems to like it too. One another thing you will need to do is to reload DISQUS every time your new view loads with new unique identifier for the page and the link. This way all the discussions that happens will be tracked under your unique view (urls).

More complete solution:

     function initDisqus() {
	window.disqus_shortname = 'your-app-name';
	var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
	dsq.src = '//' + window.disqus_shortname + '.disqus.com/embed.js';
	$.getScript(dsq.src)
			.done(function () {
				DISQUS.reset({
					reload: true,
					config: function () {
						this.page.identifier = window.location.href;
						this.page.url = window.location.href;
					}
				});
			});

	}

Note: Make sure to call this function from your “viewAttached” within your view model code.

That’s all for now folks, Happy programming!

Cheers!
Binu

Deploying Durandal SPA to Production

I have been building a single page application (SPA) using Durandal JS. In this post, I want to talk about some of the steps that you want to take when you are deploying your single page application to your production/live web server. In my case I am using ASP.Net MVC 4 and I use Windows Azure to host my website. If you want to learn more about how to build a SPA using Durandal, I strongly suggest you watch John Papa‘s SPA Jump Start course in Pluralsight.

Typically your SPA application will have a structure like this:

In this all the files except the main-built.js is your application. This includes Durandal, Require JS, your files, etc. “main-built.js” is the optimized single file that contains your javascript and html files that you need to deploy to your production web server. So you do you package this for production? This is simple than I thought. I was thinking of using ASP.Net Bundle capability to bundle all the JS files, but decided against it because I felt to manage my SPA files using ASP.Net bundling could become very tricky very fast because of paths, and html files. So I went with the optimizer that is included with Durandal.

Once you install durandal using Nuget ( or HotTowel Nuget), you will see under App\durandal\amd\ you have a file called optimizer.exe. This is the tool we will use to package our SPA application.

  1. Step1: To use this you will need to install Node.js, So get node.js and install. You can download Node.js from here.
  2. Click on Start > All Programs > Node.js > Node js command prompt
  3. Navigate to your projects \app\durandal\amd folder
  4. Run optimizer.exe
  5. This will scan everything under your \App folder and creates the combined and optimized file main-built.js

Now we can use this file in our application, following code snippet shows how to include this in your index.chtml file. We will use the full files when we are in debug mode and when we are running a release configuration, use the optimized file.

@Scripts.Render("~/scripts/vendor")
@if(HttpContext.Current.IsDebuggingEnabled) {
     <script src="~/App/durandal/amd/require.js" data-main="App/main"></script>
}
else
{
    <script type="text/javascript" src="~/App/main-built.js"></script>
}

As you can see, I am using ASP.Net Bundles to combine and compress all the standard JS files like bootstrap, jquery plugins, or any other components that I use and are not part of my SPA code and use the optimizer created file for my SPA code. With this approach, our application code (SPA code) is send to browser as a single file enabling faster download. If you want to bust cache when each time you are deploying new code to your server, you can configure Require.js to include a query string parameter to each resource it fetches.

require.config({
	paths: { "text": "durandal/amd/text" },
	urlArgs: "bust=" + (new Date()).getTime()
});

Reference: http://requirejs.org/docs/api.html#config.

Please note that the code snippet above is ideal only for development, for your release code, change this to something like :

urlArgs: "bust=v1.1"

This will make sure that your users will not be downloading any resources that browser already has unless it is changed (which typically happens when you have a new release)

That’s all for now folks! Happy Programming!
Cheers!
Binu

LinkedIn Provider for ServiceStack Authentication

I love ServiceStack ! Its just pure awesomeness!  It includes a very robust Authentication and Authorization feature that is very easily extensible. Read all about it here => https://github.com/ServiceStack/ServiceStack/wiki/Authentication-and-authorization.

…But it did not support LinkedIn provider, so I spend some time this afternoon to write one, here is the code. (I told you, its easy, even I can do this :)

    public class LinkedinAuthProvider : OAuthProvider 
    {
        public const string Name = "linkedin";
        public static string Realm = "https://www.linkedin.com/uas/oauth2/";

        public static string PeopleDataUrl =
            "https://api.linkedin.com/v1/people/~:(id,first-name,last-name,formatted-name,industry,email-address)?format=json&";

        public LinkedinAuthProvider(IResourceManager appSettings): base(appSettings, Realm, Name) {}

        public override object Authenticate(IServiceBase authService, IAuthSession session, ServiceStack.ServiceInterface.Auth.Auth request)
        {
            var tokens = Init(authService, ref session, request);
            var code = authService.RequestContext.Get<IHttpRequest>().QueryString["code"];
            var error = authService.RequestContext.Get<IHttpRequest>().QueryString["error"];
            var isPreAuthError = !error.IsNullOrEmpty();
            if (isPreAuthError)
            {
                return authService.Redirect(session.ReferrerUrl);
            }
            var isPreAuthCallback = !code.IsNullOrEmpty();
            if (!isPreAuthCallback)
            {
                var preAuthUrl = Realm + "authorization?response_type=code&client_id={0}&scope={1}&state={2}&redirect_uri={3}";
                preAuthUrl = preAuthUrl.Fmt(ConsumerKey, "r_fullprofile%20r_emailaddress", Guid.NewGuid().ToString(), this.CallbackUrl.UrlEncode());
      
                authService.SaveSession(session, SessionExpiry);
                return authService.Redirect(preAuthUrl);
            }

            var accessTokenUrl = Realm +
                                 "accessToken?grant_type=authorization_code&code={0}&redirect_uri={1}&client_id={2}&client_secret={3}";
            accessTokenUrl = accessTokenUrl.Fmt(code, this.CallbackUrl.UrlEncode(), this.ConsumerKey,
                                                this.ConsumerSecret);

            try
            {
                var contents = accessTokenUrl.GetStringFromUrl();
                var authInfo = JsonObject.Parse(contents);
                tokens.AccessTokenSecret = authInfo["access_token"];
                session.IsAuthenticated = true;
                authService.SaveSession(session, SessionExpiry);
                OnAuthenticated(authService, session, tokens, authInfo.ToDictionary());

                
                return authService.Redirect(session.ReferrerUrl.AddHashParam("s", "1"));
            }
            catch (WebException we)
            {
                var statusCode = ((HttpWebResponse)we.Response).StatusCode;
                if (statusCode == HttpStatusCode.BadRequest)
                {
                    return authService.Redirect(session.ReferrerUrl.AddHashParam("f", "AccessTokenFailed"));
                }
            }
            return null;
        }
        protected override void LoadUserAuthInfo(AuthUserSession userSession, IOAuthTokens tokens, Dictionary<string, string> authInfo)
        {
            var url = PeopleDataUrl + "oauth2_access_token={0}";
            url = url.Fmt(authInfo["access_token"]);
            var json = url.GetStringFromUrl();

            var obj = JsonObject.Parse(json);
            tokens.UserId = obj.Get("id");
            tokens.UserName = obj.Get("emailAddress");
            tokens.DisplayName = obj.Get("formattedName");
            tokens.FirstName = obj.Get("firstName");
            tokens.LastName = obj.Get("lastName");
            tokens.Email = obj.Get("emailAddress");
            
            LoadUserOAuthProvider(userSession, tokens);
        }

        public override void LoadUserOAuthProvider(IAuthSession authSession, IOAuthTokens tokens)
        {
            var userSession = authSession as AuthUserSession;
            if (userSession == null) return;

            userSession.DisplayName = tokens.DisplayName ?? userSession.DisplayName;
            userSession.FirstName = tokens.FirstName ?? userSession.FirstName;
            userSession.LastName = tokens.LastName ?? userSession.LastName;
            userSession.PrimaryEmail = tokens.Email ?? userSession.PrimaryEmail ?? userSession.Email;
        }

Happy programming !

Cheers!

Binu

Bundle your resources to speed up your ASP.Net website

I am not going to write a big blog post on this here, because there is already quite a bit of good articles out there on this topic. Why I am writing is this to share a very good article on this topic for anyone who wants to learn about Bundling and Minnification features that are available with ASP.Net 4.5.

It is written by Rick Anderson and you can read full article from here.

How to call ServiceStack API end point from JavaScript

Why this is important? You might ask? Yes, it is straight forward and we all have done this several times. But why I thought of writing about this is because I wasted couple of hours because of a silly oversight. In the title I said API based on ServiceStack, this is nothing different from any other RESTful endpoint, ex: WebAPI.

So in my service takes an input like this:

[Route("/usermeta")]
public class UserMeta
    {
        public string Email { get; set; }
        public List<string> Expertise { get; set; }
    }

and service implementation goes something like this:

[Authenticate]
        public object Post(UserMeta request)
        {
        
            //I do something here
            
        }

Now to call this api, this is what we do in JavaScript world,

                    var request = { };
                   
                    request.Email = this.profileEmail;
                    request.Expertise = this.expertAreas(); //ERROR!!!
                   
                    $.ajax({
                        type: "post",
                        url: 'api/usermeta',
                        dataType: 'json',
                        data:request,
                        success: function (data) {
                            toastr.success("Everything is saved, you are all set for now!", 'Wohoo!');
                        },
                        error: function (data) {
                            toastr.error("Oh! snap...something went wrong!", 'Error!');
                        }
                    });

Now this is straightforward, isnt’it? I thought so too. But when I ran this code, I got the email address correctly in server side, but field “Expertise” was null. Issue was that I was passing the object literal and the request was expecting json.

Every thing started working the moment, I converted “this.expertAreas()” to json using JSON.stringify() (in json2.js). Simple stupid thing, but I lost my 2 hours!!!
(Thanks to my wife for pointing out the error :)

Corrected code is given below, you can stringify the whole object literal too,

                    var request = { };
                   
                    request.Email = this.profileEmail;
                    request.Expertise = JSON.stringify(this.expertAreas());
                   
                    $.ajax({
                        type: "post",
                        url: 'api/usermeta',
                        dataType: 'json',
                        data:request,
                        success: function (data) {
                            toastr.success("Everything is saved, you are all set for now!", 'Wohoo!');
                        },
                        error: function (data) {
                            toastr.error("Oh! snap...something went wrong!", 'Error!');
                        }
                    });

Cheers!

Transform your templated web.config files with NAnt

There are many steps one need to do to setup a good working development environment. In large products where there are many project files and solutions that needed to be build in a certain order, managing all the config files can be a nightmare. This post is not going to tell you how to do things in such a large scale, but I want to show how easy is to use NAnt tool to do web config transformations. This will become one of the steps that we need to do as part of a continuous integration (CI) build or a local build. I have seen development teams struggle with setting up local development environment. This becomes a pain when project builds are not well thought, or designed well. My advise to any development team or developer is to spend some time to think thru our development process and build and deployment process. Treat this as a technical debt and deal with it aggressively before it reaches a point where you are spending hours every day trying to build your solution(s) so that you can write code.

Enough of the story, let us get to the point.

Our aim is to transform a template config file. Let us name config files in the format web.config.TEMPLATE. Idea is to use NAnt to do a transformation while copying this file to the target name of web.config. In the template file, you will need to tokenize the parts that you want to change depending on the environment. For example, when you are developing local, you may want to point to your local database server, in a QA environment, this will be a QA database server. You got the idea.

NAnt works with a project file for the build. There are several tasks NAnt can do, one of these tasks is a copy task. All NAnt related files are XML files. You can run NAnt from the command prompt and it takes many command line parameters.

nant.exe -buildfile:config.build -D:sourcefile=.\source\web.config.TEMPLATE -D:propertyfile=.\build\local.properties -D:destinationfile=.\source\web.config

Command line switch -buildfile is the name of the build file; -D allows us to pass multiple property name-values.

For our little experiment, I want to build web.config files for my two scenarios, one is when I work on local machine, I need a local version of web.config created and when I move to my QA environment, I need a different web.config file. The following picture shows how files and folders are setup:

What I have in \build folder – property files for various environments

what I have in \source folder – we.config.TEMPLATE file (actual config file is generated here itself)

This is the NAnt project file. A default.properties is loaded always. We will use this file to capture all the properties that are common across the different configurations
we are building.

<project default="buildconfig">  
	<property name="propertyfile" value="invalid.file" overwrite="false" />  

	<if test="${file::exists('default.properties')}">
		<echo message="Loading default.properties" />
		<include buildfile="default.properties" />
	</if>
	<echo message="Loading ${propertyfile}" />
	
	<include buildfile="${propertyfile}" failonerror="false" unless="${string::contains(propertyfile, 'invalid.file')}" />  
	
	<target name="buildconfig">  
		<copy file="${sourcefile}" tofile="${destinationfile}" overwrite="true">  
		  <filterchain>  
			<expandproperties />  
		  </filterchain>  
		</copy>  

	</target>  
</project> 

So for example we have the following we.config.TEMPLATE file that needs to get build for local and QA environments,

<?xml version="1.0"?>
<configuration>
  <connectionStrings>
    <add name="DatabaseConnection"  connectionString="Server=${DBServerName};Database=${DBName};Trusted_Connection=${TrustedConnectionValue}" />
  </connectionStrings>
</configuration>

So we have tokens for database server, database name and trusted connection value. For example, if our database name and the trusted connection value is not changing from environment to environment, then you keep these property values in default.properties file. Since this file is loaded always (see build file), NAnt will be able to replace those tokens. Furthermore we will pass the environment specific property file along with the command line that is used to run NAnt.

Our default.properties file:

<project>  
   <property name="DBName" value="FancyApp" />  
   <property name="TrustedConnectionValue" value="true" />  
</project>  

and our local.properties file; where we specify the database server name as (local). When we are running for another environment like QA, a qa.properties file can be created and passed in as parameter.

<project>  
   <property name="DBServerName" value="(local)" />  
</project>  

So, now with these files all set in the right places, if we run the commandline for NAnt, NAnt will run the task with a FilerChain to expand the properties using the files and/or property values supplied. Resulting file is the config file that you would want to use in the specified environment.

I am planning to expand this post in coming weeks, to show how we can use MSBuild to build the project,, deploy it to the specified location, how we can automatically checkout files from SVN, run some Unit/INtegration tests etc.

Once we have a full local build worked out, I will expand it further to use a CI Build server like Team City to kick off automated builds.

Exciting…

Until then, be productive :)

StructureMap update using Nuget – Error and Resolution

If you update StructureMap to 2.6.4 using Nuget Package Management console, you (may) get this error message

Could not load file or assembly ‘StructureMap, Version=2.6.3.0, Culture=neutral..

Here is what you need to do to get moving past this error…Pop this into your app.config or web.config file and you will be good to go!

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="StructureMap" publicKeyToken="e60ad81abae3c223" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.6.4.0" newVersion="2.6.4.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

Basically what it does is a binding redirect for StructureMap assembly that uses old versions 0.0 thru 2.6.4 to use the new version
Cheers!

Guid Strategy for DB Primary Keys

I was thinking about this for a while now, some years back, I always used Integer fields as Primary key columns in my database tables, more recently I have switched to using Guid values (uuid datatype in Sql Server) for the same.  This is not a new thing for most of us, we have weighed the options and have chosen one way or the other.

In my mind, Integers work very well as a Primary Key column, it works very well as an clustered index, the most recent is naturally the largest value. If you use a regular Guid, it is random in nature and can lead to fragmented indices. But Guid being unique, we can easily  move around that data, replicate, etc. No issues like in the case of a auto number integer.

So, in short if we can get to generate a sequential Guid, we strike gold ! I am using NHibernate ORM (with Fluent NHibernate), and it can use a Comb Identifier strategy to generate sequential Guids.

It is very easy to set this up, when you setup your session factory, you can add conventions for your mappings. You can define a PrimaryKey convention like this:

    public class PrimaryKeyConvention : IIdConvention
    {
        public void Apply(IIdentityInstance instance)
        {
            instance.Column("Id");
            instance.GeneratedBy.GuidComb();
        }
    }

and you can use this convention in your configuration like this:

    var cfg = new NHibernate.Cfg.Configuration()
                    .SetProperty(NHibernate.Cfg.Environment.CommandTimeout, "100")
                    .Proxy(p => p.ProxyFactoryFactory<DefaultProxyFactoryFactory>())
                    .DataBaseIntegration(db =>
                        {
                            db.Dialect<MsSqlAzure2008Dialect>();
                            db.ConnectionString = _context.ConnectionString;
                            db.BatchSize = (short) _batchSize;
                        });

                var sessionFactory = Fluently.Configure(cfg)
                    .Mappings(m =>
                    {
                        m.FluentMappings.AddFromAssembly(_context.Assembly);
                        m.FluentMappings.Conventions.Add(typeof(EnumConvention));
                        m.FluentMappings.Conventions.Add(typeof(PrimaryKeyConvention));
                        m.FluentMappings.Conventions.Add(typeof(DefaultStringLengthConvention));
                    })
                    .BuildSessionFactory();

This should help us having a better strategy for handling Guids as our PrimaryKey values in tables.

I still have an open question in my mind. Does this scale well (as an Int or Long) when we have millions of rows in our tables??

What do you guys think?

Grab ReSharper 7 discount NOW!

resharper-back-to-school-sale

I just noticed that there is a “Back to School” discount on new version of ReSharper. If you are a C# developer, this is the time for upgrading your personal license. If you do not have a license yet, its great time to get a personal license. Your life is so much better if you use ReSharper !

More details on this offer.

resharper-full

resharper-personal

 

Cheers!

 

Learn to write Single Page Applications using HTML5, Web API, Knockout and JQuery for Free!

Its FREE! This week only! check it out, I got this email from Pluralsight announcing this new course!

SPA w/HTML5, Web API, Knockout and jQuery - Free this week!John Papa

By John Papa – Learn to build end to end Single Page Application solutions using data binding and MVVM on the client; and examine layered patterns and data access on the server. Check our blog tomorrow for a free offer to this new course!