Web API integration (aka Authenticated/authorized web service advise - RESTful?)

Topics: Core, Writing modules
Apr 25, 2012 at 5:04 PM
Edited May 13, 2012 at 7:19 PM

I'm going to need a web service for an Orchard site soon, but the access to that web service should be controlled, i.e. client would be required to authorize themselves. How would you go?

I thought about WCF, but besides it being non-trivial to use in Orchard it also seems a bit bloated for me. Considering that I'd like to expose this functionality to clients with any technology I would opt with a RESTful web service anyway, that's why I think the best option would be to just implement it with standard controllers and actions.

Now here comes security, which is well thought-through in WCF but I'd have to implement some aspects myself. Reading some excellent resources on that topic (e.g. http://stackoverflow.com/questions/3592330/restful-web-service-authentication, http://stackoverflow.com/questions/6134082/restful-web-service-how-to-authenticate-requests-from-other-services, http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/) I came to the conclusion that probably my best bet would be to

  • Use SSL for communication
  • Use the HMAC method to sign requests (described in the third linked article too; this would be also possible with JavaScript clients with e.g. jsSHA)

The new Web API framework will be soon released with MVC 4, I wonder how it would play inside Orchard?

ServiceStack seems interesting, too but I don't think it would be simple to use with Orchard.

What do you think?

Other resources, updated continuously:

Apr 25, 2012 at 5:59 PM

Web API ? Maybe Mick could explain how to integrate it into orchard ?

Apr 25, 2012 at 5:59 PM


Apr 25, 2012 at 8:04 PM

Further resources:

All in all it seems that the cleanest and possibly the best authentication method would be to use HMAC and then employ Orchard's authorization services for authorization.

While WebAPI seems to be nice with cool features like content negotiation (meaning it serves JSON or XML or any other type, depending what the client accepts) or OData querying it seems there is no built-in solution for stateless authentication-authorization; one has to implement it on his own.

Also there seems to be no standardized way of dealing with exceptions (although there are some great tips).

Apr 30, 2012 at 9:48 PM
sebastienros wrote:


Ahem... 'Super Nick'

Apr 30, 2012 at 10:04 PM
Edited Apr 30, 2012 at 10:09 PM

Off the top of my head, the first thing I did was to get Orcahrd up to MVC 4.0 Version. Next... In the framework I needed to install the AspNetWebApi Nuget package.

Next code changes!

CompositionStrategy.cs -

You need to return a list of Service Controllers. so...

In the Compose method add.. 

var serviceControllers = BuildBlueprint(features, IsServiceController, BuildServiceControllerBlueprint, excludedTypes);
and then make sure that you have passed that through to your ShellBlueprint...

ServiceControllers = serviceControllers,


Next add a couple methods to the class...

        private static bool IsServiceController(Type type) {
            return typeof(IHttpController).IsAssignableFrom(type);

        private static ControllerBlueprint BuildServiceControllerBlueprint(Type type, Feature feature) {
            var areaName = feature.Descriptor.Extension.Id;

            var controllerName = type.Name;
            if (controllerName.EndsWith("Controller"))
                controllerName = controllerName.Substring(0, controllerName.Length - "Controller".Length);

            return new ControllerBlueprint {
                Type = type,
                Feature = feature,
                AreaName = areaName,
                ControllerName = controllerName,

Next to wire that Shiz up!


Right underneeth you build the Controllers... Add this code...


                    foreach (var item in blueprint.ServiceControllers) {
                        var serviceKeyName = (item.AreaName + "/" + item.ControllerName).ToLowerInvariant();
                        var serviceKeyType = item.Type;
                        RegisterType(builder, item)
                            .WithMetadata("ControllerType", item.Type)
                            .OnActivating(e => {
                                var controller = e.Instance as ApiController;
                                if (controller != null)


Next I needed a controller factory....

Create a folder in the framework called WebApi so it goes Orchard.Framework\WebApi

next create file called.. WebApiHttpControllerFactory.cs and post this code into it..


public class WebApiHttpControllerFactory : IHttpControllerFactory {
    private readonly HttpConfiguration _configuration;

    public WebApiHttpControllerFactory(HttpConfiguration configuration)
        _configuration = configuration;

    /// <summary>
    /// Tries to resolve an instance for the controller associated with a given service key for the work context scope.
    /// </summary>
    /// <typeparam name="T">The type of the controller.</typeparam>
    /// <param name="workContext">The work context.</param>
    /// <param name="serviceKey">The service key for the controller.</param>
    /// <param name="instance">The controller instance.</param>
    /// <returns>True if the controller was resolved; false otherwise.</returns>
    protected bool TryResolve<T>(WorkContext workContext, object serviceKey, out T instance) {
        if (workContext != null && serviceKey != null) {
            var key = new KeyedService(serviceKey, typeof(T));
            object value;
            if (workContext.Resolve<ILifetimeScope>().TryResolveService(key, out value)) {
                instance = (T)value;
                return true;

        instance = default(T);
        return false;

    public IHttpController CreateController(HttpControllerContext controllerContext, string controllerName)
        var routeData = controllerContext.RouteData;

        // Determine the area name for the request, and fall back to stock orchard controllers
        var areaName = routeData.GetAreaName();

        // Service name pattern matches the identification strategy
        var serviceKey = (areaName + "/" + controllerName).ToLowerInvariant();

        // Now that the request container is known - try to resolve the controller information
        Meta<Lazy<IHttpController>> info;
        var workContext = controllerContext.GetWorkContext();
        if (TryResolve(workContext, serviceKey, out info)) {
            var type = (Type)info.Metadata["ControllerType"];

            controllerContext.ControllerDescriptor =
                new HttpControllerDescriptor(_configuration, controllerName, type);

            var controller = info.Value.Value;

            controllerContext.Controller = controller;

            return controller;

        return null;

    public void ReleaseController(IHttpController controller) {


Next you need to hook up the routing!!!...

Create another folder called RouteExtension.cs so like so Orchard.Framework\WebApi\Extensions

Paste this code in to it...


public static class RouteExtension {
    public static string GetAreaName(this IHttpRoute route) {
        var routeWithArea = route as IRouteWithArea;
        if (routeWithArea != null) {
            return routeWithArea.Area;

        var castRoute = route as Route;
        if (castRoute != null && castRoute.DataTokens != null) {
            return castRoute.DataTokens["area"] as string;

        return null;

    public static string GetAreaName(this IHttpRouteData routeData) {
        object area;
        if (routeData.Route.DataTokens.TryGetValue("area", out area)) {
            return area as string;

        return GetAreaName(routeData.Route);

Next its time to hook your controller factory up to Orchard....

Head into the OrchardStarter.cs file

Around line 142... insert this..

var configuration = GlobalConfiguration.Configuration;
GlobalConfiguration.Configuration.ServiceResolver.SetService(typeof(IHttpControllerFactory), new WebApiHttpControllerFactory(configuration));

That should be it..... Welcome to the World of WebApi Asp.net V4!

I did this around 2 months ago... So if I have missed something, let me know!!!

May 1, 2012 at 2:07 PM

Thank you for this incredibly comprehensive compilation!

It looks that there are a lot of mods needed for this to work. It seems for me there is no better way (the problematic parts like CompositionStrategy or ShellContainerFactory are not extensible but would have to be completely overridden). I wonder if you tried to make all this in module, without modifying any core classes? I'll look into this.

May 1, 2012 at 2:09 PM
I did get WCF WebApi Preview 6 working with no modifications.

On Tue, May 1, 2012 at 2:07 PM, Piedone <notifications@codeplex.com> wrote:

From: Piedone

Thank you for this incredibly comprehensive compilation!

It looks that there are a lot of mods needed for this to work. It seems for me there is no better way (the problematic parts like CompositionStrategy or ShellContainerFactory are not extensible but would have to be completely overridden). I wonder if you tried to make all this in module, without modifying any core classes? I'll look into this.

Read the full discussion online.

To add a post to this discussion, reply to this email (orchard@discussions.codeplex.com)

To start a new discussion for this project, email orchard@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com

May 1, 2012 at 5:55 PM
Edited May 12, 2012 at 12:12 PM

That means there were so many changes between Preview 6 and the rename that you had to add so many modifications?

Other useful resources BTW:

May 1, 2012 at 8:14 PM

True... But It was more of an alternative... I would modify the core and upgrade to mvc 4 if I were you.

May 2, 2012 at 4:17 PM

My problem with that (apart from that it's modification to the core :-)) is that I'd also like to publish this module of mine that would use WebAPI and I really don't want every user to request to make this mods too.

May 7, 2012 at 10:38 AM

I've given this up for now, because updating to MVC 4 sucks :-). There are 3.0 references everywhere (e.g. in all module Web.configs, so I wonder how we'll manage the update, since I guess all the community modules have to be updated as well?), so I stopped when one error message was just too cryptic for me.

I'll maybe try again when Orchard is already MVC 4, but currently the amount of hacking needed to use Web API outweigh its gains.

May 8, 2012 at 2:30 PM

Perhaps this may be of some assistance... I haven't tried it myself (it's on my todo list)

I don't know if this uses an older version of WebApi so it may be irrelevant. 


May 8, 2012 at 8:54 PM

Thanks, I've already read it but it doesn't really help. Although my main problem here was the obstacle of updating...

May 11, 2012 at 6:21 PM

First I'm back to trying to use Web API. Actually apparently it's entirely possible to use it with MVC 3, so there is no need to update to MVC 4, which is a huge bonus :-).

Maybe it's also possible do use Web API without modifying the core? It seems to me that all this could be done with an Autofac module. It won't be the same style like Orchard registers controllers, but it wouldn't require altering the core.

  • Blueprint generation is as far as I understand necessary for the whole registration to work just like with controllers. But in the end it's just a dependency registration with Autofac (the code that would go into ShellContainerFactory).
  • The WebApiControllerFactory could be registered as a standard service with Autofac too.

What am I missing?

May 11, 2012 at 6:30 PM

You are missing that you can assume an upgrade to MVC4. So take it into account. And feel free to modify the core as necessary to have MVC4 and WebApi working. We'll take the changes. Could ship with 1.5. And then don't try to make it a module. If you need help, well I am in the MVC/WebAPI team, so I should be able to help you, I'll try at least.

May 12, 2012 at 11:47 AM

That's very cool, I'm glad for your help. Then I'll go on with the integration, The first thing will be to put Nick's code into a fork.

May 12, 2012 at 2:14 PM

I've made some integration efforts in this fork. I had to do a lot of copy-pasting, what is downright ugly:

  • Orchard.Mvc.Extensions.RouteExtension because RouteData and IHttpRouteData has nothing in common in terms of type hierarchy, although having a similar interface
  • The same with Orchard.WorkContextExtensions because of RequestContext and HttpControllerContext or even because of IHttpRoute and Route

The above would need some refactoring for sure:

  1. Either write some common classes for the actual work and use them through adapter classes.
  2. Or I wonder if there were some work going on for MVC 4 to merge the types or to create some common interfaces?

Also the class OrchardHttpControllerFactory has a lot common with OrchardControllerFactory, so this has to be refactored too.

The code won't compile, because I couldn't solve the problem with getting the work context for an HttpController. This would need the access to the HttpContext (IWorkContextAccessor.GetContext(HttpContextBase httpContext) requires it) but I've found no way to get it from HttpControllerContext. This is all in the controller factory.

I wonder, Nick how did you manage to solve this problem with the WorkContext?

May 12, 2012 at 2:29 PM

Im lookign now...

Onethings I failed to montion is that when using an ApiController... this is what I did.

    public interface IVideoEntriesController : IHttpController, IDependency { }

    public class VideoEntriesController : ApiController, IVideoEntriesController
        private readonly IVideoService _videoService;

        public VideoEntriesController(IVideoService videoService)
            _videoService = videoService;
            Logger = NullLogger.Instance;

        public ILogger Logger { get; set; }

May 12, 2012 at 2:37 PM

Ah!! I think I have noticed I missed something from above....

In ShellRoute.cs, in the method GetRouteData... where the line says this...

routeData.DataTokens["IWorkContextAccessor"] = _workContextAccessor;

you need to do this..

routeData.Values["IWorkContextAccessor"] = _workContextAccessor; //NGM : Added for WebApi
routeData.DataTokens["IWorkContextAccessor"] = _workContextAccessor;

I will keep looking.

May 12, 2012 at 2:41 PM

BTW... To do routing in your modules... you need to do this...

Create Routes.cs file (in your module)

Add this method...


        public static Route MapHttpRoute(string name, string routeTemplate, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens) {
            return new HttpWebRoute(routeTemplate, HttpControllerRouteHandler.Instance)
                                          Defaults = (defaults),
                                          Constraints = (constraints),
                                          DataTokens = (dataTokens)



So when creating your Route... you need to do this:


                           new RouteDescriptor {   
                                   Priority = 1,
                                   Route = MapHttpRoute(
                                        new RouteValueDictionary { {"area", "Foo.Bar"}, {"Controller", "Foo"} },
                                        new RouteValueDictionary (),
                                        new RouteValueDictionary { {"area", "Foo.Bar"}, })



May 12, 2012 at 2:57 PM

To fix the problems with WorkContext.... Add these two methods to WorkContextExtensions.cs

        public static WorkContext GetWorkContext(this RequestContext requestContext) {
            if (requestContext == null)
                return null;

            var routeData = requestContext.RouteData;
            if (routeData == null || routeData.DataTokens == null)
                return null;

            object workContextValue;
            if (!routeData.DataTokens.TryGetValue("IWorkContextAccessor", out workContextValue)) {
                workContextValue = FindWorkContextInParent(routeData);

            if (!(workContextValue is IWorkContextAccessor))
                return null;

            var workContextAccessor = (IWorkContextAccessor)workContextValue;
            return workContextAccessor.GetContext(requestContext.HttpContext);

        private static object FindWorkContextInParent(RouteData routeData) {
            object parentViewContextValue;
            if (!routeData.DataTokens.TryGetValue("ParentActionViewContext", out parentViewContextValue)
                || !(parentViewContextValue is ViewContext)) {
                return null;

            var parentRouteData = ((ViewContext)parentViewContextValue).RouteData;
            if (parentRouteData == null || parentRouteData.DataTokens == null)
                return null;

            object workContextValue;
            if (!parentRouteData.DataTokens.TryGetValue("IWorkContextAccessor", out workContextValue)) {
                workContextValue = FindWorkContextInParent(parentRouteData);

            return workContextValue;

May 12, 2012 at 3:01 PM

For this build error

return workContextAccessor.GetContext(controllerContext.HttpContext);

I switched it to

return workContextAccessor.GetContext();

Not sure if that was the right thing to do... but it worked.

May 12, 2012 at 3:57 PM

Thank you very much again!

Do you know why ApiControllers needed to implement IDependency too? I got it more or less working without this.

In ShellRoute for me control never reaches the lines you mentioned in GetRouteData, since _route.GetRouteData(effectiveHttpContext); returns null. I think something has to be done with route building too. I guess this has to do also with why ApiController routes are no auto-registered (and route declarations are needed).

The two methods you copied from WorkContextExtensions is the same what it is now :-).

I pushed some changes, but the WorkContext acquisition is still an issue. I don't know where it could be pushed into the route's DataTokens.

May 13, 2012 at 9:28 PM

Can you add me to the fork? I will apply some changes for ya :)

May 13, 2012 at 9:44 PM

Wow, of course, I've added you. What I've done till now is pretty much only what you've told me anyway :-).

May 13, 2012 at 11:04 PM

Okay I have fixed the WorkContext thing, but for somereason its not resolving the Lazy<IHttpController> - I need to have a look at why and how exactly I got it working.

May 13, 2012 at 11:04 PM

Test Api route is in Experimental.... Url: http://localhost:30320/OrchardLocal/webapitest

May 13, 2012 at 11:19 PM
Edited May 13, 2012 at 11:24 PM

I seem to be havign problems pushing to codeplex. I will try again tomorrow.

May 13, 2012 at 11:23 PM
Edited May 13, 2012 at 11:28 PM

Very cool! I've tested with a sample ApiController dropped into the Users module but Experimental is fine for this. The module will be removed for 1.5 anyway. Please also push the changes :-). I see you have issues with pushing the changeset. And I see possibly you've solved it now? :-) You're added to the fork so there should be no problem with authorization...

I hope Sebastien can say something about the problem of duplicates I've mentioned earlier. The worst thing that can happen is the need for adapter classes, what is not a big deal.

May 29, 2012 at 3:55 PM

I've seen you pushed some changes, awesome! Will take a look at them.

Jun 1, 2012 at 10:42 AM

I've tried it but it doesn't seem to work (opening /webapitest gives a blank page and the test controller doesn't get instantiated), although formerly when I first tried it after including the changes you told I got a test controller to run.


                            .OnActivating(e => {
                                var controller = e.Instance as ApiController;
                                if (controller != null) {

in ShellContainerFactory. What does this mean? :-)

Jun 16, 2012 at 10:17 AM

What is the current status of this?  
I would very much like to make use of ASP.NET Web API in Orchard...

Jun 16, 2012 at 12:23 PM
Piedone wrote:

I've tried it but it doesn't seem to work (opening /webapitest gives a blank page and the test controller doesn't get instantiated), although formerly when I first tried it after including the changes you told I got a test controller to run.



                            .OnActivating(e => {
                                var controller = e.Instance as ApiController;
                                if (controller != null) {


in ShellContainerFactory. What does this mean? :-)

Oh that code was left in there for me to do some debugging. With the updated RC, we need to update the packages again. I believe things have changed again so it might be worth upgrading and fixing those compile issues first.

I will see if I can take a look again this weekend.

Jun 16, 2012 at 8:53 PM


2LM: Nick has practically made the usage of Web API already possible. There are a few more steps left, and of course Web API should be released, but after this, with the support of Sebastien, it could become part of Orchard.

Jun 16, 2012 at 9:27 PM

That is awesome indeed, seems I found myself a new CMS then :)

Jun 17, 2012 at 10:41 AM

Hey All, okay so its done and working.

Get the fork - https://hg.codeplex.com/forks/piedone/webapiintegration

load up the project and go to http://localhost:30320/OrchardLocal/api/webapitest

See the lovely name "Nick" get output to the window.

Let me know if it doesnt work for you. There is some clean up, as I duplicated something twice, so the hit on the controller is quite heavy... but hey... it works!


Jun 17, 2012 at 12:22 PM

Thanks! I have just tried to download the latest version, but it seems to be missing quite a lot of module projects and such.  Running the project therefor doesn't succeed in "Cooking the Orchard Recipe", and all sorts of .NET Errors occur...  Can you check if the uploaded version is complete please?



Jun 17, 2012 at 12:24 PM

Sure, whats it missing? Whats the error messages?

Jun 17, 2012 at 12:35 PM

Well, first, for completeness, I downloaded the latest version from
where I clicked "Download Latest version".

Result was a file called Orchard-66ee5efc1b92.zip, which does seem to be the latest changeset.  
This zip file doesn't contain quite a lot of projects from Orchard.Web\Modules and Orchard.Web\Specs.  
When running the website using CTRL-F5, I get the screen to choose website name, SQL type and such,
after which the cooking recipe screen comes.  This doesn't seem to complete, as I don't get my new site,
nor any errors, just a directory browse of the Orchard folder.  

When then manually surfing to http://localhost:30320/OrchardLocal/admin I get .NET errors about jQuery
not being found (.NET, not javascript)...

Jun 17, 2012 at 2:04 PM

Sometimes weird things happen with 'get latest version' - do you have Mecurial installed?

Jun 17, 2012 at 2:17 PM

Oh are you just getting runtime warnings? You might need to turn off Thrown Exceptions, leave User-Unhandled switched on.

Jun 17, 2012 at 2:56 PM

Never mind, I downloaded TortoiseHg and made a clone of https://hg.codeplex.com/forks/piedone/webapiintegration and now I have the full repository.  The website runs completely, but the aforementioned http://localhost:30320/OrchardLocal/api/webapitest makes Orchard return "Not Found".

Anything I need to do aditionally to get it working?

Jun 17, 2012 at 3:14 PM

Ok, found it, I needed to enable the "Experimental" module, it works like a charm now.  Sorry for the confusion, I'm not at all familiar enough with Orchard I guess (working on it :))

I see that you have implemented your own IRouteProvider, which doesn't seem to make use of (Global)Configuration, or at least, I don't find it immediately.  
Where can we define stuff like formatters, message handlers and such then?  

Jun 17, 2012 at 10:50 PM
Edited Jun 17, 2012 at 10:52 PM

Yo okay, so I havent implemented any of that stuff just yet. I have an idea on how to do that as will take a look on how to make it generic and really straight forward, but that part will take me some time, not alot but some.

Ideally you dont want module devlopers dealing with GlobalConfiguration, so the Route stuff was my stab (working stab) at abstracting that away. I may create another level on top so you dont need to do some of the stuff I have done in there.

@Piedone - I am probably going to create a new fork of Orchard and move my changes to a WebApi branch to allow Seb to merge in easily. They shouldnt be on Default.

All Ideas welcome :)

Jun 18, 2012 at 6:36 AM

Well, it all depends on whether you want WebAPI to expose the meta and data from Orchard only.  If you want to enable module developers to also expose their own meta and data through Web API, or to expose their own Module data in specific formats, then there should be some way to define it, either directly in GlobalConfiguration or through some abstraction layer (the latter being preferrable if I understand you correctly).

I do fear a bit that abstracting all of this will take away a lot of the flexibility WebAPI has to offer.  In my own implementations of WebAPI, I created my own formatter selector, contextual message handlers and so on.  Maybe you should elaborate a bit on your idea on how to make it generic, that way we have an idea on how we can offer you ideas regarding this :)

Anyways, it's absolutely fantastic to see a CMS running WebAPI, I'm having a blast here :D

Jun 18, 2012 at 9:03 AM
Edited Jun 18, 2012 at 9:05 AM

@Jetski: yeah, go ahead! I would look into a bit of refactoring regarding the various duplications mentioned earlier, so please add me to the fork when you create it. Awesome work BTW!

Couldn't MediaFormatter registrations done through providers, like with routes? The problem is basically the same: something should be set in Global, but modules shouldn't leave their territory.

Jun 18, 2012 at 9:06 PM

New fork: https://hg.codeplex.com/forks/jetski5822/webapiintegration

I have created a branch called webapi on that fork.

Jun 19, 2012 at 7:27 PM

Could you please add me to the fork?

Jul 16, 2012 at 8:17 PM

Damn, now I wanted to examine it but I get a "HTTP Error: 500 (URL Rewrite Module Error.)"... I'll take a look at it later.