Maarten Balliauw {blog}

ASP.NET MVC, Microsoft Azure, PHP, web development ...

NAVIGATION - SEARCH

REST for ASP.NET MVC SDK

REST - Representational State Transfer Earlier this week, Phil Haack did a post on the newly released REST for ASP.NET MVC SDK. I had the feeling though that this post did not really get the attention it deserved. I do not have the idea my blog gets more visitors than Phil’s, but I’ll try to give the SDK some more attention by blogging an example. But first things first…

kick it on DotNetKicks.com

What is it?

“REST for ASP .NET MVC is a set of capabilities that enable developers building a website using ASP .NET MVC to easily expose a Web API for the functionality of the site. “

Ok then. Now you know. It will get more clear after reading the next topic.

When should I use this?

There are of course features in WCF that enable you to build REST-ful services, but…

In many cases, the application itself is the only reason for development of the service. In other words, when the only reason for the service’s existence is to service the one application you’re currently building, it may make more sense  would stick with the simple case of using ASP.NET MVC. (Phil Haack)

Quickly put: why bother setting up a true WCF service layer when the only reason for that is the web application you are building?

Let me add another statement. Add a comment if you disagree:

In many cases, you are building an ASP.NET MVC application serving HTML, and building a WCF layer exposing XML and/or JSON using REST, so you can use this in your Ajax calls and such. Why build two or three things displaying the same data, but in another format?

This is where the REST for ASP.NET MVC SDK comes in handy: it adds “discovery” functionality to your ASP.NET MVC application, returning the client the correct data format he requested. From the official documentation:

  1. It includes support for machine-readable formats (XML, JSON) and support for content negotiation, making it easy to add POX APIs to existing MVC controllers with minimal changes.
  2. It includes support for dispatching requests based on the HTTP verb, enabling “resource” controllers that implement the uniform HTTP interface to perform CRUD (Create, Read, Update and Delete) operations on the model.
  3. Provides T4 controller and view templates that make implementing the above scenarios easier.

An example…

… a simple ASP.NET MVC application!

Let’s say you have an application where you can create, read, update and delete your own name and firstname. We have a simple model for that:

