juin
11
2014
J'ai récemment eu à créer un service web pour permettre à des applications Windows (ou tout autre client web) de se connecter à DotNetNuke pour y gérer les comptes d'utilisateurs (création, suppression, édition, obtenir le courreil, etc.)
Puisque j'y ai passé pas mal de temps et que j'ai eu de la difficulté à trouver des exemples de code s'appliquant à DotNetNuke 7 sans y être préalablement connecté, j'ai donc décidé d'écrire cet article de blog pour mes notes et pour aussi vous informer.
Notez que cet article est en anglais, si vous ne comprenez pas l'anglais et aimeriez que cet article soit traduit, laissez-moi un commentaire et il me fera plaisir de le traduite en français.
The basics
That said, let's begin by the basics and just make a publicly accessible web service that allows anyone to ping the web service and get a pong back. For that we will use the new DotNetNuke 7 Services Framework which makes it quite simple if you know how to use it.
In order to make a web service that will work withing DotNetNuke 7, you will need to fire up Visual Studio and create a Class Library project (c# or VB but all examples here will be in c#).
That done, we will then reference some required DotNetNuke 7 required libraries (using the Add Reference dialog box), here's the list:
- DotNetNuke.dll
- DotNetNuke.Web.dll
- System.Net.Http.dll
- System.Net.Http.Formatting.dll
- System.Web.Http.dll
Then we also need to reference the System.Web class from the .NET tab of the same dialog box.
Finally, we neet to set the output path of the project to the DotNetNuke bin directory and we are ready to code.
Here is the code, the explanations follow:
01.
using
System.Net;
02.
using
System.Net.Http;
03.
using
System.Web.Http;
04.
using
DotNetNuke.Web.Api;
05.
06.
namespace
MyService
07.
{
08.
public
class
PingController : DnnApiController
09.
{
10.
[AllowAnonymous]
11.
[HttpGet]
12.
public
HttpResponseMessage PublicPing()
13.
{
14.
return
Request.CreateResponse(HttpStatusCode.OK,
"Pong!"
);
15.
}
16.
}
17.
18.
public
class
RouteMapper : IServiceRouteMapper
19.
{
20.
public
void
RegisterRoutes(IMapRoute mapRouteManager)
21.
{
22.
mapRouteManager.MapHttpRoute(
"MyService"
,
"default"
,
"{controller}/{action}"
,
new
[]{
"MyService"
});
23.
}
24.
}
25.
}
- We simply start with some using statements for our requirements as shown above
- We create a namespace for our service and whatever name we use here will be part of the url. I used MyService just for this example but use any name that makes sense for your service.
- Now we create a public class for our controller. You can create multiple controllers if you need to and the controller is just a group of related actions that make sense to group together. In my real project I have a PingController for testing purposes, a UsersController for any actions that relate to user accounts etc. Just use a name that makes sense since it will also show up in the url. Two things to be careful here:
- The name of your controller must end with the word Controller but only what comes before it will show in the url, so for PingController, only Ping will show in the url path.
- It must inherit DnnApiController so it will use the DotNetNuke Services Framework.
- Then we create the actual action, in our case, PublicPing. It is just a simple method which return an HttpResponseMessage and can have a few attributes. By default the new services framework will respond only to host users and you need to explicitly allow other access rights if needed, in this case the [AllowAnonymous] makes this method (or action if you prefer) available to anyone without credentials. The second attribute, [HttpGet] will make this action respond to HTTP GET verb, which is usually used when requesting some date from the web server.
- Finally in that action, you insert whatever code you action needs to do, in this case just return the string "Pong!", just remember that you need to return an HttpResponseMessage and not a string or int or other object.
Ok so our controller and action is done, now we just need to map that to an actual URL and that what the last part of the previous code does. In essence this code tells DotNetNuke to map a certain url pattern to the methods defined in your class. You can use that code as is just replacing MyService by whatever your service name is.
Testing:
That's all there is to it, your service is ready! To test it, first compile it, then just navigate to http://yourdomain/DesktopModules/MyService/API/Ping/PublicPing and you should see "Pong!" in your browser as a response.
For more information on the basics, see Getting Started with Services Framework WebAPI Edition blog post on DotNetNuke website.
Passing parameters
Ok, so the basic code above is working but it doesn't do anything useful. Lets add something more useful by creating an action that will give us the email address for a specific user id.
Again, here's the code and the explanations will follow (place the code inside the same namespace as the previous one):
01.
public
class
UsersController : DnnApiController
02.
{
03.
[RequireHost]
04.
[HttpGet]
05.
public
HttpResponseMessage GetEmail(
int
userid
)
06.
{
07.
DotNetNuke.Entities.Users.UserInfo ui;
08.
ui = DotNetNuke.Entities.Users.UserController.GetUserById(PortalSettings.PortalId, userid);
09.
return
Request.CreateResponse(HttpStatusCode.OK, ui.Email);
10.
}
11.
}
- First we build a UsersController class that will hold all actions related to user accounts, it is not absolutely necessary, you can have many actions in the same controller, however since this action is not at all related to our PingController, let'a make a new one more descriptive.
- We then make a GetEmail action (method) that will accept a userid parameter. The [RequireHost] parameter here will make it accessible only to host users, we'll see later other authentication options...
- The code in the method itself is pretty much self explanatory. The only interesting thing to note here is that because our class inherits DnnApiController, we already have a PortalSettings object available. That's the big advantage of making use of the DotNetNuke Services Framework. You will have a ModuleInfo object to represent your module (if there is one with the same name as your service, which is not necessary such in this case), a PortalSettings object that represents the portal at the domain name used to access the service (portal alias) and finally a UserInfo object representing the user that accessed the web service.
Testing:
If we now navigate to http://yourdomain/MyService/API/Users/GetEmail?userid=2 you should receive the email address back from the server unless of course that userid does not exist, make sure to test with a userid that actually exists for that portal. If you where not previously connected with a host account, then you will be asked for credentials.
Limiting access to certain roles
Ok, that works but you need to give host credentials to any person needing to use your webservice. To avoid that you can replace [RequireHost] by [DnnAuthorize(StaticRoles="Administrators")] which will limit access to administrators. Better but you still need to give them an admin account. So the easy way to give only limited access would be to create a new role in DotNetNuke just for your web service and replace Administrators by that specific role name in the authentication parameter.
Using HttpPost : (answer to a comment down bellow)
To answer Massod comment bellow, it is almost the same thing but you need to create an object to contain the posted data.
Let's make a simple ping that uses POST, first we need to create an object that will contain the posted data such as:
public
class
FormMessage
{
public
string
Message {
get
;
set
; }
}
Then we create the service method something like this:
public
class
PingController : DnnApiController
{
[AllowAnonymous]
[HttpPost]
public
HttpResponseMessage PostPing(FormMessage formMessage)
{
return
Request.CreateResponse(HttpStatusCode.OK,
"Pong from POST: message was '"
+ formMessage.Message +
"'."
);
}
}
note that normally, a post would only return ok and no message, I am just doing this so we can test here.
Now since this is a POST verb, we can't test it by only using url parameters, we need to make an html file with a form to test it out. It would be someting like this:
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<
head
>
<
title
>Untitled Pagetitle
>
head
>
<
body
>
<
label
for
=
"message"
>Message: label
><
input
type
=
"text"
name
=
"Message"
/>
<
input
type
=
"submit"
value
=
"Submit"
/>
form
>
body
>
html
>
The important thing to not here is that you can't just create your POST method taking a string even if this is only what you need, you do need to create an object that will take your parameters.
Also don't forget that this is only for testing, you usually don't want to make this publicly available, you would normally use another parameter than [AllowAnonymous] such as [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)] and [ValidateAntiForgeryToken] unless you really want that to be public.
Let me know if you have any more questions...
At a comment below, you can now download the project files here. Please note however that you will have to update the project references to your local .dll files.