November 05, 2017

Compatibility Chart of SDL Tridion and DXA.



Compatibility Chart 


Tridion 2011 Tridion 2011 SP1 Tridion 2013 Tridion 2013 SP1 HR1 SDL  8 SDL 8.5
Microsoft Edge - - - - - -
Internet Explorer 11 - - -
Internet Explorer 10 - -
Internet Explorer 9 - - -
Internet Explorer 8 - - - -
Internet Explorer 7 - - - -
Internet Explorer 6 - - - - - -
Mozilla Firefox
Google Chrome
Safari for Mac
Operating System
Microsoft Windows Server 2012 R2 with Update x64  Y
Microsoft Windows Server 2012 R2 x64  ✓  ✓
Microsoft Windows Server 2012 x64  ✓  ✓Dr
MS Windows 2008 R2 SP1 x64  ✓  ✓  ✓  ✓
Microsoft Windows Server 2008 R2 x64  ✓D
Microsoft Windows Server 2008 SP2 x86/x64  ✓D
Windows Server 2003 x86, x64
Windows 10 x86, x64
Windows 8.1 x86, x64  ✓  ✓
Windows 8 x86, x64  ✓  ✓  ✓  ✓Dr
Windows 7 Sp1 x86, x64  ✓  ✓  ✓  ✓  ✓
Database Server
AWS RDS-MSSQL 2016 -
AWS RDS-MSSQL 2012 ✓P
Microsoft Azure SQL database - - - - Y
MS SQL 2016 SP1 - - - - -
MS SQL 2014 SP2 ✓P
MS SQL 2014 SP1 - - - - -
MS SQL 2012 SP3  -  -  -  - ✓P
MS SQL 2012 SP2  -  -  -
MS SQL 2012 SP1  - ✓dr  - -
MS SQL 2008 R2 SP3  -  -  ✓  -  -
MS SQL 2008 R2 SP2  ✓ ✓dr  -  -
MS SQL 2008 R2  ✓dr  - - - -
MS SQL 2008 SP3  - - - - -
MS SQL 2008 SP2  - - - - -
MS SQL 2008 SP1  - - - - -
Microsoft SQL Server 2005 SP4  ✓P  - - - -
Microsoft SQL Server 2005 SP3  ✓Dr  -  -  -  -
Oracle Database 12c patch set 12.1.0.2  -  -  ✓  ✓  ✓
Oracle Database 12c patch set 12.1.0.1  -  -  ✓dr -  -
Oracle Database 11g Release 2 patch set 11.2.0.4  -  -  ✓  ✓  ✓
Oracle Database 11g Release 2 patch set 11.2.0.3  -  ✓  ✓dr  -  -
Oracle Database 11g Release 2 patch set 11.2.0.2  ✓  -  -  -  -
Oracle Database 11g Release 2 patch set 11.2.0.1  ✓dr  -  -  -  -
Oracle Database 10g Release 2 patch set 11.1.0.7  - - - - -
Oracle Database 10g Release 2 patch set 10.2.0.5  ✓  ✓dr  -  -
Oracle Database 10g Release 2 patch set 10.2.0.4  - - - - -

October 21, 2017

Publishing queue status on AWS Cloud-watch

In this years MVP retreat we did small Proof of concept to show the Publishing queue status on AWS cloud-watch in nice format. There are various ways to accomplish it.

- Using CoreService API to access the Queue.
- Directly querying the DB (not very recommended)
- PowerShell to read the queue (Yes its possible)

We choose last option as some Tridion Powershell Module created by SDL MVP Pkjaer makes it very easy.

Steps:

- Install Tridion Powershell module, details in above link.
- Install AWS Powershell module(s) on machine to work.
- Here is code snippet which do following

  • Import AWS Powershell 
  • Create Cloudwatch matrices based on two states "Waiting for Publish" and Waiting for Deployment"
  • fill the matrices with count of above two states
  • Write the data to cloudwatch


 Import-Module "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\AWSPowerShell.psd1"  
 $dat = New-Object Amazon.CloudWatch.Model.MetricDatum  
 $dat.Timestamp = (Get-Date).ToUniversalTime()  
 $dat.MetricName = "Waiting For Publish"  
 $dat.Unit = "Count"  
 $dat.Value = (Get-TridionPublishTransaction | Where-Object {$_.State -eq "WaitingForPublish"}).Count  
 $dat1 = New-Object Amazon.CloudWatch.Model.MetricDatum  
 $dat1.Timestamp = (Get-Date).ToUniversalTime()  
 $dat1.MetricName = "Waiting For Deployment"  
 $dat1.Unit = "Count"  
 $dat1.Value = (Get-TridionPublishTransaction | Where-Object {$_.State -eq "WaitingForDeployment"}).Count  
 set-AWSCredentials -AccessKey -SecretKey FT1nwN74NHkGtlJ -StoreAs "MVP17"  
 Set-AWSCredentials -ProfileName "MVP17"  
 Write-CWMetricData -Namespace "Usage Metrics" -MetricData $dat  
 Write-CWMetricData -Namespace "Usage Metrics" -MetricData $dat1  

