Showing posts with label soap. Show all posts
Showing posts with label soap. Show all posts

Friday, June 1, 2012

Consuming SDL Tridion Core Services from Adobe Flex - Part 2

In the first part Consuming SDL Core Services from Adobe Flex - Part 1 I covered the foundation of the interoperability between SDL Tridion and Adobe Flex. In this second part I will cover more advanced topics like effectively consuming data available in the Content Manager. This topic will cover read and filtering operations.

Sending soap requests to the Core Services


The web services based on soap implementation available in flex is pretty simple and does not allow you to do sophisticated requests that are easy to do in languages like C#. However, it gives you complete control on the soap messages being transferred between the flex application and the Core Services. The main issue with this approach is that must know the exact soap syntax that the Core Services understand in order to process the request. If you refer to my other article Inspecting SDL Tridion Core Services SOAP messages you will find a tool that allows you to inspect the soap messages being transferred between a C# client and the Core Services, in this post I will use the same syntax for my flex client. The following soap body would be the one used to send a request for a "Where Used" operation.

<GetListXml xmlns="http://www.sdltridion.com/ContentManager/CoreService/2011">
    <id>tcm:5-6</id>
    <filter xmlns:d4p1="http://www.sdltridion.com/ContentManager/R6"
              xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
              i:type='d4p1:UsingItemsFilterData'>
        <d4p1:ItemTypes>
              <d4p1:ItemType>Component</d4p1:ItemType>
        <d4p1:ItemTypes>
    </filter>
</GetListXml>

 

Receiving soap responses from the Core Services


Flex supports several response formats (the result formats must be specified during the request), in this topic I will cover the most important ones in order to retrieve information from the core services.

The e4x format will instruct the parser to return the soap response as it is and to don't apply any kind of serialization. This format is really important when we retrieve xml lists. This also solves a serialization problems related with the Core Services because all the xml list responses are defined as xsd:Any in the xml schema and Flex cannot serialize them.

The object format will instruct the parser to return a serialized soap response. It will return an ObjectProxy instance from there we can retrieve all the information as properties. For instance for a component we can retrieve the content and metadata of a component using the following code.

var content:String = result.Content.toString();
var metadata:String = result.Metadata.toString();

 

Reading a tridion item


As shown in the code snippets below I am defining two methods one to retrieve the Tridion Item as a serialized object and the other one as an XML stream. Note that the operation name passed to the channel.getOperation method must match with the one defined in the Core Services WSDL.

public function ReadItem(id:String, success:Function, error:Function):void {
    var op:Operation = Operation(channel.getOperation("Read"));
    op.addEventListener(ResultEvent.RESULT, success);
    op.addEventListener(FaultEvent.FAULT, error);
    op.resultFormat = "object";
    op.send(id);
}

public function ReadItemXml(id:String, success:Function, error:Function):void {
    var op:Operation = Operation(channel.getOperation("Read"));
    op.addEventListener(ResultEvent.RESULT, success);
    op.addEventListener(FaultEvent.FAULT, error);
    op.resultFormat = "e4x";
    op.send(id);

 

Retrieving an xml list

This code snippet will retrieve a "Where Used' list.

public const CORESERVICE_NS:String = "http://www.sdltridion.com/ContentManager/CoreService/2011";
public const TRIDION_NS:String = "http://www.sdltridion.com/ContentManager/R6";
public const XSDI_NS:String = "http://www.w3.org/2001/XMLSchema-instance";
public const TRIDION_5_NS:String = "http://www.tridion.com/ContentManager/5.0";

public function GetListUsingItems(id:String, itemTypes:Array, success:Function, error:Function):void {
    var op:Operation = Operation(channel.getOperation("GetListXml"));
    op.addEventListener(ResultEvent.RESULT, success);
    op.addEventListener(FaultEvent.FAULT, error);
   
    var param:XML =
        <GetListXml xmlns={CORESERVICE_NS}>
            <id>{id}</id>
            <filter xmlns:d4p1={TRIDION_NS} xmlns:i={XSDI_NS} i:type='d4p1:UsingItemsFilterData'>
                <d4p1:ItemTypes />
            </filter>

        </GetListXml>
   
    var itemTypesXML:XMLList = param.descendants(new QName(TRIDION_NS, "ItemTypes"));
    for (var index:String in itemTypes) {
        var type:String = itemTypes[index];
        itemTypesXML.appendChild(<ItemType xmlns={TRIDION_NS}>{type}</ItemType>);
    }
   
    op.resultFormat = "e4x";
    op.send(param);
}

 

Retrieving a system wide list

This code snippet will retrieve the list of publications in the system

public const CORESERVICE_NS:String = "http://www.sdltridion.com/ContentManager/CoreService/2011";
public const TRIDION_NS:String = "http://www.sdltridion.com/ContentManager/R6";
public const XSDI_NS:String = "http://www.w3.org/2001/XMLSchema-instance";
public const TRIDION_5_NS:String = "http://www.tridion.com/ContentManager/5.0";

public function GetListPublicationsXml(success:Function, error:Function):void {
    var op:Operation = Operation(channel.getOperation("GetSystemWideListXml"));
    op.addEventListener(ResultEvent.RESULT, success);
    op.addEventListener(FaultEvent.FAULT, error);
   
    var param:XML =
        <GetSystemWideListXml xmlns={CORESERVICE_NS}>
            <filter xmlns:d4p1={TRIDION_NS} xmlns:i={XSDI_NS} i:type='d4p1:PublicationsFilterData' />
        </GetSystemWideListXml>
   
    op.resultFormat = "e4x";
    op.send(param);
}

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>