[code:c#]

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

[/code]

We can do CRUD operations on this in our ASP.NET MVC application, using the action methods in our PersonController:

[code:c#]

public class PersonController : Controller
{
    protected List<Person> Data
    {
        get
        {
            if (Session["Persons"] == null)
            {
                Session["Persons"] = new List<Person>();
            }
            return (List<Person>)Session["Persons"];
        }
    }

    //
    // GET: /Person/

    public ActionResult Index()
    {
        return View(Data);
    }

    //
    // GET: /Person/Details/5

    public ActionResult Details(int id)
    {
        return View(Data.FirstOrDefault(p => p.Id == id));
    }

    //
    // GET: /Person/Create

    public ActionResult Create()
    {
        return View(new Person());
    }

    //
    // POST: /Person/Create

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Person person)
    {
        try
        {
            person.Id = Data.Count + 1;
            Data.Add(person);

            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

    //
    // GET: /Person/Edit/5

    public ActionResult Edit(int id)
    {
        return View(Data.FirstOrDefault(p => p.Id == id));
    }

    //
    // POST: /Person/Edit/5

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(int id, FormCollection collection)
    {
        try
        {
            Person person = Data.FirstOrDefault(p => p.Id == id);
            UpdateModel(person, new string[] { "FirstName", "LastName" }, collection.ToValueProvider());
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }
}

[/code]

Any questions on this? Read the book :-)

… get some REST for FREE!

Like all “free” things in life, there’s always at least a little catch. “Free” in this case means:

  1. Adding a reference to System.Web.Mvc.Resources.dll provided by the REST for ASP.NET MVC SDK
  2. Registering another controller factory in Global.asax.cs (more on that later)
  3. Adding the [WebApiEnabled] to every controller and/or action method you want to expose via REST.

The first step is quite straightforward: get the bits from CodePlex, compile, and add it as a reference in your MVC project. Next, open Global.asax.cs and add the following in Application_Start:

[code:c#]

protected void Application_Start()
{
    // We use this hook to inject our ResourceControllerActionInvoker
    // which can smartly map HTTP verbs to Actions
    ResourceControllerFactory factory = new ResourceControllerFactory();
    ControllerBuilder.Current.SetControllerFactory(factory);

    // We use this hook to inject the ResourceModelBinder behavior
    // which can de-serialize from xml/json formats
    ModelBinders.Binders.DefaultBinder = new ResourceModelBinder();

    // Regular register routes
    RegisterRoutes(RouteTable.Routes);
}

[/code]

What we do here is tell ASP.NET MVC to create controllers using the ResourceControllerFactory provided by the REST for ASP.NET MVC SDK.

Next: add the [WebApiEnabled] to every controller and/or action method you want to expose via REST. And that’s about it. Here’s what I get in my application if I browse to http://localhost:2681/Person:

image

Nothing fancy here, just a regular ASP.NET MVC application. But wait, let’s now browse to http://localhost:2681/Person?format=Xml:

image

Cool, no? And we only added 4 lines of code. But there’s more! I can also browse to http://localhost:2681/Person?format=Json and get JSON data returned. But that’s not all. There’s more!

  • You can add custom FormatHandler classes and, for example, provide one that handles RSS data.
  • There’s no need to always add the query string variable “format”: you can also specify the type of content you want in your HTTP request, by setting the HTTP “Accept” header. For example, if I set the Accept header to “application/json,text/xml”, REST for ASP.NET MVC will provide me with JSON if possible, and if not, it will send me XML. This approach is particularly useful when working with AJAX calls on your view.

Downloads

Here’s a list of downloads:

kick it on DotNetKicks.com

Book review: ASP.NET 3.5 CMS Development

ASP.NET 3.5 CMS Development From time to time, the people at Packt Publishing send me a free book, fresh of the presses, and ask nicely if I want to read it and write a review on my blog. Last week, I received their fresh ASP.NET 3.5 CMS Development book, written by Curt Christianson and Jeff Cochran, both Microsoft MVP (ASP.NET and IIS).

According to the website, the book aims at learning people how to build a CMS. Now, I know from writing my ASP.NET MVC 1.0 Quickly book that these texts are written mostly by marketing people.

This step-by-step tutorial shows the reader how to build an ASP.NET Content Management System from scratch. You will first learn the basics of a content management system and how to set up the tools you need to build your site. Then, you start building your site, setting up users, and adding content to your site. You will be able to edit the content of your site and also manage its layout all by yourself. Towards the end, you will learn to manage your site from a single point and will have all the information you need to extend your site to make it more powerful.

Filled with plenty of code snippets and screen images to keep you on track as well as numerous additional samples to show you all the exciting alternatives to explore, this book prepares you for all the challenges you can face in development. 

Ok, it is true: this book will show you how to build a content management system in ASP.NET 3.5. However, if you are a developer working with ASP.NET for several years and the CMS part is the reason you are buying this book, you will be a bit disappointed. Don’t get me wrong, the book is good for another audience: if you are making your first steps in ASP.NET development and want to learn how things like datasources, n-tier development, membership provider, extensibility, … work, by example, this book is actually pretty good at that. Curt and Jeff managed to squeeze in about all commonly used ASP.NET features using only one example application that is built from ground up.

Conclusion: probably not the book for experienced developers, but an ideal “large, example-driven tutorial” for beginning development with ASP.NET 3.5.

ASP.NET MVC 2 Preview 1 released!

Today, Phil Haack did a blog post on the release of ASP.NET MVC 2 Preview 1! Get it while it’s fresh :-) An updated roadmap is also available on CodePlex.

Guess now is about time to start revising my ASP.NET MVC 1.0 Quickly book…

kick it on DotNetKicks.com

New features in ASP.NET MVC Preview 1

Templated helpers

Templated helpers are not new: ASP.NET Dynamic Data already used this feature. Basically, you are creating a default control when you want to display/edit a specific data type in a view. For example, a System.String will have a user control defined that renders a textbox. However, if you want this to be a TinyMCE control by default, you’ll have to change the templated helper in one place and you’re done.

More concrete: create a new view in your application: Views\Shared\DisplayTemplates\String.ascx. The code for that view would be:

[code:c#]

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<strong><%= Html.Encode(Model) %></strong>

[/code]

There you go: every string you want to put in a view using the <%= Html.DisplayFor(c => person.Name) %> HtmlHelper will render that string in bold.

Note that your domain class can also use UI hints to specify the templated helper to use when rendering:

[code:c#]

public class Person {
    [UIHint("NameTextBox")]
    public string Name { get; set; }

    // ...
}

[/code]

This will make sure that when Person’s Name is rendered, the NameTextBox.ascx control will be used instead of the default one.

Areas

Finally, native support for areas! Areas help you split your application into more logical subsections, which is useful when working with large projects.Each area is implemented as a separate ASP.NET MVC. When compiling, ASP.NET MVC invokes a build task which merges all areas into the main application.

Check MSDN for a detailed example on using areas. I’ll get this one in MvcSiteMap as soon as possible.

Support for DataAnnotations

The new ASP.NET MVC 2 default model binder makes use of the System.ComponentModel.DataAnnotations namespace to perform validation at the moment of binding data to the model. This concept was used for ASP.NET Dynamic Data, recently picked up by the RIA services team and now also available for ASP.NET MVC.

Basically, what you have to do in order to validate your domain objects, is decorating the class’properties with some DataAnnotations:

[code:c#]

public class Person {
    [Required(ErrorMessage = "Name is required.")]
    [StringLength(60, ErrorMessage = "Name should not exceed 60 characters.")]
    public string Name { get; set; }

    // ...
}

[/code]

Easy no? Now just use the model binder inside your controller and validation will occur “automagically”.

Also check my blog post on TwitterMatic for another example.

HttpPost attribute

A small update: [AcceptVerbs(HttpVerbs.Post)] can now be written as [HttpPost]. Easier to read IMHO.

This means that:

[code:c#]

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Person person) {
    // ...
}

[/code]

becomes the following:

[code:c#]

[HttpPost]
public ActionResult Create(Person person) {
    //...
}

[/code]

DefaultValueAttribute

Default parameter values in an action method can now be specified using an attribute. This attribute currently only seems to support primitive types (such as integers, booleans, strings, …). Here’s an example:

[code:c#]

public class PersonController : Controller {
    public ActionResult Create([DefaultValue("Maarten")]string name) {
        // ...
    }
}

[/code]

kick it on DotNetKicks.com

ReMIX Belgium session on ASP.NET MVC

image Just learned I’ll be doing a session on ASP.NET MVC at ReMIX Belgium. ReMix brings the best of MIX09 in Las Vegas to Belgium: it bring us international speakers presenting on the best of MIX09, as well as local cases, with a story focus on User Experience (UX).

The session will be around building a Twitter clone in 60 minutes. Bear with me at ReMIX 2009!

Abstract: “What are you doing right now?, that's Twitter's question to its users. How about you creating own microblogging platform? "What are you working on?", "What are you reading?", ..., are all specific questions for your own community. This session takes you along in building a Twitter clone using the ASP.NET MVC framework.”

Authenticating users with RPXNow (in ASP.NET MVC)

ASP.NET MVC RPX RPXNow Don’t you get sick of having to register at website X, at website Y, at website Z, …? It is really not fun to maintain all these accounts, change passwords, … Luckily, there are some large websites offering delegated sign-in (for example Google Accounts, Live ID, Twitter OAuth, …). You can use these delegated sign-in methods on your own site, removing the need of registering yet another account. Unfortunately, not everyone has an account at provider X…

A while ago, I found out about the free service JanRain is offering: RPXNow. This (free!) service combines the strengths of several major account providers (Google Accounts, Live ID, Twitter, Facebook, OpenID, …) into one simple API. This means that people are able to log in to your website if they have an account at one of these providers! Here’s how to use it in ASP.NET MVC…

Download sample code: Rpx4Mvc.zip (246.97 kb)

kick it on DotNetKicks.com

Creating some HTML helpers

After registering at RPXNow, you will receive an application name and API key. This application name should be used when embedding the login control that is provided. To simplify embedding a login link, I’ve created two HtmlHelper extension methods: one for embedding the login control, another one for providing a login link:

[code:c#]

public static class HtmlHelperExtensions
{
    public static string RpxLoginEmbedded(this HtmlHelper helper, string applicationName, string tokenUrl)
    {
        return "<iframe src=\"https://" + applicationName + ".rpxnow.com/openid/embed?token_url=" + tokenUrl + "\" scrolling=\"no\" frameBorder=\"no\" style=\"width:400px;height:240px;\" class=\"rpx-embedded\"></iframe>";
    }

    public static string RpxLoginPopup(this HtmlHelper helper, string applicationName, string tokenUrl, string linkText)
    {
        return "<script src=\"https://rpxnow.com/openid/v2/widget\" type=\"text/javascript\"></script><script type=\"text/javascript\">RPXNOW.overlay = true; RPXNOW.language_preference = 'en';</script>" +
            "<a class=\"rpxnow\" onclick=\"return false;\" href=\"https://" + applicationName + ".rpxnow.com/openid/v2/signin?token_url=" + tokenUrl + "\">" + linkText + "</a>";     
    }
}

[/code]

I can now add a login link in my views more easily:

[code:c#]

<%=Html.RpxLoginPopup("localtestapp", "http://localhost:1234/Account/Login", "Login") %>

[/code]

Creating the RPX implementation

The RPX implementation is quite easy. When a user logs in, a token is posted to your web application. Using this token and the API key, you can query the RPX service for a profile Here’s a simple class which can take care of all this:

[code:c#]

public class RpxLogin
{
    protected string apiKey = "";

    public RpxLogin(string apiKey)
    {
        this.apiKey = apiKey;
    }

    public RpxProfile GetProfile(string token)
    {
        // Fetch authentication info from RPX
        Uri url = new Uri(@"https://rpxnow.com/api/v2/auth_info");
        string data = "apiKey=" + apiKey + "&token=" + token;

        // Auth_info request
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.Method = "POST";
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = data.Length;

        StreamWriter requestWriter = new StreamWriter(request.GetRequestStream(), Encoding.ASCII);
        requestWriter.Write(data);
        requestWriter.Close();

        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        TextReader responseReader = new StreamReader(response.GetResponseStream());
        string responseString = responseReader.ReadToEnd();
        responseReader.Close();

        // De-serialize JSON
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        RpxAuthInfo authInfo = serializer.Deserialize<RpxAuthInfo>(responseString);

        // Ok?
        if (authInfo.Stat != "ok")
        {
            throw new RpxException("RPX login failed");
        }

        return authInfo.Profile;
    }
}

[/code]

Note that the RPX service returns JSON data, which I can deserialize using the JavaScriptSerializer. That’s really all it takes to get the logged-in user name.

Plumbing it all together

All of the above can be plumbed together in a new AccountController. This will have to be extended for your application (i.e. for storing the logged in username in a membership database, … Simply add these two action methods in a blank AccountController and you are ready to RPX!

[code:c#]

[HandleError]
public class AccountController : Controller
{
    public ActionResult Login(string token)
    {
        if (string.IsNullOrEmpty(token)) {
            return View();
        } else {
            IRpxLogin rpxLogin = new RpxLogin("b2e418e8e2dbd8cce612b829a9234ed4a763b2c0");
            try
            {
                RpxProfile profile = rpxLogin.GetProfile(token);

                FormsAuthentication.SetAuthCookie(profile.DisplayName, false);
            }
            catch (RpxException)
            {
                return RedirectToAction("Login");
            }

            return RedirectToAction("Index", "Home");
        }
    }

    [Authorize]
    public ActionResult Logout()
    {
        FormsAuthentication.SignOut();
        return RedirectToAction("Index", "Home");
    }
}

[/code]

Download a sample application: Rpx4Mvc.zip (246.97 kb)

kick it on DotNetKicks.com

How we built TwitterMatic.net - Part 5: the front-end

TwitterMatic - Schedule your Twitter updates“After having found a god-like guardian for his application, Knight Maarten The Brave Coffeedrinker found out that his application still had no functional front-end. It’s OK to have a guardian and a barn in the cloud, but if there’s nothing to guard, this is a bit useless. Having asked the carpenter and the smith of the village, our knight decided that the so-called “ASP.NET MVC” framework might help in his quest.”

This post is part of a series on how we built TwitterMatic.net. Other parts:

kick it on DotNetKicks.com

The front-end

In part 2 of this series, we have already created the basic ASP.NET MVC structure in the web role project. There are few action methods and views to create: we need one for displaying our scheduled tweets and one for scheduling a tweet. We’ll concentrate on the latter in this post.

Action methods

The Create action method will look like this:

[code:c#]

// GET: /Tweet/Create

public ActionResult Create()
{
    TimedTweet tweet = new TimedTweet();

    ViewData["SendOnDate"] = tweet.SendOn.ToShortDateString();
    ViewData["SendOnTime"] = tweet.SendOn.ToShortTimeString();

    return View(tweet);
}

// POST: /Tweet/Create

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(int UtcOffset, string SendOnDate, string SendOnTime, FormCollection collection)
{
    TimedTweet tweet = new TimedTweet(this.User.Identity.Name);
    try
    {
        tweet.SendOn = DateTime.Parse(SendOnDate + " " + SendOnTime).AddMinutes(UtcOffset);

        // Ensure we have a valid SendOn date
        if (!TimedTweetValidation.ValidateFutureDate(tweet.SendOn))
        {
            ModelState.AddModelError("SendOn", "The scheduled time should be in the future.");
        }

        if (this.TryUpdateModel(tweet, new string[] { "Status" }, collection.ToValueProvider()) && ModelState.IsValid)
        {
            // ...
            Repository.Insert(this.User.Identity.Name, tweet);

            return RedirectToAction("Index");
        }
        else
        {
            // ...
            return View(tweet);
        }
    }
    catch
    {
        // ...
        return View(tweet);
    }
}

[/code]

As you can see, we’re doing the regular GET/POST differentiation here: GET to show the Create view, POST to actually do something with user-entered data. Nothing too fancy in the code, just passing some data to the repository we created in an earlier post.

Views

The view for our Create action is slightly more work. I’ve noticed a cool date picker at http://ui.jquery.com, and a cool time picker at http://haineault.com/media/jquery/ui-timepickr/page/. Why not use them both?

Here’s the plain, simple view, no jQuery used:

[code:c#]

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<TwitterMatic.Shared.Domain.TimedTweet>" %>

<asp:Content ID="title" ContentPlaceHolderID="TitleContent" runat="server">
    Schedule a tweet for <%=User.Identity.Name%>
</asp:Content>

<asp:Content ID="content" ContentPlaceHolderID="MainContent" runat="server">
    <h3>Schedule a tweet for <%=User.Identity.Name%></h3>

    <% if (!ViewData.ModelState.IsValid) { %>
        <%= Html.ValidationSummary("Could not schedule tweet. Please correct the errors and try again.") %>
    <% } %>

    <% using (Html.BeginForm()) {%>
        <%=Html.Hidden("UtcOffset", 0)%>

        <fieldset>
            <legend>Schedule a tweet</legend>
            <p>
                <label for="Status">Message:</label>
                <%= Html.TextArea("Status") %>
                <%= Html.ValidationMessage("Status", "*") %>
                <span id="status-chars-left">140</span>
            </p>
            <p>
                <label for="SendOn">Send on:</label>
                <%= Html.TextBox("SendOnDate", ViewData["SendOnDate"]) %>
                <%= Html.TextBox("SendOnTime", ViewData["SendOnTime"]) %>
            </p>
            <p>
                <button type="submit" value="Schedule">
                    Schedule tweet!
                </button>
            </p>
        </fieldset>

    <% } %>

    <p style="clear: both;">
        <%= Html.ActionLink("Back to list of scheduled tweets", "Index", "Tweet", null, new { @class = "more" })%>
    </p>
    <p style="clear: both;">&nbsp;</p>
</asp:Content>

[/code]

Nothing fancy in there: just a boring data-entry form. Now let’s spice that one up: we’ll add the datepicker and timepicker:

[code:c#]

<script type="text/javascript">
    $(function() {
        $("#SendOnDate").datepicker({ minDate: 0, showAnim: 'slideDown', dateFormat: 'mm/dd/yy' });
        $("#SendOnTime").timepickr({ convention: 12, rangeMin: ['00', '05', '10', '15', '20', '25', '30', '35', '40', '45', '50', '55'] });
    });
</script>

[/code]

We’re telling jQuery to make a datepicker of the DOM element with id #SendOnDate, and to make a timepickr of the element #SendOnTime. Now let’s add some more useful things:

[code:c#]

<script type="text/javascript">
    $(function() {
        calcCharsLeft();
        $("#Status").keyup(function() {
            calcCharsLeft();
        });
    });

    var calcCharsLeft = function() {
        var charsLeft = (140 - $("#Status").val().length);

        $("#status-chars-left").html(charsLeft);
        if (charsLeft < 0) {
            $("#status-chars-left").css('color', 'red');
            $("#status-chars-left").css('font-weight', 'bold');
        } else {
            $("#status-chars-left").css('color', 'white');
            $("#status-chars-left").css('font-weight', 'normal');
        }
    }
</script>

[/code]

jQuery will now do some more things when the page has loaded: we’re telling the browser to call calcCharsLeft every time a key is pressed in the message text area. This way, we can add a fancy character counter next to the text box, which receives different colors when certain amount of text is entered.

Validation: using DataAnnotations

In the action methods listed earlier in this post, you may have noticed that we are not doing a lot of validation checks. Except for the “Time in the future” check, we’re actually not doing any validation at all!

The reason for not having any validation calls in my controller’s action method, is that I’m using a different model binder than the default one: the ASP.NET MVC team’s DataAnnotationsModelBinder. This model binder makes use of the System.ComponentModel.DataAnnotations namespace to perform validation at the moment of binding data to the model. This concept was used for ASP.NET Dynamic Data, recently picked up by the RIA services team and now also available for ASP.NET MVC.

Basically, what we have to do, is decorating our TimedTweet class’ properties with some DataAnnotations:

[code:c#]

public class TimedTweet : TableStorageEntity, IComparable
{
    public string Token { get; set; }
    public string TokenSecret { get; set; }

    [Required(ErrorMessage = "Twitter screen name is required.")]
    public string ScreenName { get; set; }

    [Required(ErrorMessage = "Message is required.")]
    [StringLength(140, ErrorMessage = "Message length must not exceed 140 characters.")]
    public string Status { get; set; }

    [Required(ErrorMessage = "A scheduled time is required.")]
    [CustomValidation(typeof(TimedTweetValidation), "ValidateFutureDate", ErrorMessage = "The scheduled time should be in the future.")]
    public DateTime SendOn { get; set; }
    public DateTime SentOn { get; set; }
    public string SendStatus { get; set; }
    public int RetriesLeft { get; set; }

    public bool Archived { get; set; }

    // ...
}

[/code]

See how easy this is? Add a [Required] attribute to make a property required. Add a [StringLength] attribute to make sure a certain length is not crossed, … The DataAnnotationsModelBinder will use these hints as a guide to perform validation on your model.

Conclusion

We now know how to work with ASP.NET MVC’s future DataAnnotations validation and have implemented this in TwitterMatic.

In the next part of this series, we’ll have a look at the worker role for TwitterMatic.

kick it on DotNetKicks.com

How we built TwitterMatic.net - Part 4: Authentication and membership

TwitterMatic - Schedule your Twitter updates“Knight Maarten The Brave Coffeedrinker just returned from his quest to a barn in the clouds, when he discovered that he forgot to lock the door to his workplace. He immediately asked the digital village’s smith.to create a lock and provide him a key. Our knight returned to his workplace and concluded that using the smith’s lock would be OK, but having the great god of social networking, Twitter, as a guardian, seemed like a better idea. “O, Auth!”, he said. And the god provided him with a set of prayers, an API, which our knight could use.”

This post is part of a series on how we built TwitterMatic.net. Other parts:

kick it on DotNetKicks.com

Authentication and membership

Why reinvent the wheel when we already have so many wheel manufacturers? I’m really convinced that from now on, nobody should EVER provide subscribe/login/password retrieval/… functionality to his users again! Use OpenID, or Live ID, or Google Accounts, or JanRain’s RPX bundling all types of existing authentication mechanisms. Did you hear me? NEVER provide your own authentication mechanism again, unless you have a solid reason for it!

Since we’re building an application for Twitter, and Twitter provides OAuth API for delegating authentication, why not use OAuth? As a start, here’s the flow that has to be respected when working with OAuth.

OAuth request flow diagram

Now let’s build this in to our application…

Implementing OAuth in TwitterMatic

First of all: if you are developing something and it involves a third-party product or service, chances are there’s something useful for you on CodePlex. In TwitterMatic’s case, that useful tool is LINQ to Twitter, providing OAuth implementation as well as a full API to the Twitter REST services. Thank you, JoeMayo!

The only thing we still have to do in order for TwitterMatic OAuth authentication to work, is create an AccountController in the web role project. Let’s start with a Login action method:

[code:c#]

IOAuthTwitter oAuthTwitter = new OAuthTwitter();
oAuthTwitter.OAuthConsumerKey = configuration.ReadSetting("OAuthConsumerKey");
oAuthTwitter.OAuthConsumerSecret = configuration.ReadSetting("OAuthConsumerSecret");

if (string.IsNullOrEmpty(oauth_token)) {
    // Not authorized. Redirect to Twitter!
    string loginUrl = oAuthTwitter.AuthorizationLinkGet(
        configuration.ReadSetting("OAuthRequestTokenUrl"),
        configuration.ReadSetting("OAuthAuthorizeTokenUrl"),
        false,
        true
    );
    return Redirect(loginUrl);
}

[/code]

Our users will now be redirected to Twitter in order to authenticate, if the method receives an empty or invalid oauth-token. If we however do retrieve a valid token, we’ll use FormsAuthentication cookies to keep the user logged in on TwitterMatic as well. Note that we are also saving the authentication token as the user’s password, we’ll be needing this same token to post updates afterwards.

[code:c#]

// Should be authorized. Get the access token and secret.
string userId = "";
string screenName = "";

oAuthTwitter.AccessTokenGet(oauth_token, configuration.ReadSetting("OAuthAccessTokenUrl"),
    out screenName, out userId);
if (oAuthTwitter.OAuthTokenSecret.Length > 0)
{
    // Store the user in membership
    MembershipUser user = Membership.GetUser(screenName);
    if (user == null)
    {
        MembershipCreateStatus status = MembershipCreateStatus.Success;
        user = Membership.CreateUser(
            screenName,
            oAuthTwitter.OAuthToken + ";" + oAuthTwitter.OAuthTokenSecret,
            screenName, 
            "twitter", 
            "matic",
            true,
            out status);
    }

    // Change user's password
    user.ChangePassword(
        user.GetPassword("matic"),
        oAuthTwitter.OAuthToken + ";" + oAuthTwitter.OAuthTokenSecret
    );
    Membership.UpdateUser(user);

    // All is well!
    FormsAuthentication.SetAuthCookie(screenName, true);
    return RedirectToAction("Index", "Home");
}
else
{
    // Not OK...
    return RedirectToAction("Login");
}

[/code]

Here’s the full code to AccountController:

[code:c#]

[HandleError]
public class AccountController : Controller
{
    protected IConfigurationProvider configuration;

    public ActionResult Login(string oauth_token)
    {
        IOAuthTwitter oAuthTwitter = new OAuthTwitter();
        oAuthTwitter.OAuthConsumerKey = configuration.ReadSetting("OAuthConsumerKey");
        oAuthTwitter.OAuthConsumerSecret = configuration.ReadSetting("OAuthConsumerSecret");

        if (string.IsNullOrEmpty(oauth_token)) {
            // Not authorized. Redirect to Twitter!
            string loginUrl = oAuthTwitter.AuthorizationLinkGet(
                configuration.ReadSetting("OAuthRequestTokenUrl"),
                configuration.ReadSetting("OAuthAuthorizeTokenUrl"),
                false,
                true
            );
            return Redirect(loginUrl);
        } else {
            // Should be authorized. Get the access token and secret.
            string userId = "";
            string screenName = "";

            oAuthTwitter.AccessTokenGet(oauth_token, configuration.ReadSetting("OAuthAccessTokenUrl"),
                out screenName, out userId);
            if (oAuthTwitter.OAuthTokenSecret.Length > 0)
            {
                // Store the user in membership
                MembershipUser user = Membership.GetUser(screenName);
                if (user == null)
                {
                    MembershipCreateStatus status = MembershipCreateStatus.Success;
                    user = Membership.CreateUser(
                        screenName,
                        oAuthTwitter.OAuthToken + ";" + oAuthTwitter.OAuthTokenSecret,
                        screenName,
                        configuration.ReadSetting("OAuthConsumerKey"),
                        configuration.ReadSetting("OAuthConsumerSecret"),
                        true,
                        out status);
                }

                // Change user's password
                user.ChangePassword(
                    user.GetPassword(configuration.ReadSetting("OAuthConsumerSecret")),
                    oAuthTwitter.OAuthToken + ";" + oAuthTwitter.OAuthTokenSecret
                );
                Membership.UpdateUser(user);

                // All is well!
                FormsAuthentication.SetAuthCookie(screenName, true);
                return RedirectToAction("Index", "Home");
            }
            else
            {
                // Not OK...
                return RedirectToAction("Login");
            }
        }
    }

    public ActionResult Logout()
    {
        FormsAuthentication.SignOut();
        return RedirectToAction("Index", "Home");
    }
}

[/code]

Using ASP.NET provider model

The ASP.NET provider model provides abstractions for features like membership, roles, sessions, … Since we’ll be using membership to store authenticated users, we’ll need a provider that works with Windows Azure Table Storage. The Windows Azure SDK samples contain a project '”AspProviders”. Reference it, and add the following to your web.config:

[code:xml]

<?xml version="1.0"?>
<configuration>
  <!-- ... -->

  <appSettings>
    <add key="DefaultMembershipTableName" value="Membership" />
    <add key="DefaultRoleTableName" value="Roles" />
    <add key="DefaultSessionTableName" value="Sessions" />
    <add key="DefaultProviderApplicationName" value="TwitterMatic" />
    <add key="DefaultProfileContainerName" />
    <add key="DefaultSessionContainerName" />
  </appSettings>

  <connectionStrings />

  <system.web>
    <!-- ... -->

    <authentication mode="Forms">
      <forms loginUrl="~/Account/Login" />
    </authentication>

    <membership defaultProvider="TableStorageMembershipProvider">
      <providers>
        <clear/>
        <add name="TableStorageMembershipProvider"
             type="Microsoft.Samples.ServiceHosting.AspProviders.TableStorageMembershipProvider"
             description="Membership provider using table storage"
             applicationName="TwitterMatic"
             enablePasswordRetrieval="true"
             enablePasswordReset="true"
             requiresQuestionAndAnswer="true"
             minRequiredPasswordLength="1"
             minRequiredNonalphanumericCharacters="0"
             requiresUniqueEmail="false"
             passwordFormat="Clear" />
      </providers>
    </membership>

    <profile enabled="false" />

    <roleManager enabled="true" defaultProvider="TableStorageRoleProvider" cacheRolesInCookie="false">
      <providers>
        <clear/>
        <add name="TableStorageRoleProvider"
             type="Microsoft.Samples.ServiceHosting.AspProviders.TableStorageRoleProvider"
             description="Role provider using table storage"
             applicationName="TwitterMatic" />
      </providers>
    </roleManager>

    <sessionState mode="Custom" customProvider="TableStorageSessionStateProvider">
      <providers>
        <clear />
        <add name="TableStorageSessionStateProvider"
             type="Microsoft.Samples.ServiceHosting.AspProviders.TableStorageSessionStateProvider"
             applicationName="TwitterMatic" />
      </providers>
    </sessionState>

    <!-- ... -->
  </system.web>

  <!-- ... -->
</configuration>

[/code]

TwitterMatic should now be storing sessions (if we were to use them), membership and roles in the cloud, by just doing some configuration magic. I love ASP.NET for this!

Conclusion

We now know how to leverage third-party authentication (OAuth in our case) and have implemented this in TwitterMatic.

In the next part of this series, we’ll have a look at the ASP.NET MVC front end and how we can validate user input before storing it in our database.

kick it on DotNetKicks.com

How we built TwitterMatic.net - Part 3: Store data in the cloud

TwitterMatic - Schedule your Twitter updates “After setting up his workplace, knight Maarten The Brave Coffeedrinker thought of something else: if a farmer wants to keep a lot of hay, he needs a barn, right? Since the cloudy application would also need to keep things that can be used by the digital villagers, our knight needs a barn in the clouds. Looking at the azure sky, an idea popped into the knight’s head: why not use Windows Azure storage service? It’s a barn that’s always there, a barn that can catch fire and will still have its stored items located in a second barn (and a third). Knight Maarten The Brave Coffeedrinker jumped on his horse and went on a quest, a quest in the clouds.

This post is part of a series on how we built TwitterMatic.net. Other parts:

kick it on DotNetKicks.com

Store data in the cloud

Windows Azure offers 3 types of cloud storage: blobs, tables and queues. Blob Storage stores sets of binary data, organized in containers of your storage account. Table Storage offers structured storage in the form of tables. The Queue service stores an unlimited number of messages, each of which can be up to 8 KB in size.

Let’s look back at the TwitterMatic architecture:

“The worker role will monitor the table storage for scheduled Tweets. If it’s time to send them, the Tweet will be added to a queue. This queue is then processed by another thread in the worker role, which will publish the Tweet to Twitter. ”

This means we’ll be using two out of three storage types: Table Storage and Queue Storage. Problem: these services are offered as a RESTful service, somewhere in the cloud. Solution to that: use the StorageClient project located in the Windows Azure SDK’s samples directory!

The StorageClient project contains .NET API’s that work with the blob, table and queue storage services provided by Windows Azure. For Table Storage, StorageClient provides an extension on top of Astoria (ADO.NET Data Services Framework, but I still say Astoria because it’s easier to type and say…). This makes it easier for you as a developer to use existing knowledge, from LINQ to SQL or Entity Framework or Astoria, to develop Windows Azure applications.

Setting up StorageClient

Add a reference to the StorageClient project to your WebRole project. Next, add some settings to the ServiceConfiguration.cscfg file:

[code:xml]

<?xml version="1.0"?>
<ServiceConfiguration serviceName="TwitterMatic" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration">
  <Role name="WebRole">
    <Instances count="1"/>
    <ConfigurationSettings>
      <Setting name="AccountName" value="twittermatic"/>
      <Setting name="AccountSharedKey" value=”..."/>
      <Setting name="BlobStorageEndpoint" value="http://blob.core.windows.net"/>
      <Setting name="QueueStorageEndpoint" value = "http://queue.core.windows.net"/>
      <Setting name="TableStorageEndpoint" value="http://table.core.windows.net"/>
      <Setting name="allowInsecureRemoteEndpoints" value="true"/>
    </ConfigurationSettings>
  </Role>
  <Role name="WorkerRole">
    <Instances count="1"/>
    <ConfigurationSettings>
      <Setting name="AccountName" value="twittermatic"/>
      <Setting name="AccountSharedKey" value=”..."/>
      <Setting name="BlobStorageEndpoint" value="http://blob.core.windows.net"/>
      <Setting name="QueueStorageEndpoint" value = "http://queue.core.windows.net"/>
      <Setting name="TableStorageEndpoint" value="http://table.core.windows.net"/>
      <Setting name="allowInsecureRemoteEndpoints" value="true"/>
    </ConfigurationSettings>
  </Role>
</ServiceConfiguration>

[/code]

This way, both the web and worker role know where to find their data (URI) and how to authenticate (account name and shared key).

Working with tables

We’ll only be using one domain class in our entire project: TimedTweet. This class represents a scheduled Twitter update, containing information required to schedule the update. Here’s a list of properties:

  • Token: A token used to authenticate against Twitter
  • TokenSecret: A second token used to authenticate against Twitter
  • ScreenName: Twitter screen name of the user.
  • Status: The message to publish on Twitter.
  • SendOn: Time to send the message.
  • SentOn: Time the message was sent.
  • SendStatus: A status message (pending, in progress, published, …)
  • RetriesLeft: How many retries left before giving up on the Twitter update.
  • Archived: Yes/no if the message is archived.

Here’s the code:

[code:c#]

public class TimedTweet : TableStorageEntity, IComparable
{
    public string Token { get; set; }
    public string TokenSecret { get; set; }
    public string ScreenName { get; set; }
    public string Status { get; set; }
    public DateTime SendOn { get; set; }
    public DateTime SentOn { get; set; }
    public string SendStatus { get; set; }
    public int RetriesLeft { get; set; }
    public bool Archived { get; set; }

    public TimedTweet()
        : base()
    {
        SendOn = DateTime.Now.ToUniversalTime();
        Timestamp = DateTime.Now;
        RowKey = Guid.NewGuid().ToString();
        SendStatus = "Scheduled";
        RetriesLeft = 3;
    }

    public TimedTweet(string partitionKey, string rowKey)
        : base(partitionKey, rowKey)
    {
        SendOn = DateTime.Now.ToUniversalTime();
        SendStatus = "Scheduled";
        RetriesLeft = 3;
    }

    public int CompareTo(object obj)
    {
        TimedTweet target = obj as TimedTweet;
        if (target != null) {
            return this.SendOn.CompareTo(target.SendOn);
        }
        return 0;
    }
}

[/code]

Note that our TimedTweet is inheriting TableStorageEntity. This class provides some base functionality for Windows Azure Table Storage.

We’ll also need to work with this class against table Storage. For that, we can use TableStorage and TableStorageDataServiceContext class, like this:

[code:c#]

public List<TimedTweet> RetrieveAllForUser(string screenName) {
    StorageAccountInfo info = StorageAccountInfo.GetDefaultTableStorageAccountFromConfiguration(true);
    TableStorage storage = TableStorage.Create(info);

    storage.TryCreateTable("TimedTweet");

    TableStorageDataServiceContext svc = storage.GetDataServiceContext();
    svc.IgnoreMissingProperties = true;

    List<TimedTweet> result = svc.CreateQuery<TimedTweet>("TimedTweet").Where(t => t.ScreenName ==     screenName).ToList();
    foreach (var item in result)
    {
        svc.Detach(item);
    }
    return result;
}

[/code]

Using this, we can build a repository class based on ITimedtweetRepository and implemented against Table Storage:

[code:c#]

public interface ITimedTweetRepository
{
    void Delete(string screenName, TimedTweet tweet);
    void Archive(string screenName, TimedTweet tweet);
    void Insert(string screenName, TimedTweet tweet);
    void Update(TimedTweet tweet);
    List<TimedTweet> RetrieveAll(string screenName);
    List<TimedTweet> RetrieveDue(DateTime dueDate);
    TimedTweet RetrieveById(string screenName, string id);
}

[/code]

Working with queues

Queues are slightly easier to work with: you can enqueue messages and dequeue messages, and that’s about it. Here’s an example snippet:

[code:c#]

public void EnqueueMessage(string message) {
    StorageAccountInfo info = StorageAccountInfo.GetDefaultTableStorageAccountFromConfiguration(true);

    QueueStorage queueStorage = QueueStorage.Create(info);
    MessageQueue updateQueue = queueStorage.GetQueue("updatequeue");
    if (!updateQueue.DoesQueueExist())
        updateQueue.CreateQueue();

    updateQueue.PutMessage(new Message(message));
}

Conclusion

[/code]

We now know how to use StorageClient and have a location in the cloud to store our data.

In the next part of this series, we’ll have a look at how we can leverage Twitter’s OAuth authentication mechanism in our own TwiterMatic application and make use of some other utilities packed in the Windows Azure SDK.

kick it on DotNetKicks.com

How we built TwitterMatic.net - Part 2: Creating an Azure project

TwitterMatic - Schedule your Twitter updates “Knight Maarten The Brave Coffeedrinker was about to start working on his TwitterMatic application, named after the great god of social networking, Twitter. Before he could start working, he first needed the right tools. He downloaded the Windows Azure SDK, a set of tools recommended by the smith (or was it the carpenter?) of the digital village. Our knight’s work shack was soon ready to start working. The table on which the application would be crafted, was still empty. Time for action, the knight thought. And he started working.”

This post is part of a series on how we built TwitterMatic.net. Other parts:

kick it on DotNetKicks.com

Creating an Azure project

Here we go. After installing the Windows Azure SDK, start a new project: File > New > Project... Next, add a “Web And Worker Cloud Service”, located under Visual C# (or VB...) > Cloud Service > Web And Worker Cloud Service.

The project now contains three projects:

TwitterMatic Visual Studio Solution

The web role project should be able to run ASP.NET, but not yet ASP.NET MVC. Add /Views, /Controllers, Global.asax.cs, references to System.Web.Mvc, System.Web.Routing, … to make the web role an ASP.NET MVC project. This should work out fine, except for the tooling in Visual Studio. To enable ASP.NET MVC tooling, open the TwitterMatic_WebRole.csproj file using Notepad and add the following: (copy-paste: {603c0e0b-db56-11dc-be95-000d561079b0})

Enable ASP.NET MVC tooling in Windows Azure project

Visual Studio will prompt to reload the project, allow this by clicking the "Reload" button.

(Note: we could have also created a web role from an ASP.NET MVC project, check my previous series on Azure to see how to do this.)

Sightseeing

True, I ran over the previous stuff a bit fast, as it is just plumbing ASP.NET MVC in a Windows Azure Web Role. I have written about this in more detail before, check my previous series on Azure. There are some other things I would like to show you though.

The startup project in a Windows Azure solution contains some strange stuff:

TwitterMatic startup project

This project contains 3 types of things: the roles in the application, a configuration file and a file describing the required configuration entries. The “Roles” folder contains a reference to the projects that perform the web role on one side, the worker role on the other side. ServiceConfiguration.cscfg contains all configuration entries for the web and worker roles, such as the number of instances (yes, you can add more servers simply by putting a higher integer in there!) and other application settings such as storage account info.

ServiceDefinition.csdef is basically a copy of the other config file, but without the values. If you are wondering why: if someone screws with ServiceConfiguration.cscfg when deploying the application to Windows Azure, the deployment interface will know that there are settings missing or wrong. Perfect if someone else will be doing deployment to production!

Conclusion

We now have a full Windows Azure solution, with ASP.NET MVC enabled! Time to grab a prefabricated CSS theme, add a logo, … Drop-in ASP.NET MVC themes can always be found at http://www.asp.net/mvc/gallery. The theme we used should be there as well (thanks for that, theme author!).

In the next part of this series, we’ll have a look at where and how we can store our data.

kick it on DotNetKicks.com

How we built TwitterMatic.net - Part 1: Introduction

TwitterMatic “Once upon a time, Microsoft started a Windows Azure developing contest named new CloudApp();. While it first was only available for US candidates, the contest was opened for international submissions too. Knight Maarten The Brave Coffeedrinker and his fellow knightsmen at RealDolmen decided to submit a small sample application that could be hosted in an unknown environment, known by the digital villagers as “the cloud”. The application was called TwitterMatic, named after the great god of social networking, Twitter. It would allow digital villagers to tell the latest stories, even when they were asleep or busy working.”

There, a nice fairy tale :-) It should describe the subject of a blog post series that I am starting around the techncal background of TwitterMatic, our contest entry for the new CloudApp(); contest. Now don't forget to vote for us between 10 July and 20 July!

Some usage scenario’s for TwitterMatic:

  • Inform your followers about interesting links at certain times of day
  • Stay present on Twitter during your vacation
  • Maintain presence in your activity stream, even when you are not available
  • Never forget a fellow Twitterer's birthday: schedule it!
  • Trick your boss: of course you are Tweeting you're leaving the office at 8 PM!

Perfect excuses to build our application for the clouds. Now for something more interesting: the technical side!

If you are impatient and immediately want the source code for TwitterMatic, check http://twittermatic.codeplex.com.

kick it on DotNetKicks.com

TwitterMatic architectural overview

Since we’re building a demo application, we thought: why not make use of as much features as possible which Windows Azure has to offer? We’re talking web role, worker role, table storage and queue storage here!

  • The web role will be an application built in ASP.NET MVC, allowing you to schedule new Tweets and view archived scheduled Tweets.
  • The worker role will monitor the table storage for scheduled Tweets. If it’s time to send them, the Tweet will be added to a queue. This queue is then processed by another thread in the worker role, which will publish the Tweet to Twitter.
  • We’ll be using OAuth, delegating authentication for TwitterMatic to Twitter itself. This makes it easier for us: no need to store credentials, no need to maintain a user database, …
  • The web role will perform validation of the domain using data annotations. More on this in one of the next parts.

For people who like images, here’s an architecture image:

TwitterMatic Architecture

What’s next?

RealDolmen Windows Azure The next parts of this series around Windows Azure will be focused on the following topics:

Stay tuned during the coming weeks! And don’t forget to start scheduling Tweets using TwitterMatic.

kick it on DotNetKicks.com