Use API in C#

Use API in C#

by Penyo Rusev -
Number of replies: 25

Hello! I need to use Moodle's API in my C# project, but I don't know how to call Moodle's Methods. Can you help me?

Average of ratings: -
In reply to Penyo Rusev

Re: Use API in C#

by Bill Antonia -

Probably not what you want to hear, as far as I know there is no wsdl currently which describes the functions etc to call a Moodle server. I have recently been looking at trying to create one, in a round about way but so far no luck. So you would have to write your own calls, either to send SOAP messages or use REST protocols.

However as a fallback, I know it is not ideal and someone may have a better method, is to create a number of webservices in Java running on a Glassfish server which in turn calls the Java REST library I've written which actually does the call to the Moodle site. As I said, not ideal, but one advantage is a wsdl can be created for the Glassfish webservices which in turn can be used for clients written in other programming languages. I've been ruminating on this idea as another project and wondering if this might be helpful for someone.

In reply to Bill Antonia

Re: Use API in C#

by Penyo Rusev -

Thanks for fast support!
Can I see your Java's solution?

And I have other problem. When I create my own Service in Moodle, I can't call him. I tried with this "https://www.yourmoodle.com/login/token.php?username=USERNAME&password=PASSWORD&service=SERVICESHORTNAME" to call him token but the answer was '{"error":"Web service is not available (it doesn't exist or might be disabled)" ,"stacktrace":null,"debuginfo":null,"reproductionlink":null}'
Also, tried http://www.yourmoodle.com/webservice/rest/server.php?wstoken=66a62ad146c76bea8e6216c1385eec0f&wsfunction=core_files_get_files

But no result...
How to call my service?
Thanks!

In reply to Penyo Rusev

Re: Use API in C#

by Bill Antonia -

Hi Penyo,

I've no idea currently how to set up a call in C#, although I'm learning, but looking at your last part of your code it looks close to what I do in my library.

http://www.yourmoodle.com/moodlepath/webservice/rest/server.php?wstoken=66a62ad146c76bea8e6216c1385eec0f&wsfunction=function_name_here

Note you can remove "/moodlepath" to suit where you have your Moodle installation.

The above is followed by the various parameters required for that function each part separated by the "&" symbol. For instance to return details of a course you would change "function_name_here" above for "core_course_get_courses" followed by, for example "&ids[0]=1". Note you do have to url encode the string so the "[" "]" become encoded but don't encode the "=" (Have a look at my source code for the library, class MoodleRestCourse, it might give you some clues). With the value 1 you should get the details of the "Site" course. When you get your reply it will be in XML which you will have to parse to extract the content.

Sorry, just looked and noticed you wanted to look at the source code, download the current release from:

http://sourceforge.net/projects/moodlerestjava/?source=directory

or the one I'm working on so not really released yet:

http://www.beaconhillcott.net/

Regards

Bill

In reply to Bill Antonia

Re: Use API in C#

by Penyo Rusev -

I tried and http://mymoodle.com/webservice/rest/server.php?wstoken=66a62ad146c76bea8e6216c1385eec0f&wsfunction=core_files_get_files&ids[0]=1

but no result...
I see your files, but its java and I need to migrate to .Net... This is a big problem...
Also, I need to pick webservice's url...

In reply to Penyo Rusev

Re: Use API in C#

by Bill Antonia -

Hi Penyo,

Sorry, just checked the params after the function name should be "&options[ids][0]=1", forgot the "options" and placing the "ids" in square brackets.

In reply to Bill Antonia

Re: Use API in C#

by Penyo Rusev -

Thanks, but I try "http://mymoodle/webservice/rest/server.php?wstoken=66a62ad146c76bea8e6216c1385eec0f&wsfunction=core_files_get_files&options[ids][0]=1" and again no result.. sad

In reply to Penyo Rusev

Re: Use API in C#

by Bill Antonia -

Note you do have to url encode the brackets [ ] so it becomes:

http://mymoodle/webservice/rest/server.php?wstoken=66a62ad146c76bea8e6216c1385eec0f&wsfunction=core_course_get_courses&options%5Bids%5D%5B0%5D=1

Note the function name I'm using as an example is different to yours, the core_files_get_files function would have different parameters. The url above, with "mymoodle" changed to your own site should return a load of XML as long as your token is correct for the service.

By the way, I have just tested the earlier idea of creating a Glassfish webservices server, just using the core_course_get_courses and it worked as long as I remove the entity injection the library does into the XML stream.

See the attached as example wsdl and schema for the test. The currently distributed library will throw a null error if you try this yourself with Glassfish. Something to fix!

In reply to Bill Antonia

Re: Use API in C#

by Bill Antonia -

Hmmmmmmm.......

Someone who could be trusted, could in theory set themselves up as a Moodle WSDL proxy server site to enable developers to access their own data via SOAP calls created from WSDL after enabling the REST protocol on their site. All you would have to do is to send as parameters the original .../webservice/rest/server.php URL, the token and the parameters for the call.

As I say, someone who could be trusted as the URL and token would be known to the proxy server but only in a transient way.

