Tridion Component Link not resolving in Dynamic Component Presentation
Asked Answered
K

4

21

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.

Kopeisk answered 10/5, 2012 at 10:57 Comment(8)
Hey Mike, Welcome to Tridion. You manage to hide your newness quite well. :-) You'll find that most members of the Tridion community are quite helpful. If you haven't done so already, please commit to our Tridion proposal on area51: area51.stackexchange.com/proposals/38335/…Wedding
The problem is with CPFactory - use CPAssembler instead, as Will shows in his replyChiapas
On the .getContent() error, any chance it's related to multiple presentation servers and/or the component presentations actually being unpublished when you run the code?Portingale
Alvin - it's a single presentation server so that shouldn't be a problem. I also republished all the components (about 15 of them) after I'd changed the setting to publish as ascx rather than HTML in the broker DB just to make sure that wouldn't cause issues. Unfortunately, the issue is still there...Kopeisk
Use the other constructor instead, ComponentPresentationAssembler("tcm:35-62652-64", Page); ==> This page is .NET's page objectChiapas
Have you made sure that your ASCX files are published within your web application folder? You can set this in your cd_broker_conf.xml file.Skeptical
Thanks @Ryan, they were being published to the default location which was within the wwwroot folder but not the actual web app's folder which was an issue. It's not fully solved the problem but it's hopefully a step closer!Kopeisk
For the CP assembler to work I think you need to have a cd_wai_conf.xml file in bin/config and cd_wai.jar in bin/lib. Also try looking in the cd log files (check what log file path is configured in bin/config/cd_broker_conf.xml) - often you get a very clear error message logged here, different to the generic error messages in .NETSupercharge
S
11

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

Skeptical answered 11/5, 2012 at 17:47 Comment(3)
Cheers Ryan, I've marked Will's answer as the accepted answer as he was right with the use of the ComponentPresentationAssembler but it was really handy to have the list of things required in order to ensure everything was in place for this to work. Cheers!Kopeisk
Actually, looking at this again, I think that your answer is actually the reason that I managed to fix this. It turns out the error I was getting regarding ClassNotFoundException (see Update 2) was due to the fact that I was using the wrong namespace for the ComponentPresentationAssembler. Changing to the Tridion.ContentDelivery.WAI namespace fixed this issue and allowed me to get the code working completely. Apologies for missing that important part when it came to marking correct answers.Kopeisk
Unless I'm otherwise mistaken, you'll have to make sure that you have a license to use the WAI functionality. Just a note... I wouldn't want anyone to implement this and then find out they don't have the necessary Tridion licenses!Canea
S
18

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

Supercharge answered 10/5, 2012 at 12:35 Comment(8)
Good stuff Will. I see that you haven't joined our proposal yet for getting a Tridion-specific StackExchange area. Please follow this link and consider it: area51.stackexchange.com/proposals/38335/…Wedding
Thanks for that info @Will. I've attempted this but I'm now getting an error when I try and retrieve the DCP. I've added my error details to the post. Any ideas?Kopeisk
Ah, the classic CP Assembler vs Factory explanation (with the new goodness from REL), nice! @MikePercival--I suspect the difference in the errors was you caught null CPs in your first example. If you remove the check, do you get the same error over the same set of component ids?Portingale
@AlvinReyes I put a lot of logging in the code and the fail is definitely coming from the cpa.GetContent() call. I'm checking for nulls at all points but it's not finding any before the code errors. I've added more detail of my findings to the original post.Kopeisk
@Mike - For the CP assembler to work you need bin/conf/cd_wai_conf.xml and bin/lib/cd_wai.jar (see my comment under the question) - this may be the problem hereSupercharge
As you say Will, the absence of a WAI config could be a problem, or indeed that (a misconfigured) one exists, and now becomes relevant.Muskrat
Thanks @Will, it took a bit of fighting and code rewriting for this to work nicely, but it's pretty much as you originally stated. I've used the ComponentPresentationAssembler and it's working and resolving the links as expected. Thanks to you all for your help with this.Kopeisk
@Supercharge - I've changed my accepted answer to Ryan after reviewing what he'd written. It was the fact that I had changed the namespace I was referencing which solved the main issues and allowed me to implement the code correctly. Your answer did get me on the right track however so I'd love to be able to mark both as accepted answers. Cheers, MikeKopeisk
S
11

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

Skeptical answered 11/5, 2012 at 17:47 Comment(3)
Cheers Ryan, I've marked Will's answer as the accepted answer as he was right with the use of the ComponentPresentationAssembler but it was really handy to have the list of things required in order to ensure everything was in place for this to work. Cheers!Kopeisk
Actually, looking at this again, I think that your answer is actually the reason that I managed to fix this. It turns out the error I was getting regarding ClassNotFoundException (see Update 2) was due to the fact that I was using the wrong namespace for the ComponentPresentationAssembler. Changing to the Tridion.ContentDelivery.WAI namespace fixed this issue and allowed me to get the code working completely. Apologies for missing that important part when it came to marking correct answers.Kopeisk
Unless I'm otherwise mistaken, you'll have to make sure that you have a license to use the WAI functionality. Just a note... I wouldn't want anyone to implement this and then find out they don't have the necessary Tridion licenses!Canea
W
10

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.

Wedding answered 10/5, 2012 at 12:19 Comment(0)
C
9

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);
}
Caliche answered 10/5, 2012 at 11:12 Comment(2)
-1 because Tridion has out-of-the-box support for doing this with the ComponentPresentationAssemblerMuskrat
Thanks Dominic. I was not aware of the ComponentPresentationAssembler. You learn something new everyday.Caliche

© 2022 - 2024 — McMap. All rights reserved.