Auto-scaling:

One of the purpose to push the queue data to AWS Cloudwatch is to configure the auto-scaling of instances.

if there are lots of items in queue, auto-scaling of publishing system can be configured on AWS infrastructure.



September 30, 2017

Migrate Images in Media Manager automation

Consider the use-case of uploading 7500 images manually and linking each image with component in SDL  Tridion. Its very tedious tasks to do and if any change in images and need to redo 2-3 times. you need hell of a time and dedication.

So Best approach is to Automate set of tasks so that it can be imported into Media Manager and Linking can also happen side by side.

So need following set of services to accomplish this task:

  1. SDL Tridion
  2. Media Manager Cloud instance
  3. STS Service
  4. SDL Media manager Client
  5. ECL Service Client
Part 1

Connecting to Media manager

STS - Security token service (STS) is a cross-platform open standard core component of the OASIS group's WS-Trust web services single sign-on specs.

STS is used to authenticate between Migration Tool and SDL media manager. setting up it required configuring public key of the  Media manager. It was the hardest part for this whole stuff.

- Generate proxy from the Media Manager Service
-  STS service should be in the running state.
- Migration tool will connect to MM using Federated Security with STS service providing the encoded MM's public certificate.
- Once connection is established the upload process triggers.

There would be two bindings in app.config  one for connecting to mediaManager another to connect to STS service running on Url like following : http://localhost:89/IWSTrust13

Note: STS service is not provide OOTB by SDL. You have to code is based on STS standard or talk to SDL if they have ready to use such service which can be leverages.

Part 2
This section is involved in ingesting assets into DAM.

Following are code snippet for digital assets migration/ingestion. code. first section create a program id and upload image

second code snipped create a distribution associated with program id.

 public string UploadFile(long folderId, long assetTypeId, long[] tags, string keywords, string fullPathToFileToUpload)  
     {  
       MediaManager2011Client mediaManagerService = null;  
       try  
       {  
         Logger.Info("Uploading Image");  
         UploadInfoData data = new UploadInfoData();  
         data.DistributionCreation=DistributionCreationOptions.OneDistributionPerItem;  
         data.IsIncludedInGalleries = true;  
         data.MakeAvailableForDownload = true;  
         data.MakeAvailableForWebPublishing = true;  
         data.ProgramCreation = ProgramCreationOptions.OneProgramPerItem;  
         mediaManagerService = new MediaManager2011Client("FederationEndpointHttps");  
         string uploadUrl = mediaManagerService.GetUploadUrl(folderId, assetTypeId, tags, keywords, data);  
         WebClient webClient = new WebClient();  
         var response= webClient.UploadFile(uploadUrl, fullPathToFileToUpload);  
         WebHeaderCollection headers = webClient.ResponseHeaders;  
         string assetIdAsString = headers["AssetId"];  
         string programIdAsString = headers["ProgramId"];  
         Logger.Debug(string.Format("Asset Id:{0} & ProgramId:{1} For Uploaded Image", assetIdAsString, programIdAsString));  
         return programIdAsString;  
       }  
       catch (Exception ex)  
       {  
         Logger.Error(string.Format("Exception caught while uploading image-{0}", ex.Message));  
         return null;  
       }  
       finally  
       {  
         if (mediaManagerService != null)  
         {  
           if (mediaManagerService.State == System.ServiceModel.CommunicationState.Faulted)  
           {  
             mediaManagerService.Abort();  
           }  
           else  
           {  
             mediaManagerService.Close();  
           }  
         }  
       }  
}

  public ItemData CreateNewDistributionData(long programId,long folderId,string distributionName, long outletId, IMediaManager2011 client)  
     {  
       var distributionData = new DistributionData();  
       distributionData.Name = distributionName;  
       distributionData.OutletId = outletId;  
       distributionData.OutletType = OutletClassifier.Image;  
       distributionData.ProgramIds = new[] { programId };  
       distributionData.IsLive = true;  
       distributionData.FolderId = folderId;  
       return client.AddItem(distributionData);  
     }  

Part 3
after images are ingested into Media Manager DAM, those needs to be linked to required components in the Tridion. so for External Content Library has to be used. Installation and configuration of ECL are very well documented on SDL Docs.

ECL Service client - Generating ECL stub is quite a task, it involves getting Media manager id and generate a stub in the CMS which actually create a component in CMS with Tcm-id. 

Stub Uri has following format: "ecl:{publicationId}-mm-{dist-Id}-dist-file"
ECL client is used to create ECL stubs in CMS. Check Detailed Article

