During a recent DXA project we experienced strange errors when publishing some content.  We are moving to DXA and the new DXA templates try to render every field of the Component and linked-to Components.  This is usually great, but if your content is a bit stale or outdated, or possibly contains an invalid value (like mine did) then the following script might be helpful.  (You should create a normal Core Service app, mine is a Console App, and reference all the usual Tridion Assemblies).

It was complaining that a Category did not contain the Keyword.  The error message was ‘Keyword with title ‘Long Lost Keyword’ does not exist in Category ‘Amazing Category’ [tcm:7-12345-512].’ After some digging we found a Multimedia Component with invalid Metadata.   To view the invalid Metadata we used the excellent Tridion Alchemy Plugin Show Item XML from the team at Content Bloom.  If you haven’t yet tried Alchemy yet, now is the perfect time, and this plugin alone makes it worth the (free) install.  You can even just install it on your Dev server if you want.

The simple solution for our invalid metadata problem would be to change it in the GUI, but the GUI didn’t show the value, and we were stuck.  So, we decided to write a small Core Service script that updates the Metadata field or Removes it.  Hope this helps.

 

Currently as part of the Publish process, in a post-build event I am sending JSON to an external search engine.  As part of that process, I wait for a response from the search engine that the content arrived successfully.

However, when it doesn’t arrive, I wold like to notify authors via the PublishQueue status that it didn’t get there.  One solution is to update the Publish Status on the published item, setting it to Warning or Failed, and also update the text in the Publish Transaction.  The code below shows how we can do this.  I implemented it as a WebService, so it is possible to be called from any external system, including the event system.

 public void Get(string transactionUri)
 {
      string uri = "tcm:" + transactionUri;
      string binding = "netTcp_201501";
      SessionAwareCoreServiceClient client = new SessionAwareCoreServiceClient(binding);
      PublishTransactionData trans = client.Read(uri, new ReadOptions()) as PublishTransactionData;
      string title = trans.Title;
      trans.State = PublishTransactionState.Warning;
      trans.Information = "Didn't make it to Search Index - please publish again";
      client.Update(trans, new ReadOptions());
 }

 

Using the Core Service we can easily get a list of all the Publish Targets in the system. We might want to do this if we are creating an app to publish items to a target (like the publish window) or if we want to Decommission a Publication Target in an environment, such as when we restore a database from one environment to the next.

The following code will get a list of all PublishTargets available within the context of a Publication. If you want to get all targets in the system then using the Admin user is the best. However, if you want to use the logged on user, then see my previous article to use the Core Service as the authenticated user (for a web app).

The data returned from the GetSystemWideList call changed between 2011 and 2013, and with the code below you will get all the info from the 2013 method. Special thanks to Likhan for the tip on the Tridion StackExchange.

The Tridion Core Service is a powerful API that gives us access to everything in the Tridion system. Sometimes we want to use an account with Admin permissions to get lists of items or delete items, for example. However, when creating or publishing items, we often want to do this in the context of the user logged into our Web Application built with the Core Service. This article is going to explain how to use the logged in user to perform Core Service actions and also give you a small debugging tip for Visual Studio.

Creating the Core Service Connection

I use a SessionAwareCoreService client which allows me to impersonate the user only with the username and not requiring a password. However, we do need port 2660 open between my local Visual Studio instance and the server if I debug against the server. Otherwise, if I work on my own local Virtual Machine with Tridion installed, I do not need to worry about this limitation. Then, after deploying to the server, it will work as expected.

Code

Making it work in Visual Studio

This user is normally empty when debugging in Visual Studio and this caused a small issue for me. Luckily, I found this great StackOverflow post explaining the solution. The one that worked for me is this:

“look at the properties of the web project, hit F4 to get the project properties when you have the top level of the project selected. Do not right click on the project and select properties, this is something entirely different.

Change Anonymous Authentication to be Disabled and Windows Authentication to be Enabled.”

Happy Core Service hacking!

