Integrating C# app with Moodle 2


Moodle 2 exposes the same service methods using several protocols like XML-RPC, AMF and SOAP. In this post we’ll use XML-RPC, other protocols will be a subject of future posts. The examples below use existing Moodle 2 services. These are very few but I believe the Moodle 2 team will add more as time comes. In some future post I will discuss how you can add or extend such services.

Configure web services

To expose web service methods for Moodle 2 use the following documentation: https://docs.moodle.org/dev/Web_services. Since this documentation is sparse, we’ll list the basic steps required to configure a user that can access existing web service methods.

  1. Add a new Moodle user – we’ll assume this user will only access web service methods. Login as the Moodle admin and go to Site administration → Users → Accounts → Add a new user. Create a user with username wsuser and with the password Wsuser!23 (or any other username and password combination you please).
  2. Define a role that can be assigned to wsuser. Roles are how capabilities are assigned to users. Go to Site administration → Users → Permissions → Define roles. Add a new role. Call the role WebService. Assign the role to the Context type System (just tick the check box System).  Then, assign the following capabilities to the role:
    • webservice/xmlrpc:use
    • moodle/course:view
    • moodle/course:update
    • moodle/course:viewhiddencourses
    • moodle/user:viewdetails
  3. Assign the WebService role with all its associated capabilities to wsuser. Go to Site administration → Users → Permissions → Assign system roles. Select the WebService role. Assign wsuser to the role.
  4. Enable web services-  if they are already enabled skip this step. Go to Site administration → Advanced features. Tick the “Enable web services” check box. Save changes.
  5. Enable the xml-rpc protocol at Site administration → Plugins → Web services → Manage protocols.
  6. Create a new external service – Go to  Site administration → Plugins → Web services → External services. Add a new web service. Set the name to test, tick Enabled check box, and tick the “Authorised  user only” check box.
  7. Add the following functions to web service test:
    • moodle_course_get_courses
  8. Add user wsuser as authorized user of web service test. If the user has any capabilities missing, you will be prompted about missing capabilities. Add these capabilities as shown in step 2.

Create C# App

We’ll create an interface for the XMLRPC.net framework. Here’s the interface:

public interface IMoodle : IXmlRpcProxy
{
[XmlRpcMethod("moodle_user_get_users_by_id")]
  object[] GetUserById(object[] id);
[XmlRpcMethod("moodle_course_get_courses")]
  object[] GetCourses();
}

Next, we call a method on this interface:

IMoodle moodleProxy;
moodleProxy = XmlRpcProxyGen.Create<IMoodle>();
moodleProxy.Url = "http://host/moodle/webservice/xmlrpc/simpleserver.php?wsusername=wsuser&wspassword=Wsuser!23";
object [] a = moodleProxy.GetCourses(); // returns an array of Hashtable

In the example above we recover a list of courses, the method GetCourses returns an array of Hashtable. Each hash table contains attributes of a course object. These are key value pairs that can be printed out using a simple method such as:

private string ConvertToString(object[] a)
{
  string ret = string.Empty;
  if (a.Count() <= 0 || !(a[0] is XmlRpcStruct) || !(a[0] is Hashtable))
  {
    return ret;
  }
  for (int i = 0; i < a.Count(); i++)
  {
    Hashtable h = (Hashtable)a[i];
    IDictionaryEnumerator e = (IDictionaryEnumerator)h.GetEnumerator();
    while (e.MoveNext())
    {
      ret += e.Key + "=" + e.Value + ",";
    }
    ret += ";";
  }
  return ret;
}

Here’s a sample output from this method:

timecreated=1282062417,summary=This is a test course,showreports=0,shortname=CF101,
format=weeks,id=2,categorysortorder=100,enablecompletion=0,forcetheme=,showgrades=1,
startdate=1282100400,summaryformat=1,newsitems=5,idnumber=,maxbytes=2097152,numsections=10,
groupmodeforce=0,lang=,completionnotify=0,categoryid=1,hiddensections=0,
timemodified=1282062417,completionstartonenrol=0,defaultgroupingid=0,
fullname=Course Fullname 101,visible=1,groupmode=0,;

Next, we’ll see how we can recover a list of courses where each course is represented by an object.

Returning objects