September 27, 2017

Automation of ECL stubs creation

To generate a Stub for the image from external sources using External Content library,  its tricky to generate stub. if you have 100s of images to be imported and then putting those into SDL Tridion using ECL, its very time consuming

so we used following way to generate stub at run-time


Code Snippet:

This code create the ECL compatible URI which will be later used to generate the actual stub

 public string GetUris(string publicationId, CustomImage image)  
 {  
             if (image.d != null)  
             {  
               return string.Format("ecl:{0}-mm-{1}-dist-file", publicationId, image.Id);  
             }  
  }  


Following code is baseclass and instantiate the client to create the stub using following settings
    <endpoint name="EclBinaryEndpoint" address="net.tcp://localhost:2660/ExternalContentLibrary/2012/netTcp" binding="netTcpBinding" bindingConfiguration="EclNetTcpBinding" contract="Tridion.ExternalContentLibrary.Service.Client.ISessionAwareEclService"/>  


 public abstract class TridionEclBase  
   {  
     protected static Client tridionClient { get; set; }  
     public TridionEclBase()  
     {  
       tridionClient = Client.GetClientInstance();  
     }  
   }  

following snippet was used to create the actual stub in the CMS

 public class CreateImageStub : TridionEclBase  
   {  
     private SessionAwareEclServiceClient eclServiceClient;  
     public CreateImageStub()  
       : base()  
     { }  
     public Dictionary<string, string> CreateImageStubByEclUir(List<string> eclUrl)  
     {  
       return eclServiceClient.CreateOrGetStubUris(eclUrl);  
     }  
   }  

it returns key value pair

ECLID as key
TCMID as Value

July 26, 2017

Localization Best practices for pages and pagemeta

In multilingual websites, localization of Page-Meta is something which is tricky as metadata is either part of structure group if you want to apply for set of pages or part of page.

take the scenario of 10 countries , two language each, so you have 20 websites where you have to localize the pages(50 pages per site) of your website. if you go by flat meta data schema for pages. 

or you create a language master. where you localize the pages for the metadata. 



Some issues:
  • Localization needs to be done in multiple publications for each Language.
  • Translation Manager : Multiple publication needs to be localized for each Language e.g. for French both “Content Translation Fr” and “500 Website Parent French”.
  • Priority conflict between Localized Page in “500 Website Parent French” and “500 Belgium Website English”.
  • Blueprinting Complexity Increases.
Approach we took:

- Keep metadata in Component















- In Metadata schema create a component link for that.













Approach Benefits:
  • Only one Publication needs to be localized i.e. “300 Translation Fr”
  • Translation Manager : Metadata for Page gets localized with Content.
  • Priority conflict resolved. Country Master Website  takes priority as there is no Language Website Master.
  • Blueprinting Complexity is reduced.

Any Cons:

As we were using page types to create page similar pages. As page types do not clone the component links, so every pages started having same component which we added to sample 
page

Solution: in next post.

May 29, 2017

Unpublish Dynamic Component when Page is unpublished

We have a setup where component is dynamic and its also used on Page. But by-design in Tridion if you un-publish a Page which is using a dynamic component, it does not un-publish the component.


We have to fetch the component based on the metadata at various places and attached on page where component was also required on page for following requirements.
  • Author driven Page name
  • Author driven page Url
  • Author driven page metadata.
so following event code was written to handle the scenario.  in our scenario 

 [TcmExtension("UnpublishEventHandler")]  
   public class UnpublishEventHandler : TcmExtension  
   {  
     public UnpublishEventHandler()  
     {  
       EventSystem.Subscribe<Page, UnPublishEventArgs>(UnpublishComponent, EventPhases.TransactionCommitted);  
     }  
     public void UnpublishComponent(Page page, UnPublishEventArgs mUnPublishEventArgs, EventPhases mEventPhases)  
     {  
       var appConfig = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);  
       string cts = appConfig.AppSettings.Settings["UnpublishPageComponentTemplates"].Value;  
       IList<ComponentPresentation> cpList = page.ComponentPresentations;  
       List<IdentifiableObject> items = new List<IdentifiableObject>();  
       if (cpList != null)  
       {  
         foreach (ComponentPresentation cp in cpList)  
         {  
           if (cts.ToLowerInvariant().Contains(cp.ComponentTemplate.Title.ToLowerInvariant()))  
                        items.Add(cp.Component);  
         }  
         IEnumerable<IdentifiableObject> itemsenum = items;  
          List<TargetType> targets = new List<TargetType> { };  
          foreach (var pubTarget in mUnPublishEventArgs.Targets)  
          {  
            targets.Add((TargetType)pubTarget);  
          }  
          var transaction = PublishEngine.UnPublish(itemsenum, mUnPublishEventArgs.UnPublishInstruction, targets);  
       }  
     }  
   }