Making development easier with the Remote Plugins Test Service

The Remote Plugins Test Service was created to facilitate manual testing of Remote Plugins in the Desire2Learn Learning Environment and provide a demonstration of different Remote Plugin types. The service supports four types of Remote Plugins: Widgets, Navbar links, Insert Stuff types, and Quicklink types.

The testing service has proven valuable internally at D2L for verifying the functionality of Remote Plugins and providing a basic starting point for creating new Remote Plugins. It was decided that the testing service would be useful to the developer community as sample code and a working project. It is currently hosted on Valence GitHub account. It is licensed under the Apache 2 open source license. It is currently implemented in C# but additional implementations in other languages are in the works.

Four routes are provided for each of the supported remote plugin types: widget, isfselector, nav, and quicklinksselector. Each route expects an LTI Launch (HTTP POST). The index page will render a splash page with a listing of supported Remote Plugin types. The code for each implementation is meant to be straightforward and minimalist. All error handling scenarios may not be covered.

If using the C# implementation, open the solution and start debugging to launch the IIS development server. It will begin running the service on your local machine. If your machine is accessible from your learning environment you can add the service’s routes as Remote Plugins. Use the Remote Plugins administrative page in the learning environment to add new Remote Plugins.

If you’ve got a GitHub account, you can Watch the Remote Plugin Test Service repo to be notified of improvements and additional language implementations for this test service.

So you want to extend your LMS – Part 2: Remote Plugins

Before diving in, be sure to check out Part 1 to review the basics of creating a tool using the Learning Tools Interoperability (LTI) standard.

The Challenge

You want to provide your users with a learning tool. The user experience should be integrated into the Desire2Learn Learning Environment (LE) user interface, the connection between the LE and your tool needs to be secure and enable rich data manipulation, and your tool needs to be hosted separately from the LE to enable ease of maintenance.

The Solution

The remote plugin service provides you with a framework to integrate an LTI-enabled tool into the LE interface, and allows you to extend beyond LTI through the use of the Valence Learning Framework APIs.

The Details

As of LE version 10.3, there are five types of remote plugins – Widget, Course Builder, NavBar, QuickLink, and the Insert Stuff Framework (ISF). You can use these integration points to deliver a learning tool through the appropriate extension point in the LE interface. Your tool can be a straight LTI-enabled tool that uses an LTI Launch to create a secure connection between the LE and the externally hosted resource – whether it be a widget on your own webserver, or a major third-party content-hosting service. Once your tool moves beyond the capabilities of LTI, the Valence LF APIs can automatically take over to provide the extra functionality you need.

The Sample

We’ve created the Course Builder Remote Plugin Sample (edit: link updated), which provides a handy tool to assist an instructor in building course content. To set it up in your environment, download the sample, edit the config.php file to configure it for your environment, and host the tool on a web server. Then create a new remote plugin using the same process described for the BookWidget sample, this time choosing the Course Builder plugin type.

When you deploy a Course Builder Remote Plugin, you add a custom object to the Course Builder toolbox. To use this custom object, drag it into the appropriate place in the content structure for the course you are building. For the Course Builder Remote Plugin sample, this action causes a popup to appear, which contains a list of available content that is served by the Tool Provider. To populate this list, an LTI Launch occurs so that the LMS can connect to the external tool and retrieve the list of links to the externally-hosted content. In this case, the list includes LTI-enabled links to quizzes that the instructor can choose to include in their course – including the WHMIS quiz we viewed in Part 1 of this series.

LTI is great for connecting to an external resource, but in order to add a quiz to the course content, you need to go beyond the capabilities of LTI. In this case, inserting a quiz involves inserting a new link in the course content. When the student clicks that link, a new LTI Launch will occur so that the student can access the externally-hosted quiz in order to complete that assessment and receive a grade. This sample uses the Valence LTI APIs to insert that quiz link into the course content.

Since this tool is being deployed as a remote plugin, Valence authentication can happen automatically using the credentials of the user currently logged in to the LE. When Valence Authentication occurs, the user may be prompted to allow the application to proceed. But beyond that prompt, the user experience is seamless.