Obviously the external proxy would need access to the local Moodle site via the Internet, could not just be a local installation hidden behind a firewall.

Advantage of this would be all software languages which can use WSDL could call Moodle functions without any extra coding.

In reply to Bill Antonia

Re: Use API in C#

by Penyo Rusev -

Thanks for your support! I tried http://mymoodle/webservice/rest/server.php?wstoken=66a62ad146c76bea8e6216c1385eec0f&wsfunction=core_course_get_courses&options%5Bids%5D%5B0%5D=1 and it's work! Thanks! But if I want to call other function (like get_users_by_id) I haven't IDs and can't pick up. How to pick up?
And I tried  http://mymoodle/login/token.php?username=MYNAME&password=MYPASS!&service=SERVICENAME but the reply is "Web service is not available" but I enable it, so I haven't pick up the Token. Have you got any other idea for this?

I how to know all of parameters that I need to call? From API Documentation?

Thanks!

In reply to Penyo Rusev

Re: Use API in C#

by Bill Antonia -

http://mymoodle/webservice/rest/server.php?wstoken=66a62ad146c76bea8e6216c1385eec0f&wsfunction=core_user_get_users_by_id&userids%5B0%5D=1&userids%5B1%5D=2

This should return, after modifying the domain, the Guest (userid=1) and Admin (userid=2) users account details. These accounts are installed on your initial set-up of your Moodle.

As far as I know at the moment there is no way of obtaining a complete list of current users via web services. However if you go to Site administration->Users->Accounts->Browse list of users, then if you hover over the name you should see the details of the link, depending upon your browser you are using, Firefox shows the link URL at the bottom left of the page. One of the parameters is "id", the number after that is the Moodle id of the user you are hovering over.

One thing though, if you are going to use REST protocols then I would suggest you switch to sending requests via HTTP POST rather than HTTP GET as the URL strings could get very long and there is a limit, determined by the browser, any proxy you are using and the webserver software your Moodle is running on. It's ok to use HTTP GET in the examples you have been trying.

By the way, your second URL is not in the correct form for calling a REST webservice function what you are calling there is to retrieve a token for the user you are passing the credentials of.

http://<moodlesite>/<pathtomoodle/>webservice/protocol/server.php for token authentication, change <moodlesite> and <pathtomoodle/> as appropriate, followed by ?wstoken=someverylongstringwhichisatoken&wsfunction=some_function_name. This is then followed by the parameters required for that call.

http://<moodlesite>/<pathtomoodle/>webservice/protocol/simpleserver.php for user/password authentication, again change <moodlesite> and <pathtomoodle/> as appropriate, followed by ?wsusername=username&wspassword=some_password&wsfunction=some_function_name, the password being in clear text. This is then followed by the parameters required for that call.

If you go to Site administration->Plugins->Web services->API Documentation then you should see a list of function names. Click on one and it will expand to reveal the parameters and their required details and what is returned. Note, the [ ], any characters which are used within HTML such as < and >  and spaces should be urlencoded otherwise the call will not work.

In reply to Bill Antonia

Re: Use API in C#

by Penyo Rusev -

Thanks for your reply!
I need to see user's info, but I don't want to see it's ID from Site administration->Users->Accounts->Browse list of users
Sorry, but I don't understand that you say for HTTP GET and HTTP POST, can you give me more explanations and examples?
I need to get Token for authentication, like this examp: http://docs.moodle.org/dev/Creating_a_web_service_client (How to get a user token) but SERVICESHORTNAME is only in the DB and I can't see or change it.
Thanks!

In reply to Penyo Rusev

Re: Use API in C#

by Bill Antonia -

I think the only way you are going to get the Moodle user id(s) is to read the database explicitly using SQL statements ie "select id from mdl_user where deleted=0;"

As for the SERVICESHORTNAME, I cannot find where in Moodle to edit this field in the database, you could try a test database or make a backup and edit the field by hand to something appropriate to test as the SERVICESHORTNAME in the parameters of the call.

HTTP GET calls the server with all the parameters within the URL string.

HTTP POST calls the server with the URL required but an extra part is also sent with the rest of the data. This is how HTML FORM data is sent when the METHOD is set to POST. This extra part does have limitations on size but depends on the server at the other end only and is usually configurable. However its capacity is much larger than a HTTP GET.

In reply to Bill Antonia

Re: Use API in C#

by Penyo Rusev -

I want to work without the DB and get ID's, but may be this is a very big problem...
I see in the DB and can't see where is SERVICESHORTNAME or Services-table...
For HTTP POST I see this example https://github.com/moodlehq/sample-ws-clients/blob/master/JAVASCRIPT-REST/client.php
But I can't find for HTTP GET. Can you give me someone?
Thanks!

In reply to Penyo Rusev

Re: Use API in C#

by Bill Antonia -

HTTP GET is just doing what you have already been doing in your tests with the URL containing all the information required for the call to the webservice.

Look in the mdl_external_services table, you will find the shortname field there associated with the name of your service name, currently it will be NULL.

In reply to Bill Antonia

Re: Use API in C#

by Penyo Rusev -