Parameters and return values can be of a specific type. A Moodle course object can be represented by a struct such as:

public struct Course
{
  public int id;
  public string shortname;
  public int categoryid;
  public int categorysortorder;
  public string fullname;
  public string idnumber;
  public string summary;
  public int summaryformat;
  public string format;
  public int showgrades;
  public int newsitems;
  public int startdate;
  public int numsections;
  public int maxbytes;
  public int showreports;
  public int visible;
  public int hiddensections;
  public int groupmode;
  public int groupmodeforce;
  public int defaultgroupingid;
  public int timecreated;
  public int timemodified;
  public int enablecompletion;
  public int completionstartonenrol;
  public int completionnotify;
  public string lang;
  public string forcetheme;
  public override string ToString()
  {
    string ret = string.Empty;
    FieldInfo [] attribs = this.GetType().GetFields();
    foreach (FieldInfo attrib in attribs)
    {
      ret += attrib.Name + "=" + attrib.GetValue(this) + ",";
    }
    return ret;
  }
}

To return an array of Course objects, modify the GetCourses method in the IMoodle interface:

[XmlRpcMethod("moodle_course_get_courses")]
Course[] GetCourses();

Now, instead of a generic hash table for each object, we get a proper  Course object.

Authenticating using tokens

Tokens are hard to decipher values that can be used for authentication instead of username and password. Go to Site administration → Plugins → Web services → Manage tokens. Add a token for service test and user wsuser. This token can then be used in the url of the XML-RPC proxy:

moodleProxy.Url = "http://192.168.2.1/moodle/webservice/xmlrpc/server.php?wstoken=7ab3284ee0b534b039728c0e945d9c71";
Advertisements

Integrating a C# app with Moodle using XML-RPC


We’ll make RPC calls to Moodle using MNet using a simple example. Our objective is to check if a user name / password combination is valid using the email auth plugin.

What we need

We’ll be using the following tools in this post:

  • A C# compiler, or the free Visual C# Express IDE

  • An XML-RPC library, the one we’ll use can be obtained at http://www.xml-rpc.net/

  • SQL Server 2008 Express database

  • Moodle installation (using 1.9.9+) using an external database (we use SQL Server 2008 Express)

Enable MNet networking in Moodle

Use the admin page to enable MNet networking. Instructions to do so are provided in the Moodle Docs at https://docs.moodle.org/32/en/MNet.

Add Trusted Hosts

Add the IP address from where you’ll make the calls, to the list of trusted hosts. You then don’t need to use encryption in XML-RPC calls, but don’t use this over a public network. On the site administration page navigate to Networking, XML-RPC hosts.

Publish methods through MNet

Modify the auth email plugin located at auth\email\auth.php, to publish its methods through MNet.

/**
* Provides the allowed RPC services from this class as an array.
*
* @return array Allowed RPC services.
*/
function mnet_publishes() {
  $servicelist = array();

  $service['name'] = 'auth';
  $service['apiversion'] = 1;
  $service['methods'] = array('user_login');
  $servicelist[] = $service;

  return $servicelist;
}

Add RPC calls to the Moodle database

Update MNet service database tables to allow RPC calls. Run the following SQL statements using SQL Server Management Studio. If you use any other database, you may need to tweak the SQL syntax a bit.

SET IDENTITY_INSERT [moodle].[dbo].[mdl_mnet_rpc] ON
GO
INSERT INTO [moodle].[dbo].[mdl_mnet_rpc]
(id,[function_name],[xmlrpc_path],[parent_type],[parent],[enabled],[help],[profile])
VALUES
(15,'user_login','auth/email/auth.php/user_login','email','auth',1,'','')
GO
SET IDENTITY_INSERT [moodle].[dbo].[mdl_mnet_rpc] OFF
GO
SET IDENTITY_INSERT [moodle].[dbo].[mdl_mnet_service] ON
GO
INSERT INTO [moodle].[dbo].[mdl_mnet_service]
(id,[name],[description],[apiversion],[offer])
VALUES
(4,'auth','auth','1',1)
GO
SET IDENTITY_INSERT [moodle].[dbo].[mdl_mnet_service] OFF
GO
SET IDENTITY_INSERT [moodle].[dbo].[mdl_mnet_service2rpc] ON
GO
INSERT INTO [moodle].[dbo].[mdl_mnet_service2rpc]
(id,[serviceid],[rpcid])
VALUES
(15,4,15)
GO
SET IDENTITY_INSERT [moodle].[dbo].[mdl_mnet_service2rpc] OFF
GO
INSERT INTO [moodle].[dbo].[mdl_mnet_host2service]
([hostid],[serviceid],[publish],[subscribe])
VALUES
(0,4,1,1)
GO