As you can see, there are several touch-points where LTI and Valence are being used. Here’s a summary of the workflow for this sample:

  1. INSTRUCTOR: Drag the custom object into the appropriate location in the course structure.
  2. TOOL: Perform an LTI Launch to the Tool Provider to load a list of available content and present it to the instructor in the Course Builder interface.
  3. INSTRUCTOR: Click checkboxes to insert content into the course, such as the WHMIS quiz.
  4. TOOL: Authenticate with Valence using the session for the currently logged in user. If this is the first use of this tool, prompt the user to allow the tool to proceed. Perform Valence calls to create the necessary LTI links for the content and insert them into the course structure.
  5. STUDENT: Click a link in the course to access the WHMIS quiz.
  6. LINK: Perform an LTI Launch to enable the student to access the quiz. Using LTI, send the grade result from the quiz to the grade book for the course.

The Result

This sample is only one example of how a remote plugin can take advantage of both LTI and Valence to extend the user experience for instructors and students. Give it a try in  your own environment. If you have deployed your own tool using a remote plugin, leave a comment describing how your tool helps your end users.

So you want to extend your LMS – Part 1: LTI Primer

The Challenge

You want to create a learning tool that can connect easily and securely to a learning management system. The connection needs to allow for some context-passing from the LMS to your tool so that you can customize the experience based on the unique user, the role of that user (student versus instructor), and the course where they launched the tool (Biology versus Creative Writing). If your tool offers an assessment, you also need a method to pass back grades for each user.

The Solution

The IMS Global Learning Consortium has created a standard called Learning Tools Interoperability (LTI) to address these needs. Basic LTI is the 1.0 version of the standard, and offers context passing from an LMS (known as the tool consumer in the relationship) to the learning tool (known as the tool, which is created by a tool provider). LTI version 1.1 offers the ability to pass back grades information from the tool to the LMS grade book.

The Details

One of the main goals of the LTI Specification is to enable a seamless user experience. So, in a well-implemented LTI tool, the user simply clicks a link or uses a tool embedded in an iframe in the LMS, with little awareness of whether the tool is being served from an external source, or how the tool is being hooked into their LMS, because the process is not obtrusive.

Context-passing from the LMS to the learning tool occurs through the LTI launch. This launch is an HTTP POST that sends a standard set of information to the LTI-enabled learning tool. The data included in a launch is detailed in the LTI Specification. An LTI Launch can look like the following example:

    [launch_presentation_locale] => EN-US__
    [tool_consumer_instance_guid] => 1ed35f2c89ed0exc26we6fw8f50em13a44563a53f
    [tool_consumer_instance_name] => LVU
    [tool_consumer_instance_description] => Lake Valley University
    [tool_consumer_instance_contact_email] => 
    [tool_consumer_info_version] => 10.2.0
    [tool_consumer_info_product_family_code] => desire2learn
    [context_id] => 6609
    [context_title] => Chemistry 100
    [context_label] => C100
    [context_type] => CourseOffering
    [user_id] => 02405492-05f8-495f-b0ad-358e4741768a_169
    [roles] => Student
    [lis_person_name_given] => Bob
    [lis_person_name_family] => McFred
    [lis_person_name_full] => Bob McFred
    [lis_person_contact_email_primary] => 
    [ext_tc_profile_url] => http://localhost:44444/d2l/api/ext/1.0/lti/tcservices
    [resource_link_id] => 1226856900
    [resource_link_title] => WHMIS Quiz
    [resource_link_description] => Level 1 WHMIS Quiz
    [custom_timecreated] => 1371064958 
    [custom_level] => advanced
    [lis_result_sourcedid] => 8d053b33-6f1f-410c-888b-1944226e44d3          
    [lis_outcome_service_url] => http://localhost:44444/d2l/le/lti/Outcome
    [lti_version] => LTI-1p0
    [lti_message_type] => basic-lti-launch-request
    [oauth_version] => 1.0
    [oauth_nonce] => 224535671
    [oauth_timestamp] => 1371064981
    [oauth_signature_method] => HMAC-SHA1
    [oauth_consumer_key] => mykey
    [oauth_callback] => about:blank
    [oauth_signature] => /fjsylvVX435ZnY2D85gmQvDWqU=
    [basiclti_submit] => Launch Endpoint with BasicLTI Data

