Tuesday, May 29, 2012

Inspecting SDL Tridion Core Services SOAP messages

While debugging and troubleshooting tasks it is really important to have access to the soap messages being transmitted between the core services clients and the content manager server. Also, this kind of functionality can be used in order to modify the message before/after it is received and giving it a different meaning; in this post I am just writing those messages to the console stream but the same base line can be used to intercept and change messages like updating the soap header to include a different X509 certificate when signing messages.

In a well defined SOA design it is common to have message brokers that dispatch messages based in well defined policies. Message brokers can use message interceptors to change soap messages before they leave the bounds of the application based on business rules.

Adding a new Messages Inspector

Implement the interface IClientMessageInspector defined in the System.ServiceModel.Dispatcher namespace. This interface defines two methods that must be implemented AfterReceiveReply (intercepts the soap result message) and BeforeSendRequest(Intercepts the soap request message).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;

namespace Tridion.Extensions.CoreServices {
    public class CustomMessageInspector : IClientMessageInspector {
        public void AfterReceiveReply(ref Message reply, object correlationState) {
            Console.WriteLine(reply);
        }

        public object BeforeSendRequest(ref Message request, IClientChannel channel) {
            Console.WriteLine(request);
            return null;
        }
    }
}

Adding a new Endpoint Behavior

Implement the interface IEndpointBehavior by registering the CustomMessageInspector as part of the client behavior. Note that you can add multiple MessageInspectors that will be executed in the order they were added.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;

namespace Tridion.Extensions.CoreServices {
    public class CustomEndpointBehavior : IEndpointBehavior {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) {
            clientRuntime.MessageInspectors.Add(new CustomMessageInspector());
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) {
        }

        public void Validate(ServiceEndpoint endpoint) {
        }
    }
}

Adding some client code for testing

CoreServiceClient channel = new CoreServiceClient("basicHttp_2011");
channel.ChannelFactory.Endpoint.Behaviors.Add(new CustomEndpointBehavior());

OrganizationalItemItemsFilterData filter = new OrganizationalItemItemsFilterData();
filter.ItemTypes = new ItemType[] { ItemType.Component, ItemType.Folder };
filter.BaseColumns = ListBaseColumns.IdAndTitle;
           
XElement result = channel.GetListXml("tcm:5-4-2", filter);

This code will output the following input/output soap messages.

Input Messaage
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://www.sdltridion.com/ContentManager/CoreService/2011/ICoreService/GetListXml</Action>
  </s:Header>
  <s:Body>
    <GetListXml xmlns="http://www.sdltridion.com/ContentManager/CoreService/2011">
      <id>tcm:5-4-2</id>
      <filter xmlns:d4p1="http://www.sdltridion.com/ContentManager/R6" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" i:type="d4p1:OrganizationalItemItemsFilterData">
        <d4p1:BaseColumns>IdAndTitle</d4p1:BaseColumns>
        <d4p1:IncludeAllowedActionsColumns>false</d4p1:IncludeAllowedActionsColumns>
        <d4p1:ItemTypes>
          <d4p1:ItemType>Component</d4p1:ItemType>
          <d4p1:ItemType>Folder</d4p1:ItemType>
        </d4p1:ItemTypes>
      </filter>
    </GetListXml>
  </s:Body>
</s:Envelope>

Output Message
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <ActivityId CorrelationId="21305a1e-ab4c-453e-99a0-44d53163d617" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">244b2dd5-4477-4d09-88a9-d909f867d3b3</ActivityId>
  </s:Header>
  <s:Body>
    <GetListXmlResponse xmlns="http://www.sdltridion.com/ContentManager/CoreService/2011">
      <GetListXmlResult>
        <tcm:ListItems Managed="10682" ID="tcm:5-4-2" xmlns:tcm="http://www.tridion.com/ContentManager/5.0">
          <tcm:Item ID="tcm:5-38-2" Title="FootNotes" />
          <tcm:Item ID="tcm:5-35-2" Title="Level1" />
          <tcm:Item ID="tcm:5-40-2" Title="LightBoxes" />
          <tcm:Item ID="tcm:5-43-2" Title="Multimedia Library" />
          <tcm:Item ID="tcm:5-46-2" Title="Notes" />
          <tcm:Item ID="tcm:5-41-2" Title="Overlays" />
          <tcm:Item ID="tcm:5-24-2" Title="TestContent" />
          <tcm:Item ID="tcm:5-42-2" Title="TooTips" />
          <tcm:Item ID="tcm:5-643" Title="MC1" />
          <tcm:Item ID="tcm:5-642" Title="New Component" />
        </tcm:ListItems>
      </GetListXmlResult>
    </GetListXmlResponse>
  </s:Body>
</s:Envelope>

No comments:

Post a Comment