Publishing is at the heart of every Tridion implementation – and when it breaks, I feel a bit sad inside.  Recently I had a strange content scenario breaking the Publisher service (and the TcmServiceHost.exe in Preview).  This happens about 1 time every 2 weeks or so, but when it does, it’s painful.  A seemingly normal Multimedia Component could cause this to happen, and we had no way to predict it.

Scenario:

1.  Publishing a Multimedia Component (linked to Page) gets stuck at the ‘Rendering’ phase and will not continue or fail.
2.  All other pages after this remain waiting in the Publish Queue.

To fix it:

1.  Remove item from Publish Queue
2.  Re-start Publisher

Troubleshooting the problem:
1.  Remove the Multimedia Components 1 by 1 until the problem one is found.
2.  Create a new Multimedia Component, using the same image, and replace the old broken Multimedia Component
3.  Re-Publish

We are still looking for the root cause.

In the meantime, we need a way to make sure the Publish Queue does not get stuck.

The Solution

Create a Windows Service that scans the Publish Queue at a regular interval (ie. 5 minutes) and if an item is in Queue for 2 intervals at the same phase, it’s stuck.  Remove the stuck item from the Queue, restart the Publisher service, and email an Admin.

Source Code

The Source Code is on GitHub at https://github.com/rcurlette/TridionPubQMonitor

Main class:  https://github.com/rcurlette/TridionPubQMonitor/blob/master/TridionPubQMonitoringService/TridionPubQService.cs

To Run:
1.  Download Source Code
2.  Add the Tridion Core Service DLL and Config to dependencies folder
3.  Update the app.config with your username / password for the Core Service
4.  Add mailtrap.io settings for sample email
5.  Compile
6.  Open Command Prompt (Run As Admin)
7.  Run ‘InstallUtil.exe TridionPubQMonitoringService.exe’
You can run this on the .exe file built from your Visual Studio in the bin/Debug folder
8.  Start the Service in the Services Control Panel.  Look at the Tridion Event Log for messages about starting, stopping, etc
9.  To recompile, stop the service, uninstall it ‘InstallUtil.exe /u TridionPubQMonitoringService.exe’ and then compile and install

Tips:

– Change the Phase to a phase that items stay in for more than 5 minutes while testing.  I had a lot of pages going to ‘Failed’ on my local Dev box, so I set it to that phase.  But if your Dev server is in better shape than mine, maybe you would want to change that to ‘Success’.

– You should see the items disappear from the Publish Queue at some moment (after 2 time intervals have passed) and also a message written to the Tridion Event Log.

 

What happens if you have hundreds, or thousands of items you want to check-in? One solution is to check-in the items using the GUI, My Tasks, All Checked out items option. However, there is another way and that is to run a script to check-in the items automatically. This is also helpful if you want to check-in all items before running another script.

Running scripts in Tridion is a common activity on large implementations. There’s always some data manipulation we want to do in bulk and save the Editors and Authors hours of time. Sometimes, however, during these bulk operations we have a failure, and sometimes items remain checked out.

In this article I will describe how to create a Core Service Console Application to check-in Tridion items. The following code uses the Tridion Core Service and can run from any Tridion instance.

Step 1: Creating the Core Service App and References

1. Create a new Console Application.

2. Reference the Tridion Core Service DLL

3. Create an App.config file

Copy the Core Service config from C:\Program Files (x86)\Tridion\bin\client\Tridion.ContentManager.CoreService.Client.dll.config

4. Reference 2 Microsoft DLLs:

  • System.Runtime.Serialization
  • System.ServiceModel

5. Add the using statement for the Tridion Core Service.

using Tridion.ContentManager.CoreService.Client;

Summary:
Creating the core Service app is relatively simple and straight-forward. The good news is we now have everything we need to get started writing some code.

Step 2: Using the Core Service to find Checked-out items

1. Set the binding. The Tridion Core Service comes with 2 binding options. It depends on your client (.Net, Java, etc) and also the ports avaialble (netTCP requires port 2660). For this example I will ue NetTCP since it is the fastest binding and most often used.

The binding is in the App.config file.

<endpoint name="netTcp_2011"

// use the endpoint name in our C# code
class Program
    {
        private static string binding = "netTcp_2011";
		//....
	}