To take advantage of LTI, the tool must be able to receive this POST and parse the data being sent, ignoring anything it doesn’t require. The tool can then provide a contextually-appropriate experience for each user. For example, the tool can use the information from the [lis_person_name_full] field to greet each user by name. The tool can use the [roles] and [context_title] fields to provide an instructor with a list of quizzes and videos that are appropriate to the subject area of a course, and then present students with the content assigned by the instructor. Your tool can also use information populated in a [custom_xyz] field, which can be used to relay static information that can be customized for each LTI link. In this example, the tool can be customized to use the [custom_level] field to identify students of advanced standing and present them with additional content for enrichment.

To ensure the security of the LTI Launch, you can opt to use OAuth 1.0 to sign messages. This protocol requires that the tool provider and the tool consumer establish a key and secret ahead of time, as part of the configuration of the tool. Notice that any fields in the LTI Launch that pertain to this security method are prefixed by [oauth_]. The tool should parse these fields to ensure that the key and secret are valid before providing a user with access to functionality.

To send back grades once a student has completed an assessment in a learning tool, the tool sends an HTTP POST back to the LMS via the URL specified in the [lis_outcome_service_url] field, the payload being a block of XML that contains the grade details.

<?xml version = "1.0" encoding = "UTF-8"?>
<imsx_POXEnvelopeRequest xmlns = "">

We can see that the <sourcedId> value matches the value from the [lis_result_sourcedid] field that was sent as part of the initial LTI Launch. This value is a GUID identifying the gradable object in the LMS. The grade is sent as a decimal value in a <textString>, which is used to update the LMS grade book.

The Sample

To help you get started building your own LTI-enabled tool, we’ve created the LTI Quiz Sample (edit: link updated). This sample uses LTI to enable students to complete an externally-hosted quiz and then sends the final grade back to the course grade book, using similar values for the LTI Launch and the Grades Return that we outlined above. You can download the LTI Quiz Sample (edit: link updated) from our GitHub repository.

To get this sample working in your own environment, you’ll need to run it on a webserver that is accessible from your LMS. (Edit: View the file for full details on how to configure the sample on your webserver.) To implement an LTI-enabled tool in the Desire2Learn Learning Environment, review the following whitepaper: Does Desire2Learn Learning Environment Integrate With..? (Edit: Link updated.) This whitepaper also goes into more detail about the values sent in an LTI Launch.

The Result

Using LTI, we have created an external tool that provides value to instructors and students while also enabling a seamless user experience.

Stay tuned for Part 2 of this post, where we’ll talk about how to integrate your LTI tools into the user interface of the Desire2Learn Learning Environment using Remote Plugins, and how to extend the experience even further using the Valence Learning Framework APIs.

Revisiting the BookList sample with RestSharp

Many of you are already familiar with the BookWidget sample. We’ve updated that sample to show some best practices for using the C# Valence SDK and creating a Remote Plugin Widget. The sample is available on GitHub for download (edit: link updated). It uses Microsoft’s ASP.NET web framework as the basis for the project. Several additional libraries are also used which are described below.

Know Your Platform

It’s important when using any language to be informed about the library options available. There are several excellent libraries available for C# that help relieve some of the tedious work of creating your own OAuth authentication library and handling RESTful HTTP requests.

The sample project makes use of RestSharp for handling Valence requests. Because Valence is a RESTful API, all communication is handled over HTTP. RestSharp makes the process of creating these requests less tedious and, in addition, exposes interfaces that can be used for unit testing.

LTI launch requests can optionally be signed using OAuth 1.0. There are several existing OAuth libraries available for C#; a good option is DevDefined.OAuth. The sample we’ve created makes use of this library to verify the OAuth signature on the LTI launch request.

All of these libraries are available via nuget which is integrated with Visual Studio. You can make use of the package manager built into Visual Studio to easily add packages as dependencies to your project.

