Access Sitecore data with WCF

12

February 8, 2011 by Alistair Deneys

So, my laptop died. Again. Second time within 12 months. Time to get a new one…but as a result I’ve had to borrow another for this blog post. This laptop is quite under spec’d compared to my previous laptop. In fact, this laptop is actually a netbook with only 1 gig RAM and a 1.66 Ghz atom processor running Windows XP home. Yet I’ve been able to get Sitecore 6.4.1 running on it.

I’m also missing Visual Studio professional and am instead using the Visual Web Developer Express that’s on the machine. Being that I’m running Windows XP home I don’t have IIS installed so I’ll have to use the embedded ASP.NET web server that comes with Visual Web Developer.

A few years ago I was going to write a blog post entitled “Express, Express and Xpress” to show how anyone can start playing and developing on Sitecore for free by using Visual Studio Express, SQL Express and the free-for-personal-use Sitecore Xpress. But when I came to write it there really wasn’t anything to write about, the whole process was straight forward. So with this blog post, I’m just confirming that (e)xpress stack does in fact work.

Recently I had a query from a reader about how to use WCF with Sitecore to export data. So in this post I’ll show how easy it is to host a WCF service inside your Sitecore solution and access it using a Windows console application.

Sitecore is currently tied to the HttpContext and the API simply won’t work without one. I’ve heard of people trying to fake the HttpContext but only once have I heard of someone being successful in doing so. Yes, I seem to recall I also tried this, but gave up when I realised it was getting to hard for me to have confidence in the solution. Not to mention the giant web.config required to configure Sitecore to allow it to run which would need to be merged into the application.

An easier way to interact with the Sitecore API is to realise that Sitecore is an ASP.NET application, and deal with it. Don’t try and force the application to run without an HttpContext. Instead simply expose the APIs you need through a web service or WCF service. These services are hosted by the Sitecore application inside ASP.NET so there’s an HttpContext and the API will run. External applications including console and Windows applications can then call those services to do what they need to.

The first thing we’re going to do is create our project. Whether you create your project inside the Sitecore webroot or outside and use post build scripts to copy project files to your Sitecore folder is up to you. I favour the build-outside-webroot model, which I’ve covered before, but on this machine lacking IIS it’s much easier to use the build-inside-webroot model.

The build-inside-webroot project model requires an existing Sitecore instance so go ahead and set one of those up. I’ve create a Sitecore 6.4 instance under c:\inetpub\Sitecore64. Now I’ll create a new ASP.NET web application project called SitecoreWCF in Visual Web Developer under the site webroot (c:\inetpub\sitecore64\website) so I can have VWD spin up Cassini for me. By default VWD will put your project inside a folder of the same name, so your project would actually site under c:\inetpub\sitecore64\website\SitecoreWCF and Sitecore wouldn’t run when you start Cassini. So unload your project, move the project to the Sitecore webroot (don’t copy the web.config or any aspx files), delete the old folder and load your project in VWD again. You’ll know you’ve got it right if inside your project in VWD you open the web.config file and it’s your Sitecore web.config file.

Also add a reference to the Sitecore.Kernel dll in the /website/bin folder and set it’s CopyLocal property to false.

Next I’ll add a folder to put my service below, just to keep things organised. In Windows explorer create a folder called MyAPI inside the sitecore modules folder. Back inside VWD select the “Show All Files” button in the solution explorer then find the MyAPI folder you just created, right click and select “Include in Project”.

Now we can create the WCF service by right clicking the MyAPI folder and selecting add, new item, WCF service. Call the new WCF service MyAPI.svc. Visual Studio will now create the SVC file, code-behind and interface for the service. It will also update your web.config file to expose the service.

Sitecore has a great configuration patching system built in to allow adding or updating configuration through succinct include files. The benefit of this is that you don’t need to modify the Sitecore web.config file which is quite large (except changing the data folder). This makes it much easier to update Sitecore when the update includes web.config updates. if you’d made changes to the web.config file then you’d have to either update the new web.config with your changes, or update your customised web.config file with those that Sitecore have included in the release.

Unfortunately the config patching system only works for Sitecore configuration, which is understandable. But ASP.NET already includes a hierarchical configuration system. A web application can include web.config files in folders of the application to have those changes apply only to that folder. So rather than leaving my WCF configuration in the web.config file and needing to apply that configuration when I update, I’ll instead move the WCF configuration into a separate web.config file in the same location as the SVC file. This will also make it much easier to distribute the service as there wouldn’t be any web.config updates required to the application running the service.

<?xml version="1.0"?>
<configuration>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

I’ll add a new method to the service interface file and stub it out in the code-behind as well. Open the IMyAPI.cs file and add the following method declaration.

[OperationContract] 
string GetItemXML(string id);

Now create the method stub in MyAPI.svc.cs file.

public string GetItemXML(string id)
{
}

This method should accept an item ID or path as a string, find the item in the database then return the item’s XML. A note about context here though.

