July 17, 2014 spout

Moving My ASP.NET Web Site to Disqus

I’m surprised how well that my commentRss proposal has been accepted in the world. As often as not, if I’m digging through an RSS feed for a site that supports comments, that site also provides a commentRss element for each item. When I proposed this element, my thinking was that I could make a comment on an item of interest, then check a box and I’d see async replies in my RSS client, thereby fostering discussion. Unfortunately, RSS clients never took the step of allowing me to subscribe to comments for a particular item and a standard protocol for adding a comment never emerged, which made it even less likely for RSS clients to add that check box. All in all, commentRss is a failed experiment.

Fostering Discussion in Blog Post Comments

However, the idea of posting comments to a blog post and subscribing to replies took off in another way. For example, Facebook does a very good job in fostering discussion on content posted to their site:

image

The Facebook supports comments and discussions nicely

 

Not only does Facebook provide a nice UI for comments, but as I reply to comments that others have made, they’re notified. In fact, as I was taking the screenshot above, I replied to Craig’s comment and within a minute he’d pressed the Like button, all because of the support Facebook has for reply notification.

However, Facebook commenting only works for Facebook content. I want the same kind of experience with my own site’s content. For a long time, I had my own custom commenting system, but the bulk of the functionality was around keeping spam down, which was a huge problem. I recently dumped my comments to an XML format and of the 60MB of output, less than 8MB were actual comments — more than 80% was comment spam. I tried added reCAPTCHA and eventually email approval of all comments, but none of that fostered the back-and-forth discussions over time because I didn’t have notifications. Of course, to implement notifications, you need user accounts with email verification, which was a whole other set of features that I just never got around to implementing. And even if I did, I would have taken me a lot more effort to get to the level of quality that Disqus provides.

Integrating Disqus Into Your Web Site

Disqus provides a service that lets me import, export and manage comments for my site’s blog posts, the UI for my web site to collect and display comments and the notification system that fosters discussions. And they watch for spam, too. Here’s what it looks like on a recent post on my site:

image

The Disqus services provides a discussion UI for your web site

 

Not only does Disqus provide the UI for comments, but it also provides the account management so that commenters can have icons and get notifications. With the settings to allow for guest posting, the barrier to entry for the reader that wants to leave a comment is zero. Adding the code to enable it on your site isn’t zero, but it’s pretty close. Once you’ve established a free account on disqus.com, you can simply create a forum for your site and drop in some boilerplate code. Here’s what I added to my MVC view for a post’s detail page to get the discussion section above:

<%-- Details.aspx –%>
...
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
  <!-- post –>
  ...
  <h1><%= Model.Post.Title %></h1>
  <div><%= Model.Post.Content %></div>
  <!-- comments -->
  <div id="disqus_thread"></div>
  <script type="text/javascript">
    var disqus_shortname = "YOUR-DISQUS-SITE-SHORTNAME-HERE";
    var disqus_identifier = <%= Model.Post.Id %>;
    var disqus_title = "<%= Model.Post.Title %>";

    /* * * DON'T EDIT BELOW THIS LINE * * */
    (function () {
      var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
      dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
      (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
  </script>
</asp:Content>

The discussion section for any post is just a div with the id set to disqus_thread”. The code is from the useful-but-difficult-to-find Disqus universal embed code docs. The JavaScript added to the end of the page creates a Disqus discussion control in the div you provide using the JS variables defined at the top of the code. The only JS variable that’s required is the disqus_shortname, which defines the Disqus data source for your comments. The disqus_identifier is a unique ID associated with the post. If this isn’t provided, the URL for the page the browser is currently showing will be used, but that doesn’t work for development mode from localhost or if the comments are hosted on multiple sites, e.g. a staging server and a production server, so I recommend setting disqus_identifier explicitly. The disqus_title will likewise be taken from the current page’s title, but it’s better to set it yourself to make sure it’s what you want.

And that’s it. Instead of tuning your UI in the JS code, you do so in the settings on disqus.com yourself an includes things like the default order of comments, the color scheme, how much moderation you want, etc.

There’s one more page on your site where you’ll want to integrate Disqus: the page the provides the list of posts along with the comment link and comment count:

image

Disqus will add comment count to your comment lists, too

 

Adding support for the comment count is similar to adding support for the discussion itself:

<%-- Index.aspx --%>
...
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
  ...
  <!-- post -->
  <h2><%= Html.ActionLink(post.Title, "Details", "Posts", new { id = post.Id }, null) %></h2>
  <p><%= post.Content %></p>
  <!-- comment link --> 
  <p><%= Html.ActionLink("0 comments", "Details", "Posts", null, null, "disqus_thread",
new RouteValueDictionary(
new { id = post.Id }),
new Dictionary<string, object>() { { "data-disqus-identifier", post.Id } }) %></p> ...
  <script type="text/javascript">
    // from: https://help.disqus.com/customer/portal/articles/565624
    var disqus_shortname = "sellsbrothers";

    /* * * DON'T EDIT BELOW THIS LINE * * */
    (function () {
      var s = document.createElement('script'); s.async = true;
      s.type = 'text/javascript';
      s.src = 'http://' + disqus_shortname + '.disqus.com/count.js';
      (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
    }());
  </script>
</asp:Content>

Again, this code is largely boilerplate and comes from the Disqus comment count docs. The call to Html.ActionLink is just a fancy way to get an A tag with an href of the following format:

<a href=“/Posts/Details/<<POST-ID>>#disqus_thread data-disqus-identifier=“<<POST-ID>>”>0 comments</a>

The disqus_thread” tag at the end of the href does two things. The first is that it provides a link to the discussion portion of the details page so that the reader can scroll directly to the comments after reading the post. The second is that it provides a tag for the Disqus JavaScript code to change the text content of the A tag to show the number of comments.

The data-disqus-identifier” attribute sets the unique identifier for the post itself, just like the disqus_identifier JS variable we saw earlier.

The A tag text content that you provide will only be shown if Disqus does not yet know about that particular post, i.e. if there are no comments yet, then it will leave it alone. However, if Disqus does know about that post, it will replace the text content of the A tag as per your settings, which allow you to be specific about how you want 0, 1 and n comments to show up on your site; 0 comments”, 1 comment” and {num} comments” are the defaults.

Importing Existing Comments into Disqus

At this point, your site is fully enabled for Disqus discussions and you can deploy. In the meantime, if you’ve got existing comments like I did, you can import them using Disqus’s implementation of the WordPress WXR format, which is essentially RSS 2.0 with embedded comments. The Disqus XML import docs describe the format and some important reminders. The two reminders they list are important enough to list again here:

  • Register a test forum and import to that forum first to work out the kinks.” Because Disqus only lists some of the restrictions on their site for the imported data, I probably had to do a dozen or more imports before I get everything to move over smoothly. I ended up using two test forums before I was confident enough to import comments into my the real forum for my site.
  • Keep individual file sizes < 50 MB each.” In fact, I found 20MB to be the maximum reliable size. I had to write my script to split my comments across multiple files to keep to this limit or my uploads would time out.

 

The XML import docs do a good job showing what the XML format is as an example, but they only list one of the data size requirements. In my work, I found several undocumented limits as well:

  • comment_content must be >= 3 characters (space trimmed) and <= 25,000 characters. I found out the max when trying to import some of my unapproved spam comments.
  • comment_author and comment_author_email must be <= 75 characters. You may get errors about comment_author being too long even if you haven’t provided one; that just means that Disqus has grabbed comment_author_email as the contents for comment_author.
  • post_date_gmt and comment_date_gmt must be formatted correctly as yyyy-MM-dd HH:mm:ss. Of course, they must be in GMT, too.
  • The actual post content should be empty. Even though it looks like you’re uploading your entire blog via RSS, you’re only providing enough of the post content to allow Disqus to map from post to associated comments, like the thread_identifier referenced as disqus_thread in the JavaScript code above, as well as to show the post title and date as appropriate. The only real content you’re importing into Disqus is the comment content associated with each post.

Something else to keep in mind is that as part of the comment import process is that Disqus translates the XML data into JSON data, which makes sense. However, they report their errors in terms of the undocumented JSON data structure, which can be confusing as hell. For example, I kept getting a missing or invalid message” error message along with the JSON version of what I thought the message was to which they were referring. The problem was that by message”, Disqus didn’t mean the JSON data packet for a particular comment,” they meant the field called message’ in our undocumented JSON format which is mapped from the comment_content element of the XML.” I went round and round with support on this until I figured that out. Hopefully I’ve saved future generations that trouble.

If you’re a fan of LINQPad or C#, you can see the script I used to pull the posts and comments out of my site’s SQL Server database (this assumes an Entity Framework mapping in a separate DLL, but you get the gist). The restrictions I mention above are encapsulated in this script.

Where Are We?

Even though my rssComments extension to the RSS protocol was a failed experiment, the web has figured out how to foster spam-free, interactive discussions with email notifications across web sites. The free Disqus service provides as implementation of this idea and it does so beautifully. I wish importing comments was as easy as integrating the code, but since I only had to do it once, the juice was more than worth the squeeze, as a dear Australian friend of mine likes to say. Enjoy!