There is now an additional Valence SDK package available from nuget that integrates with RestSharp. D2L.Extensibility.AuthSdk.Restsharp implements the IAuthenticator interface provided by RestSharp. You simply supply your ID2LUsercontext to the ValenceAuthenticator class to create an IAuthenticator object. This object is then passed to a RestSharp client object to handle all authentication. You can see how this is handled in the sample project.

Features of the Sample

This sample makes use of the Valence Content APIs to retrieve the list of assigned books from a course the user is enrolled in. After retrieving the list of ISBNs from the the LMS it fetches additional information about the books from the Google Books API. The final view is a grid of book cover thumbnails to show the user which textbooks have been assigned.

The sample makes use of the LTI role field and only allows those with the ‘instructor’ role to add and remove textbooks from the course. All of this functionality is implemented using the existing Valence Content APIs.

Pay attention to the BookController.cs file. It contains a POST handler that takes care of extracting parameters from the LTI launch and verifying the OAuth signature. It also takes care of the initial Valence authentication so that the project can make use of the Valence Content APIs.

Digging deeper you’ll notice the Course.cs file under the models folder. This contains the Valence calls to the LMS implemented using RestSharp. You’ll also notice the project has wrapped up the Google Book API calls and adapts the result to pass to the Razor templates that have been constructed.

Final Thoughts

We hope this project gives a good starting point for working with Valence and creating remote plugins using our C# SDK. The sample is licensed under the Apache 2 License. Feel free to check it out on Github and adapt it for your own purposes.

Diving into Valence with the Course Search sample

The Challenge

Getting your hands dirty with an API can be a daunting task. Where do you start? Experience is a great teacher, but how do you come up with a project that will provide a useful learning experience with real-world application?

The Solution

The Course Search sample provides you with a chance to explore a basic project, and opportunities to dive into the Valence Learning Framework APIs to get the widget running in your environment and extend the base functionality. This sample is a great first project for a developer who is new to the Valence platform. It is also a useful exercise for experienced developers who want to tackle an area of the Learning Framework API they might not have investigated before.

The Course Search sample is a remote plugin. As we saw with the Book Widget sample, remote plugins are easy to deploy. This widget is designed to compile a list of courses and allow users to filter the list by Semester and Department to find a specific course. You can try the online demo of this sample to get a feel for the basic functionality.

The Details

Before the widget can execute searches within your environment, you must complete some configuration. The necessary values are unlikely to change for an organization, so we make them constants for performance reasons. To perform the configuration, copy config.php.sample to config.php and change the values accordingly.

As with any application, the Course Search sample requires an App ID/Key pair and an appropriate User ID/Key pair in order to make calls against your LMS. To provide the application with the appropriate level of access, you must configure it to run under a service account with administrator privileges. By performing these configurations, you have an opportunity to work through the key request process and develop a stronger understanding of the authentication model.

  1. Follow the steps outlined in the App ID/Key pair topic to request a Limited App ID\Key pair for the environment where you will be deploying the Course Search widget. Once approved, the App ID\Key pair will be active in the environment within 24 hours.
  2. In config.php, set  appId and appKey to the values for the App ID\Key pair you receive.
  3. In the Getting Started Sample, update the appropriate fields to point to your LMS and use your App ID/Key pair.
  4. Click authenticate. You will be redirected to authenticate against your LMS. Enter credentials for the service account you configured to run this sample.
  5. When you are redirected back to the Getting Started Sample, note the User ID and User Key values.
  6. In config.php, set  userId and userKey to the values returned by the authentication process.

For the variables outlined below, you’ll need to manually run some API calls to retrieve the appropriate values. As you did above, you can point the Getting Started Sample to your own LMS and then run the necessary API calls.

  1. Set rootOrg to the identifier property returned by GET /d2l/api/lp/1.0/organization/info (See organization info API documentation.)
  2. Set deptOrgType to the Id property returned by GET /d2l/api/lp/1.0/outypes/department (See department API documentation.)
  3. Set semesterOrgType to the Id property returned by GET /d2l/api/lp/1.0/outypes/semester (See semester API documentation.)