2. Create an instance of the Core Service client and get all checked out items. * The magic here is in which filter to use. Big thanks to Andrey (aka Mr. P) for his help. how-do-i-get-a-list-of-checked-out-items-with-the-core-service

I always wrap the code in a using statement to displose of resources. The SystemWideListFilter is a special one that has magic powers to get items not conatined in any Blueprint Publication.

public static XElement FindCheckedOutItems()
{
	using (SessionAwareCoreServiceClient client = new SessionAwareCoreServiceClient(binding))
	{
		RepositoryLocalObjectsFilterData filter = new RepositoryLocalObjectsFilterData();
		XElement checkedOutItemsXml = client.GetSystemWideListXml(filter);
		return checkedOutItemsXml;
	}           
}

Step 3: Using the Core Service to Check-in items

1. Check-in the items with the Core Service

private static void CheckinItems(XElement items)
{
	using (SessionAwareCoreServiceClient client = new SessionAwareCoreServiceClient(binding))
	{
		foreach (XElement tridionItem in items.Nodes())
		{
			if (tridionItem.Attribute("Type").Value == "16" || tridionItem.Attribute("Type").Value == "64")
			{
				client.CheckIn(tridionItem.Attribute("ID").Value, new ReadOptions());
			}
		}
	}
}

That’s it. Here’s the final solution code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tridion.ContentManager.CoreService.Client;
using System.Xml.Linq;

namespace CheckinItems
{
    class Program
    {
        private static string binding = "netTcp_2011";
        static void Main(string[] args)
        {
            CheckinItems(FindCheckedOutItems());
        }

        public static XElement FindCheckedOutItems()
        {
            using (SessionAwareCoreServiceClient client = new SessionAwareCoreServiceClient(binding))
            {
                RepositoryLocalObjectsFilterData filter = new RepositoryLocalObjectsFilterData();
                XElement checkedOutItemsXml = client.GetSystemWideListXml(filter);
                return checkedOutItemsXml;
            }           
        }

        private static void CheckinItems(XElement items)
        {
            using (SessionAwareCoreServiceClient client = new SessionAwareCoreServiceClient(binding))
            {
                foreach (XElement tridionItem in items.Nodes())
                {
                    if (tridionItem.Attribute("Type").Value == "16" || tridionItem.Attribute("Type").Value == "64")
                    {
                        client.CheckIn(tridionItem.Attribute("ID").Value, new ReadOptions());
                    }
                }
            }
        }
    }
}

Summary

The Core Service is a powerful tool in our Tridion toolbelt. With the right filters we can work magic, retrieving lists of items never thought possible. A big thanks for the help from the Tridion community for sharing information!

The Tridion TOM.NET API and the Core Service introduced some new ItemTypes to Tridion, including the IdentifiableObject type.  While this is not a UFO, it might appear to you as an Unidentifable (Flying) Object.  In this post I hope to explain these other ItemTypes: IdentifiableObject, SystemWideObject, RepositoryLocalObject, and VersionedItem and are what I call the Tridion UFOs.

The Tridion Core Service methods return the IdentifiableObject method a lot and knowing more about this type and also how to cast it to a more specific type is very important to get a working solution.  Recently I struggled a bit with this and was fortunate to have the Tridion Community on StackOverflow help me with my question.

In the old TOM API we did not have any generic parents to the objects – we always got back a concrete instance of an object that matched 1-1 to something we could see and touch in the GUI. This is not the case with TOM.NET or the Core Service where we can get back base-objects that contain a subset of the methods and properties of our real objects. These new classes are super-handy in .NET where we can use Generics and create more re-usable methods. But, using them requires a little bit of knowledge as to which one is best for the given scenario.

The Tridion 2011 UFOs

IdentifiableObject

The opposite of a UFO, but the most prevalent ItemType is the IdentifiableObject (IO). The favorite return type of many methods in TOM.NET and the Core Service, the IdentifiableObject always leaves us wanting more. Which is why we usually cast it to a more concrete object as soon as possible – unless we really only need the Title or URI.

Methods and Properties available:  * means the property is mandatory.

  • Title*
  • ID
  • IsEditable
  • AllowedActions
  • ExtensionData

SystemWideObject

Items not within a Publication. Most of these can be found in the Administration section of the GUI. Examples are Users and PublicationTargets.

Methods and Properties available:

  • Same as IdentifiableObject

RepositoryLocalObject

Repository is another name for Publication (why couldn’t they call it PublicationLocalObject?) so this means all items within our Publication. This ItemType is a good generic one to use when dealing with most content types.

Methods and Properties available include all from IdentifiableObject plus:

  • BlueprintInfo
  • IsPublishedInContext
  • LocationInfo
  • Metadata

VersionedItem

Content items such as Pages and Components. Does not include non-versioned items such as Folders or Structure Groups.

Methods and Properties available include all from RepositoryLocalObject plus:

  • LocationInfoVersionInfo

Tridion Old School Objects

Page

The page object we all know and love. Contains a mandatory property ‘FileName’ that must be set when creating new items.

Methods and Properties available include all from VersionedItem plus:

  • ComponentPresentations
  • FileName*
  • IsPageTemplateInherited
  • PageTemplate
  • WorkflowInfo

Component

The classic object containing the actual content. Contains a mandatory property of Schema.

Methods and Properties available include all from VersionedItem plus:

  • ApprovalStatus
  • BinaryContent
  • ComponentType
  • Content
  • IsBasedOnMandatorySchema
  • IsBasedOnTridionWebSchema
  • Schema*
  • WorkflowInfo

Casting the Generic IdentifiableObject to a Page object

Recently I was working on porting a classic ASP custom page to use the Core Service and was excited to learn about the copy method on this StackOverflow post. By default it returns an IdentifiableObject:

// newItem is ItemType IdentifiableObject
var newItem = client.Copy(source.Id, orgItemUri, true, new ReadOptions());

If I want to access the FileName property I need to cast it to a Page object:

// newItem is ItemType Page
var newItem = client.Copy(source.Id, orgItemUri, true, new ReadOptions()) as Page;

However, in my code I wanted to copy any kind of item and cast it to a Page if I need to. With some help from the Tridion StackOverflow community I learned how to get the ItemType and then for only Pages set the FileName property.

PageData pageData = newItem as PageData;  // Cast IdentifiableObject to Page object

Notice the new UnknownByClient (UBC) ItemType – almost a UFO!

	private string CreateNewItemCopy(string title, RepositoryLocalObjectData source, string filename)
        {
            string newItemUri = "";
            try
            {
                ItemType tridionItemType = GetTridionItemType(source);
                string orgItemUri = source.LocationInfo.OrganizationalItem.IdRef;
                var newItem = client.Copy(source.Id, orgItemUri, true, new ReadOptions());
                newItem.Title = title;
                if (tridionItemType == ItemType.Page)
                {
                    PageData pageData = newItem as PageData;
                    pageData.FileName = filename;
                    client.Update(pageData, new ReadOptions());
                }
                else
                {
                    client.Update(newItem, new ReadOptions());
                }
                newItemUri = newItem.Id;
            }
            catch (Exception ex)
            {
                throw;
            }

            return newItemUri;
        }

	private ItemType GetTridionItemType(RepositoryLocalObjectData source)
	{
		string itemType = source.GetType().Name;

		switch (itemType)
		{
			case "ComponentData":
				return ItemType.Component;
			case "PageData":
				return ItemType.Page;
		}
		return ItemType.UnknownByClient;
	}

Tridion Object Casting Is Good

Don’t worry if the method returns an IdentifiableObject and you need a concrete object such as Page or Component. Cast it to the object type you need and you’ll be cooking with gas!

Summary

It is a lot of fun learning about the Core Service. However, sometimes it is difficult getting familiar with the new ItemTypes and limited properties they provide. Becoming familiar with them and casting is essential.  What they offer allows us to use the most generic object possible for our methods yet also the opportunity to cast the object down to reality when you need to access that oh-so-special property. I hope I’ve provided a good overview of these UFOs and wish you luck in your casting adventures.