Yes, but I can't reproduce it in C#.
Thanks, I see this table and it's Null as you said. But I want to work without use the DB, so how to get/change Service short name outside the DB?
Thanks!

In reply to Penyo Rusev

Re: Use API in C#

by Bill Antonia -

Once it is changed in the DB you don't have to go back there, just use what you entered into the shortname field in your call to replace SERVICESHORTNAME when fetching the token.

If you look at the documentation http://docs.moodle.org/dev/Creating_a_web_service_client then it says you currently cannot edit this field using the admin UI (it's near the end) although it states it will be added later.

In reply to Bill Antonia

Re: Use API in C#

by Penyo Rusev -

You are right! Thanks again! smile
Now, in C# I call any method with HttpWebRequest and HttpWebResponse.GetResponseStream() but I receive Moodle's method resault lika e string. How to make to pick it up lika a XML with headers and value?
Thanks!

In reply to Penyo Rusev

Re: Use API in C#

by Bill Antonia -
You have now got to the position where I decided to write a library in Java, but yours obviously would be in C#, to be able to decypher the XML response. The only problem is there are no headers sent, you have to use the tools you have in the language you are using to parse the text into something useful. I had to inject a list of entities into the stream for my parser to work, it's all teachers who add fancy html to their course summaries etc which causes problems!
In reply to Bill Antonia

Re: Use API in C#

by Penyo Rusev -

I make this and I pick up needed fields with

  XDocument xd = XDocument.Load("http://mymoodle/webservice/rest/server.php?wstoken=MYTOKEN&wsfunction=core_user_get_users_by_id&userids[0]=USERID");
            var keyz = from mXml in xd.Descendants("KEY")
                      
                      select new
                      {
                          Name = mXml.Attribute("name").Value,
                          Value = mXml.Element("VALUE").Value
                      };
            foreach (var k in keyz) { .... }

 

And it's work, but when get "customfields" and crashed, becouse there is other XML-design and can't get all XML-values.

 

So, I put this between 'from' and 'select' where (mXml.Attribute("name").Value == "firstname" || mXml.Attribute("name").Value == "lastname" || mXml.Attribute("name").Value == "email" || mXml.Attribute("name").Value == "address"
                          || mXml.Attribute("name").Value == "phone1" || mXml.Attribute("name").Value == "phone2" || mXml.Attribute("name").Value == "city" || mXml.Attribute("name").Value == "country")

But I need to pick all Values..

In reply to Penyo Rusev

Re: Use API in C#

by Bill Antonia -

You have to also take into account the "Parent" tag name, the root of the document is <RESPONSE>.

When you get to the custom fields etc, the "Parent" becomes <customfields> rather than <RESPONSE>, you have to change what you are parsing accordingly and create an array of objects for each custom field you find. The so overall you have one object with the main data then an array within that for the custom field objects.

You have to repeat this for <preferences> and <enrolledcourses>.

I use in this case an indication of "Parent" being <REPONSE> and "name" being <id> as the start of another person.

Hope that makes sense.

In reply to Bill Antonia

Re: Use API in C#

by Penyo Rusev -

Thank you, I'll try id. smile

In reply to Penyo Rusev

Re: Use API in C#

by Bill Antonia -

Hi Penyo,

What you need to use is the keyword "VALUE" for the search, in Java I'm afraid this is:

elements = (NodeList)xpath.evaluate("//VALUE", source, XPathConstants.NODESET);

Which from each Node it may be possible to obtain the "KEY" and its parent node by or the equivalent in C#:

for (int j=0;j<elements.getLength();j++) {
                String parent=elements.item(j).getParentNode().getParentNode().getParentNode().getParentNode().getNodeName();
                if (parent.equals("KEY"))
                    parent=elements.item(j).getParentNode().getParentNode().getParentNode().getParentNode().getAttributes().getNamedItem("name").getNodeValue();
                String content=elements.item(j).getTextContent();
                String nodeName=elements.item(j).getParentNode().getAttributes().getNamedItem("name").getNodeValue();

}

Inside that loop then parent, nodeName and content have the values you need for that one data element.

I use the nodeName equal to "id" when parent is "RESPONSE" to trigger the identification of a new user object.

In reply to Bill Antonia

Re: Use API in C#

by Penyo Rusev -

Thank you, I'll try it! smile

In reply to Penyo Rusev

Re: Use API in C#

by Penyo Rusev -

I can't reproduce it in C#. Can you help me?

I need to pick all "id's" in "enrolledcourses".

Thanks!

In reply to Penyo Rusev

Re: Use API in C#

by Bill Antonia -

Currently I don't know enough C# to write the code for you but as a guess....

You had this line in one of your earlier posts:

var keyz = from mXml in xd.Descendants("KEY");

If instead you replace "KEY" for "VALUE", this is assuming keyz is an array of pointers into the XML document. By selecting each entry in keyz is it possible to get the associated node which contains "KEY" for each "VALUE" node and therefore the name associated with the "KEY", then go on to finding the parent multiple entry node name. Once you have these three things you can interpret the data and store the information in a data structure.