If you would like to run the Course Search widget for multiple LMSes, there is an opportunity to extend this sample by creating a more elaborate way to fetch and store these variables across multiple environments.

The Course Search widget uses the Organization Structure Learning Framework APIs to repeatedly walk down the organization structure to compile a list of courses. First, the widget performs a GET to retrieve the list of semesters. Then the widget performs a GET to retrieve a list of departments. You can see how this is done within the index.php file. These values are presented to the user as lists used to filter the courses.

Choosing an option from the list of departments

Choosing an option from the list of departments.

Retrieving the list of courses is a three-stage process in the dept.php file. First, the widget performs a GET to retrieve the available course templates for the department that the user selected using the widget. Course templates are org units that link a course offering to a department. Course templates allow you to configure, store and reuse components of a course, such as quizzes, dropbox folders, and surveys, and then use the components in individual course offerings. For each template, the widget performs another GET to retrieve all of the courses that match the template. Finally, the widget performs a GET to retrieve all offerings for each course. These values are presented to the user in a drop-down list of available courses.

Choosing an option from the list of course offerings.

Choosing an option from the list of course offerings.

Once the user selects a specific course, the user interface displays a Submit button. This button provides an opportunity to extend the sample, as there is currently no functionality attached to it. Perhaps it could be used to copy the data to the clipboard so that the user can paste the information into the school’s enrollment system. There is a wide range of possibilities. Be sure to share your ideas for extending this sample in the comments.

The Sample

To use the Course Search widget in your own environment, you need to deploy it as a Remote Plugin.

  1. Download the current version of the Course Search sample. The sample requires PHP installed on the server where it is running.
  2. Log in to the Learning Environment as an administrator.
  3. Click on the Admin Tools icon and click Remote Plugins.
  4. Click on the New Remote Plugin button and fill out the Launch Point and Name. In this example, the Launch Point is the URL of the running instance of the Course Search sample.
  5. Change the Plugin Type dropdown to Widget.
  6. Add the Org Units that will have permission to run the Course Search widget by clicking the Add Org Units button.
  7. Click Save.

The Result

The Course Search sample is a development exercise that exposes you to key facets of the Valence platform – from application keys & authentication, to retrieving data, to deploying a remote plugin in the LMS. If you experimented with deploying and extending this sample, share your experience in the comments.

Remote plugins & the BookWidget sample

The Challenge

A Desire2Learn Learning Environment administrator can install applications to offer greater functionality or streamline common processes for their users. However, there is some overhead involved in performing software updates to install these applications on the Learning Management System. Logically, reducing this installation overhead can reduce a barrier to adoption of an application.

The Solution

A remote plugin (Note: Link updated to expanded documentation on Remote Plugin Service.) can extend the functionality of the LMS without requiring additional software. The remote plugin object has a rich content connection with the LMS, and provides UI elements that the developer can control. Using the BookWidget as an example, we will introduce some of the functionality that is possible through remote plugins and demonstrate the ease of building and deploying them.

The BookWidget is designed to allow an instructor to select textbooks to associate with their courses. Instructors can search by ISBN, title, or author to locate textbooks, and add or remove textbooks for each course they manage.

An instructor adds books by searching for the ISBN, author, or title.

An instructor adds books by searching for the ISBN, author, or title.

Students are presented with a user-friendly interface to determine which textbooks they need to acquire, including a thumbnail of the cover, and key information such as title and author. Where applicable, the BookWidget also provides students with a link to purchase textbooks from online retailers.

A student views thumbnails of textbooks listed for a course.

A student views thumbnails of textbooks listed for a course.

The Details

Remote plugin widgets are hosted separately from the LMS, which allows them to be enabled without performing software updates to the LMS. They take advantage of the Learning Tools Interoperability (LTI) specification to connect to the LMS. Once connected, the Valence Learning Framework APIs take over to provide interactivity with the LMS. The BookWidget sample is a VisualStudio 2010 project, which is available to download from our public code repository (Note: Moved to GitHub).

A remote plugin widget loads within an iframe embedded in a course homepage. When a student or instructor loads a page that  contains a remote plugin widget, the widget issues an LTI launch request, which results in a POST to the URL configured as the target for the remote plugin widget. The POST contains a set of fields described in the LTI documentation. Once the widget extracts these fields from the POST data, it generates the application context to create the appropriate LTI authorization parameters. The LTI authentication takes place using OAuth, which uses a shared key and secret between the remote plugin and the widget code. The widget then redirects to the generated authentication URL. After authentication is completed, the widget reloads at its launch URL.

Once the LTI launch is complete, the remote plugin widget uses the Learning Framework APIs to perform actions against the LMS. For the BookWidget, this includes retrieving and manipulating information related to the books assigned to a particular course. The BookWidget uses an HTTP POST to the appropriate route to associate a book with a course. It uses an HTTP DELETE to remove a book from a course. And it uses an HTTP GET to retrieve the list of associated books for a course. When we developed the BookWidget, we identified the Learning Framework APIs we needed and then tested them interactively to ensure they behaved as we expected. We performed this interactive testing using the Getting Started Sample. Then we built those routes into the BookWidget application.

Because a remote plugin is hosted separately from the LMS, it does not inherit the look and feel of the course homepage. It is not yet possible to retrieve LMS CSS information using the APIs, so the BookWidget uses a simple design with minimal embellishments to allow it to blend in with the LMS styles. The sample was built using Bootstrap to help make styling easier.

The Sample

Setting up the BookWidget in your own environment demonstrates how easy it is to deploy a remote plugin.

  1. Download the current version of the BookWidget sample (edit: link updated). The sample requires Visual Studio 2010.
  2. Log in to the Learning Environment as an administrator.
  3. Click on the Admin Tools icon and click Remote Plugins.
  4. Click on the New Remote Plugin button and fill out the Launch Point and Name. In this example, the Launch Point is the URL of the running instance of the BookWidget. If running the sample from Visual Studio it will likely be “http://localhost:6371/books“.
  5. Change the Plugin Type dropdown to Widget.
  6. Add the Org Units that will have permission to run the BookWidget by clicking the Add Org Units button.
  7. Click Save.

Once the BookWidget is configured, an instructor can add it to their course homepage and start using it.

The BookWidget on a course homepage.

The BookWidget on a course homepage.

The Result

As we’ve demonstrated, a remote plugin provides LMS users with additional functionality without the overhead of software updates. The BookWidget sample demonstrates how a remote plugin can use LTI and the Learning Framework APIs to offer a rich user experience.

Try the BookWidget sample in your own environment. Share your experience implementing and extending this sample in the comments. If you create your own remote plugins, be sure to let us know. We’d love to feature your work in a future blog post!

Note: This sample has been updated. See the post “Revisiting the BookList sample with RestSharp” for details.

Real World Application

I was happy when I received some recent requests from a developer about Grade Export apps using Valence to be able to reconnect to Chris at BJU.  I knew Chris had previously worked on a Grades Export app and had worked through most of the items people would likely encounter. He helped us out by sharing his real world experience of creating an app with the developer working on a similar problem, which was great, but Chris has also graciously allowed me to share a slightly edited version of his email so you will see a summary of his experiences.

If you are working on  an app like this or just getting started with Valence check out Chris’s approach below.

Chris says:

First of all, be sure to become familiar with the Valence web site  There is a ton of information out there.

Within that web site, especially note the following.  I would add these links to your browser toolbar or add them as favorites. and talks about the authentication process is the jumping off point for the specific docs on each section of the API, including users, courses, grades, etc. and is the specific page on the API calls for grades. is where you go to sign in and request a key (app ID and app key).  You will probably want a key for testing purposes and a separate key for production purposes. is where the Java code / library is found.  You will definitely want this—it will save you a whole lot of time and effort.

Specifically within the ZIP file above, you want the lib/lmsapi.jar library to be included in your Java project.  That library is worth its proverbial weight in gold.  In my code I did not have to do any hard work to manage the authentication (which is pretty complex stuff with all the keys and encryption) — this library handles all of that for you.

Now for a quick overview of how the interaction between our SIS (Student Information System) and D2L happens.  There is a lot of back-and-forth that has to happen before you can request grade information from D2L.

1.       The user enters grades in D2L.  We have enabled a link on the D2L page where grades are entered for each particular class (see below for details on this).  The link calls a particular page on our SIS, passing the orgUnitId of the course that the user is entering grades for.

2.       When that SIS page comes up, it requires the faculty member to login to our SIS (if he is not already logged in).  Then it saves the orgUnitId of the course from the link for future references, and begins the authentication process with D2L by means of an initial REST API call to D2L.

3.       As part of the authentication process, D2L displays a page to the user asking for his permission to share D2L data with our SIS.  The user must grant that permission in order for the process to continue.  The user is offered a checkbox to give permanent permission so that the page is not displayed in the future if he wishes.

4.       Then the D2L page returns to our SIS, passing additional parameters that are needed for future REST API calls.  Back in the SIS, we retrieve the orgUnitID which was passed in the very first call from D2L to our SIS, and look that up in our database to see which course the faculty member is working on, and display the name of that course to the faculty member to confirm that he has the right course.  Since we use the D2L Holding Tank to synchronize our course data (among other things) with D2L, we have that information in our database.

5.       The faculty member is offered two buttons on that page:  one that will get the grades from D2L and display them only, without posting them to the SIS, and a second button that will both display and post them to the SIS.

6.       When the user clicks one of those buttons, we initiate a series of REST API calls to D2L that get the class roster (from D2L) and then iterate through the roster and get a grade for each student.  As we go, we also compare that D2L roster with the roster in our SIS and let the user know of any discrepancies (for example, a student might have recently dropped or added the class, and maybe the SIS knows that before D2L does).  Depending on which button the user clicked in step 5, we either display the grades and give the user a second chance to post them to the SIS, or else we display and post the grades, along with any messages about discrepancies between the class roster in D2L and the class roster in our SIS.

General note: in our particular case, we group all the sections of a course together that are taught by the same teacher.  So for example, if a teacher has sections 1, 3, and 4 of En 101 (English Composition), we would grab all the grades for those three sections at once rather than one section at a time.  That is because of the way we synchronize our course and section data through the D2L Holding Tank.  You may choose to handle each section separately—it’s up to you.

Now for the details:

In order to enable the link on the D2L Enter Grades pages of each course, we set the following:

Within D2L, in the DOME, there is a setting at the following location “Tools.Grades.ExportHandlerPage”  and we set this to point at a particular page within our SIS.

The setting will look something like this: https://<SIS Name>/{orgUnitId}

As you may have noted, the SIS controller has to be called multiple times, with a different set of parameters each time.  So it has to pay attention to those parameters and behave accordingly.

Within our SIS controller, we have the following basic outline:

1.       Validation that the user is a faculty member or part of the Records Office.

2.       Look for certain parameters that are being passed in.  Depending on what is passed in, we can tell whether this is the first time in, or the second time, or the third or more time in.

A.      ou parameter (orgUnitID).  If it exists, that means we are here for the first time and we need to save that piece of information in the session for future reference.  If it does not exist, then we are here for the second or subsequent time and we need to get this piece of information from the session variable that we stored before.

B.   x_a, x_b, and x_c:  if these are set, then it means we are being called the second time, and that D2L has verified our authentication and is ready now for us to make calls to get class and grade information.  We will store these parameters in session variables because we will need them later.  If these are not set, then we will get them from the session variables.

C.   If the parameters getGrades or reviewOnly are present (coming from the two buttons previously mentioned), it means we are in the third (or more) time through.

3.   If this is the first time through, begin the authentication process with D2L

4.   If this is the second time through, save the authentication parameters and show the user the course name, along with buttons for getting and posting grade information.

5.   If this is the third (or more) time through, then we are getting grade information from D2L and displaying it (and potentially posting it to our SIS).

We are using the Spring libraries, in a standard MVC environment.  To work with JSON, we are also using the JSON objects from  In order to do the GET, we are using a function based on

Thanks very much to Chris for sharing this.


Get every new post delivered to your Inbox.

Join 40 other followers