Question

I'm currently implementing functionality in Tridion 2009 SP1 where the user is able to utilise a filter which in turn queries the broker for matching criteria and then returns the Component Presentations to the page. Each item returned contains a component link.

Originally the dynamic CPs were stored in the broker DB as HTML fragments but it was discovered that when storing the CPs this way, Tridion would strip the component link from the content and leave a blank space in the HTML.

I then switched the setting so that the dynamic CPs are now stored on the filestore as ascx controls. When this setting is used, the <tridion:ComponentLink ... /> is successfully stored in the ascx file.

However, when I come to render the results to the screen, the component link is not being resolved and I am being left with the <tridion:ComponentLink ... /> in my resulting source.

Currently, I am using the GetComponentPresentation method to return the CP content which is then added to a List before being bound to a Repeater for display.

Summarised code is below:

ComponentPresentationFactory CPFactory = new ComponentPresentationFactory();
List<string> componentPresentations = new List<string>();

for (int i = 0; i < tbl.Rows.Count; i++)
{
    ComponentPresentation cp = CPFactory.GetComponentPresentation(
                                             tbl.Rows[i][0].ToString(), 
                                             strComponentTemplate.ToString());

    if (cp != null)
    {
        componentPresentations.Add(cp.Content);
    }
}

This list is the bound to the repeater in the usual way:

rptOffer.DataSource = componentPresentations;
rptOffer.DataBind();

Does anyone know how I can force the Component Link to be resolved and why the GetComponentPresentationfunction doesn't do this for me?

Is there something that I should be doing differently or is this just not possible in the way I'm implementing this?

I have confirmed that the tridion tagprefix is correctly registered in the web.config.

I'm fairly new to Tridion so any help is greatly appreciated!

UPDATE

I've attempted to implement Will's suggestion as it seems like the most appropriate solution for my scenario but I'm receiving a (pretty bland) error when I attempt to use Will's suggestion with my code below:

ComponentPresentationAssembler cpa = new ComponentPresentationAssembler("tcm:35-62652-64");
string content = cpa.GetContent(tbl.Rows[i][0].ToString(), strComponentTemplate.ToString());

There are actually 2 errors which occur (seemingly) randomly but always at the cpa.GetContent(...) call. The errors are:

Exception occurred during configuration callback
OR
com.tridion.dcp.ComponentPresentationFactory

I can't seem to figure out why the error changes between the times I run the code. The error changes even when no code changes are made.

Does anybody know what I'm missing here? I assumed that it would be an issue with the connectivity to the Broker storage etc but then I remembered that that part was working when I was using the ComponentPresentationFactory class.

If it helps, the DCP which is stored on the file store as an ascx contains the following HTML:

<div class="content-list-item offer redesign noImage">
<h2><span>Mike Offer 01/06 - 10/06 &amp; 20/06 - 10/07</span> Exp May 20th</h2>
<div class="content-list-item-text">
    <p>Body Text</p> 
    <div class="input-btn burgundy">
        <tridion:ComponentLink runat="server" PageURI="tcm:0-0-0" ComponentURI="tcm:35-31685" TemplateURI="tcm:0-0-0" AddAnchor="false" LinkText="Button Text&lt;span class=&#34;rm&#34;&gt;: Button Text&lt;/span&gt;" LinkAttributes=" alt=&#34;Button Text&#34; target=&#34;_self&#34; " TextOnFail="true"/>    
    </div>
        <p>Sub Title</p>
</div>
<div class="offers-list">        
    <ul>
        <li>Offer ends: 20 May 2012</li>
        <li>Offer available at all hotels</li>
    </ul>
</div>                          
<div class="back-to-top">
    <a href="#content">Back to top</a>
</div>

UPDATE 2

Thanks to Ryan, I've discovered that my DCP (ASCX) files weren't being published within the application's folder within the wwwroot folder which has solved the issue of it outputting the <tridion:ComponentLink ... /> tag directly to the source. It is now being rendered but the link is still not being resolved. The <a ... /> tags are not being output. This is where the Assembler will hopefully come in - once I can get this to work.

I've implemented more logging and checking and have more information on the error which suggests that I may be missing a jar file or have the incorrect version:

Exception Details: Java.Lang.ClassNotFoundException: com.tridion.dcp.ComponentPresentationFactory

The interesting this is, when I use the ComponentPresentationFactory class, it works (without resolving the internal link) but as soon as I use the Assembler, it throws the above error.

I have also attempted to add the Page to the constructor as suggested by Alvin but the output is the same.

Was it helpful?

Solution

As discussed already, in order to solve your problem you need to use the ComponentPresentationAssembler class, not the ComponentPresentationFactory class but you need to ensure that you use the ComponentPresentationAssembler class inside the Tridion.ContentDelivery.WAI namespace:

Tridion.ContentDelivery.WAI.ComponentPresentationAssembler presentationAssembler = new Tridion.ContentDelivery.WAI.ComponentPresentationAssembler("tcm:5-44410-64",this.Page);
Response.Write(presentationAssembler.GetContent("tcm:5-62700", "tcm:5-62627-32"));

You also need to ensure:

  • Your ASCX files are published to the file system This is set in the cd_broker_conf.xml file inside the <Bindings> section e.g. <Binding Name="ASPComponentPresentation" Class="com.tridion.broker.componentpresentations.FSASCXComponentPresentationHome"/>

  • Your ASCX files are published inside your .Net web application. This is set in the cd_broker_conf.xml file inside the <Publications> section e.g.

    <Publication Id="5" DocumentRoot="C:/Inetpub/wwwroot/website1" DataRoot="C:/Inetpub/wwwroot/website1/dcp">
        <Dcp>
            <Asp Location="C:/Inetpub/wwwroot/website1/dcp"/>
        </Dcp>
    </Publication>
    

Be aware that the locations you see above are case sensitive

OTHER TIPS

In order to execute a DCP, rather than just get the published content, you need to use the ComponentPresentationAssembler class, not the ComponentPresentationFactory class.

A simple example below:

ComponentPresentationAssembler cpa = 
   new ComponentPresentationAssembler("tcm:69-6212-64",this.Page);
Response.Write(cpa.GetContent("tcm:69-2882", "tcm:69-6339-32"));

Note that if you are publishing a lot (ie hundreds) of component presentations (and publishing them frequently), its not a good idea to use ascx - you may get some performance issues with ASP.NET batch recompiling the folder that contains them all, or triggering application restarts.

It is safer to publish them as (X)HTML fragments to database, and post process the links as Mark mentions.

As Frank mentions in 2011 SP1 you can use REL to do this post processing for you. See this article for more information

Mark's answer already covers the most important part for your version of Tridion: you must publish the ASCX files to disk in order for the tridion:CompontentLink controls to be executed by ASP.NET.

Tridion 2011 introduced REL as an alternative solution for this. When using REL you'll just publish HTML fragments again and the tcdl:ComponentLink will be stored as is into the database (so not transformed to tridion:ComponentLink upon deployment). Then when you retrieve the content (through the ComponentPresentationTransformer or through the new Content Delivery OData web service) thetcdl:ComponentLink (and other tcdl:* tags) will be resolved and you'll get the result you want.

You are loading the content of the dynamic component presentation as a string rather than executing the string as say a user control.

To solve your problem you can use 1 of 2 solutions:

1) Use a Regex on cp.Content to process the links via the Tridion API.

2) Publish you Dynamic content to the file system as user controls and load this control onto your page/ user control, thus executing it

using (var cpf = new ComponentPresentationFactory(publicationId))
{
    var cp = cpf.GetComponentPresentation(componentId, componentTemplateId);
    fileLocation = cp.FileLocation;
}

if (!String.IsNullOrEmpty(fileLocation))
{
    var crtl = this.LoadControl(MapPathReverse(fileLocation));
    phldControls.Controls.Add(crtl);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top