Create C# app

The following code sample shows how you can use XML-RPC to call the method user_login. First, we need to create an interface that will be implemented by the xmlrpc.net framework.

public interface IMoodle : IXmlRpcProxy
{
  [XmlRpcMethod("system/listMethods")]
  string [] ListMethods();
  [XmlRpcMethod("auth/email/auth.php/user_login")]
  bool Login(string user, string password);
}

Next, we create a proxy for the interface, set the service URL and call the method.

private IMoodle moodleProxy;
moodleProxy = XmlRpcProxyGen.Create<IMoodle>();
moodleProxy.Url = "http://192.168.2.1/moodle/mnet/xmlrpc/server.php";
bool result = moodleProxy.Login("dkt", "pwd"); // returns true if successful or else false

Add IIS Smooth Streaming support to Moodle’s Multimedia Plugins Filter


We use the Smooth Streaming Player provided by the Silverlight Media Framework project at https://smf.codeplex.com/.

Download and unzip the contents of smooth streaming player binaries to the filter\mediaplugin folder of your Moodle installation.

Modify filter.php in the same folder. Add the following lines to the function called filter, at the appropriate location.

if ($CFG->filter_mediaplugin_enable_ism) {
  $search = '/<a.*?href="([^<]+\.ism\/Manifest)"[^>]*>.*?<\/a>/is';
  $newtext = preg_replace_callback($search, 'mediaplugin_filter_ism_callback', $newtext);
}
if ($CFG->filter_mediaplugin_enable_ism) {
  $search = '/<a.*?href="([^<]+\.isml\/Manifest)"[^>]*>.*?<\/a>/is';
  $newtext = preg_replace_callback($search, 'mediaplugin_filter_ism_callback', $newtext);
}

To the same file add the following function.

function mediaplugin_filter_ism_callback($link, $autostart=false) {
  global $CFG;
  $url = $link[1];
  if (empty($link[3]) or empty($link[4])) {
    $mpsize = '';
    $size = 'width="600" height="400"';
    $autosize = 'true';
  } else {
    $size = 'width="'.$link[3].'" height="'.$link[4].'"';
    $mpsize = $size;
    $autosize = 'false';
  }
  $mimetype = mimeinfo('type', $url);
  $autostart = $autostart ? 'true' : 'false';
  return $link[0].
'<span>
<!--object data="data:application/x-silverlight-2," type="application/x-silverlight-2" '.$size.'>
<param name="source" value="'.$CFG->wwwroot.'/filter/mediaplugin/SmoothStreamingPlayer.xap"/>
<param name="background" value="white" />
<param name="minRuntimeVersion" value="4.0.50401.0" />
<param name="autoUpgrade" value="true" />
<param name="InitParams" value="selectedcaptionstream=textstream_eng,mediaurl='.$url.'" />
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50401.0" style="text-decoration:none">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>
</a>
</object-->
</span>';
}

Modify filtersettings.php in the same folder. Add the following line at the appropriate location.

$settings->add(new admin_setting_configcheckbox('filter_mediaplugin_enable_ism', get_string('mediapluginism','admin'), '', 1));

Finally, we need to add a string resource used by the settings page of the plugin. Edit lang\en_utf8\admin.php (or the appropriate language file) and add the following:

$string['mediapluginism'] = 'Enable .ism (IIS Smooth Streaming) filter';

Here’s a screenshot of the filter in action.

A URL to a smooth stream, live or on demand, does not just end with .isml or .ism, you have to add a /Manifest after that. Without this the filter will not recognize the URL as a smooth stream.

This has been tested with the latest Moodle weekly build 1.9.9+ but should be easy to adapt for version 2.

If you encounter any issue with the Smooth Streaming Player, try to get a newer version from the project site, or report the issue to them. If you have any other suggestion, please leave a comment.

Happy smooth streaming!