Archive

Archive for the ‘WCF’ Category

Access Sitecore data with WCF

February 8, 2011 10 comments

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 :)

Categories: Sitecore, WCF

WCF Trace Tool

February 16, 2009 2 comments

I’ve been doing a fair bit of WCF lately. And an absolute nightmare of an error to try to debug is the “Channel was in a faulted state” error. This is a very generic error and doesn’t really say much at all about the cause of the error.

The way WCF communicates is through channels. When a channel is in the faulted state, it means the construction and opening of a channel failed for some reason, and the channel faulted. Once in the faulted state a channel cannot be used. It must be constructed again.

So how do I debug this issue and resolve the cause of the error? If only there were some way of getting more information out of the channel creation process. Enter the WCF Trace Tool. WCF traces a fair bit of information when it’s doing it’s thing. There’s a lot going on under the hood, and Microsoft realise that we need to know what exactly is going on. So now all we have to do, is catch that trace.

Open up web.config and add the following configuration to /configuration/system.serviceModel:

<diagnostics performanceCounters="All" wmiProviderEnabled="true">
  <messageLogging logEntireMessage="true" logMalformedMessages="true"
    logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true"
    maxMessagesToLog="100000"/>
</diagnostics>

Then add the following to /configuration/system.diagnostics:

<sharedListeners>
  <add name="sharedListener"
    type="System.Diagnostics.XmlWriterTraceListener"
    initializeData="c:\logs\servicetrace.svclog" />
</sharedListeners>
<sources>
  <source name="System.ServiceModel" switchValue="Verbose,
ActivityTracing" >
    <listeners>
      <add name="sharedListener" />
    </listeners>
  </source>
  <source name="System.ServiceModel.MessageLogging"
    switchValue="Verbose">
    <listeners>
      <add name="sharedListener" />
    </listeners>
  </source>
</sources>

Thank Michele Leroux Bustamante for this info from her blog entry SvcTraceViewer.exe – Learn it, Know it, Love it.

Now when WCF is invoked, an XML trace file is written to the location above in the initializeData attribute. You could try inspecting this file in a text or XML editor, but the easiest way to inspect it is to use the WCF Trace Viewer which ships with the .net 3.0 SDK. This can be found at c:\Program Files\Microsoft Visual Studio 9.0\SvcTraceViewer.exe (that might only be the location if you have VS installed).

Just execute this program and load the XML trace file into it using the file menu. Now I can inspect the process of channel creation, servicing requests, and channel destruction. If I get an error it will be highlighted red.

Now let me tell you about what I was doing when I found this tool, as I reckon this is a pretty cool feature of WCF. Being that I’m building web sites, I of course usually host my WCF services in IIS. IIS only supports the HTTP protocols. As we all know HTTP only supports request / response calls. A server cannot send data to a client unless it is a response to a request. But WCF allows us to get around this limitation of HTTP, by using the duplex channel.

A duplex channel facilitates two way communication between a client and the server. How is this done? When the client sets up it’s channel, it communicates with the server and registers itself. To allow the server to call back into the client, the client sets up it’s own WCF service and tells the server about it, so the server can just call the service hosted by the client. So to facilitate two way communication, each machine hosts it’s own service which the other machine makes calls to. And the client side service is completely transparent to the developer.

So what did I need the trace tool for? Initially I was hosting the service I had issues with on the same machine as I was calling it from. Whilst both the server and the client were the same machine, I didn’t have any issues. I then moved the service onto another machine that was only connected to the first through a VPN. All of a sudden I started getting the faulted channel error. After enabling the trace and reading it in the trace viewer I could see the call where the client registers it’s callback service with the server. And I could see that the host name the client was sending to the server was the internal machine name which wouldn’t resolve through the VPN. After I changed this by setting the clientBaseAddress attribute on the binding, and applying the appropriate security, all worked fine.

I never would have worked this out had it not been for the trace viewer. I could have ripped out wireshark (you know it’s a bad day when you have to rip out wireshark :) ), but this was a production server where the error was occurring, and I wouldn’t have liked to deploy such a heavy tool to work it out. I hope this save you some sanity.

Categories: WCF
Follow

Get every new post delivered to your Inbox.