If you were to start coding the body of this method you’d be inclined to use the Sitecore context database only to find it’s null. This is because the Sitecore context site and item are both null. This just means we have to get the database ourselves. Which database to get? That will depend on what your doing with your data. If you’re only interested in published and approved content then use the web database. If your after item data to backup then use the master database. I’m going to use the master database for this example. The code below grabs the master database then finds the item and returns it’s XML. This is the body of the GetItemXML method.

var database = Sitecore.Configuration.Factory.GetDatabase("master");
var item = database.GetItem(id);

if (item != null)
  return item.GetOuterXml(false);
else
  return "item not found";

Now we have our WCF service we need to implement a WCF client to call the service. I’m going to create a Windows Console application, but Visual Web Developer doesn’t do Windows applications, so we’ll have to rip out one of the other weapons in the Visual Studio Express arsenal. And all I have on this machine is Visual Basic Express. Well, I suppose in the spirit of this “let’s try new approaches” post…

In Visual Basic Express create a new Windows console application then right click in your solution and select “Add Service Reference”. Make sure you have your Sitecore solution running in Visual Web Developer by selecting the debug menu then either “start debugging” or “start without debugging”. In the “Add Service Reference” dialog enter the URL of your WCF service.

http://localhost:2255/sitecore modules/MyAPI/MyAPI.svc

Alter the port above to what Cassini is using.

Click the “Go” button to find the service and after the service has been discovered define the namespace as MyAPI then click OK. If all goes well Visual Basic Express will create you a client proxy to use.

We can now call the WCF service through the client proxy inside the console application. The following code creates the client, calls the service method then outputs the item XML returned to the console. Keep in mind the below is in VB, not C#.

Dim client = New MyAPI.MyAPIClient

Console.WriteLine("Please enter an item ID or path")
Dim input = Console.ReadLine 

Dim xml = client.GetItemXML(input) Console.WriteLine(xml)

Now run the client with a valid item ID and the item’s XML will be written to the console.

wcf client output

And there you go. A WCF service running in Sitecore, using the Sitecore API and being called by a console application written in VB.

Now you can go and try and wash the VB off your hands 🙂

Advertisements

12 thoughts on “Access Sitecore data with WCF

  1. Padma says:

    Alistair: Very nice article could you share the source code with us.

  2. […] All the above options for long running processes are OK running up to a couple of minutes. You must keep in mind that Sitecore runs inside IIS and so the execution lifetime of your code is controlled by IIS and not you. IIS may terminate your application at any time for whatever reason. Due to this I would recommend using an external Windows application and services hosted in Sitecore for any tasks which would run for more than a few minutes. I’ve recently blogged about how to host a WCF service inside Sitecore. […]

  3. suresh says:

    Hi
    this is great. But, i want to follow the same approach by hosting the services outside the sitecore solution. what is the minimal configuration i need to have..?

    thanks

  4. suresh says:

    Hi Alistair
    thanks for the reply.
    yes, i would be hosting on the iss.
    since my project is an integration project and we are hosting all our services on a different server. and also there will be many calls to this server and i do not want to put load on my sitecore servers.

    Hence, want to host it outside the sitecore solution.

    thanks,
    suresh

    • Alistair Deneys says:

      Hi Suresh,
      Have a look at my post about unit testing against Sitecore outside the HttpContext https://adeneys.wordpress.com/2011/12/23/automated-testing-in-sitecore-without-an-httpcontext/. That should help you with this, though I would have concerns about concurrent usage of the Sitecore DBs from another instance. If you’re only reading the data then you should be fine, but if you’re planning to write to the DBs as well I’d still be inclined to host a service inside the Sitecore website and access that from your integration service, just to keep all the data access synchronised. Keep in mind the Sitecore data layer contains a lot of caching and if data is updated in the DB the data layer needs to be notified so it can reload that data. You might end up writing entries to the event queue to make that happen.

  5. schaelle says:

    Hi Alistair,

    Thanks for your post. I got the WCF service running inside my sitecore solution. But I have a problem to access my data because i get back no data from the database, also the Context.is null. I tried also this solution http://sitecoreblog.alexshyba.com/2009/03/attach-wcf-services-to-sitecore-context.html but with no success. If I run the samecode inside a ascx it works.

    Thank you very much for your help.

    Stefan

    • Alistair Deneys says:

      Hi Schaelle,
      The issue may be to do with site context. This can depend on where you have you SVC file in your project. Ensure the file is under a folder covered by one of the module site definitions (either “sitecore modules\shell” or “sitecore modules\web”). Hopefully then the site will resolve and the context will populate. You might also need to specify your service requires ASP.NET using the [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] attribute on the service class.

  6. schaelle says:

    Hi Alistair,

    Thanks for your help. I got it running.

    Stefan

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

The views expressed on this blog are solely my own and do not necessarily reflect the views of my employer.
%d bloggers like this: