The Launch Action

In my last post I mentioned that I had just posted a sample LTI Consumer app on CodePlex. Consumer is an ASP.NET MVC 4.5 app (it also uses Entity Framework 5, jQuery, jQuery UI, Chosen, tiny-mce, and qtip). Most of the app is devoted to user and assignment management.

Users have a user profile in which they can select their U.S. state, school district, and school (did I mention that I am K-12 centric?), and set some privacy choices which will come in handy.

Assignments are web links with some additional meta-data including a key and secret used for OAuth signing, and a sharing scope so that users only see the assignments they should see.

If you are here because you want to see a real LTI request being built, then you are in luck because that is what the rest of this post is about. The LTI specification basically says:

LTI Essentials

  • Learning systems (consumers and providers) should use HTTP or HTTPS to talk to each other.
  • Requests should use the POST method.
  • The form-data must include some name/value pairs that identify the request as as LTI request, specify the context (e.g. who is sending the request, what course are they in, and what their role is in the course).
  • The request should also say what the requester wants…launch a tool, display a document, start a game, etc. This can be in the URL (my preference), a combination of the URL and form-data, or just in the form-data (my least favorite). Note that the tool provider gets to choose. The tool consumer should to be flexible enough to work with any provider.
  • And finally, the request must be signed using an OAuth signature.

In the sample Consumer app, when a user clicks on the Launch button next to each assignment, they invoke the Launch action in the AssignmentController. The controller calculates all the form-data fields needed to launch the tool or content and then loads the Launch view.

        //
        // GET: /Assignment/Launch/5

        public ActionResult Launch(int id = 0)
        {
            Assignment assignment = db.Assignments.Find(id);
            if (assignment == null)
            {
                return HttpNotFound();
            }
        
            // Public assignments are displayed on the front page even if the
            // user is not logged in. If the user is anonymous or if the 
            // assignment does not have an LTI key and secret defined, then
            // the Launch reverts to a simple redirect (GET). I'm curious to
            // see how providers handle this.

            if (Request.IsAuthenticated && assignment.IsLtiLink)
            {
                BuildLtiRequestViewBag(assignment);
                return View(assignment);
            }

            // If the user is not logged in or the assignment does not have an LTI
            // key and secret, then treat the launch as a simple link.
            return Redirect(assignment.Url);
        }

The Launch view builds a simple form which is displayed in the browser and automatically submitted it to the provider.

@model Consumer.Models.Assignment

@{
    ViewBag.Title = Model.Name;
    Layout = "~/Views/Shared/_LayoutEmpty.cshtml";
}

@*
The AssignmentController calculated all the form data, and even the
form action. All this view needs to do is create the form and ask
the browser to submit it.
*@
@<form id="form" action="@ViewBag.Action" method="post">
    @foreach (var name in ViewBag.NameValues.AllKeys)
    {
        <input type="hidden" name="@name" value="@ViewBag.NameValues[name]" />
    }
    <input type="hidden" name="oauth_signature" value="@ViewBag.Signature" />
</form>

@section Scripts {
<script>
    $(function () {
        $("#form").submit();
    });
</script>
}

Which results in a page like this which submits itself automatically.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>IMS Test Tool - LTI Tool Consumer</title>
        <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon" />
        <meta name="viewport" content="width=device-width" />
    </head>
    <body>
        


<form id="form" action="http://www.imsglobal.org/developers/LTI/test/v1p1/tool.php" method="post">
        <input type="hidden" name="oauth_callback" value="about:blank" />
        <input type="hidden" name="oauth_consumer_key" value="12345" />
        <input type="hidden" name="oauth_nonce" value="40fa050d9363433785edfb19fc01f240" />
        <input type="hidden" name="oauth_signature_method" value="HMAC-SHA1" />
        <input type="hidden" name="oauth_timestamp" value="1352044832" />
        <input type="hidden" name="oauth_version" value="1.0" />
        <input type="hidden" name="lti_message_type" value="basic-lti-launch-request" />
        <input type="hidden" name="lti_version" value="LTI-1p0" />
        <input type="hidden" name="resource_link_id" value="1-1" />
        <input type="hidden" name="resource_link_title" value="IMS Test Tool" />
        <input type="hidden" name="tool_consumer_instance_name" value="LTI Consumer Sample" />
        <input type="hidden" name="tool_consumer_instance_guid" value="/" />
        <input type="hidden" name="context_id" value="1" />
        <input type="hidden" name="context_label" value="Andy Miller" />
        <input type="hidden" name="context_title" value="Andy Miller's Class" />
        <input type="hidden" name="context_type" value="CourseSection" />
        <input type="hidden" name="user_id" value="teacher" />
        <input type="hidden" name="roles" value="Instructor" />
        <input type="hidden" name="lis_person_name_family" value="Miller" />
        <input type="hidden" name="lis_person_name_given" value="Andy" />
        <input type="hidden" name="launch_presentation_locale" value="en-US" />
        <input type="hidden" name="custom_state_id" value="OR" />
        <input type="hidden" name="custom_district_id" value="00000000002243" />
        <input type="hidden" name="custom_school_id" value="00000000000000001320" />
        <input type="hidden" name="lis_outcome_service_url" value="http://localhost:54641/Assignment/Outcome" />
        <input type="hidden" name="lis_result_sourcedid" value="1" />
    <input type="hidden" name="oauth_signature" value="4t3Mtpe5tvh4W06KsGyGlGlrZ7c=" />
</form>



        <script src="/Scripts/jquery-1.8.2.js"></script>

        
<script>
    $(function () {
        $("#form").submit();
    });
</script>

    </body>
</html>
This entry was posted in Uncategorized and tagged , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.