How to access transformed html page in Custom Page Deployer? - tridion

Let's say we have to access the content of our published page in a Custom Deployer.
This part of the code is inside the processPage method that is in our CustomModule that extends PageDeploy class.
This way I will get the page that is being published, but content of that page will not be transformed (components that are in that page are not rendered).
public void processPage(Page page, File pageFile) throws ProcessingException {
File file = new File(pageFile.toString());
}
If I know that I can disable cleanup of the TransportPackages in cd_deployer.conf.xml, by changing the Cleanup to false: <WorkFolder Location="C:\tridion\work" Cleanup="false"/>,
I see that Tridion generates two versions of my page:
root\page.html (that has unrendered content, with path pageFile.ToString())
root\transformed\page.html (that has complete content - content that I want)
Why then when I create new File with the transformed page file path and read it, I get html code with even less content then the original html? Is this because in this phase of the deployment page is still not rendered and complete or...?
Thanks!

Is your page using Dynamic Component Presentations? If so, the Page-level HTML that is published and deployed will only contain an "include instruction" for the Component Presentation
<tcdl:ComponentPresentation ... />
The only thing that happens during deployment is that the "technology agnostic" language used during publishing/transport is translated into either a JSP tag or a ASP.NET server control include, in both cases it typically translated into something starting with tridion:ComponentPresentation.
The HTML fragment of the Dynamic Component Presentation itself will be published separately and stored as a separate item in the configured storage.
The complete HTML will only be composed when the page is requested (for serving to a visitor). At that stage the JSP tag library or ASP.NET server control will be invoked, read the HTML fragment for the Component Presentation from the storage and inject it into the HTML "wireframe" of the page.
With that knowledge, it indeed explains why you can't find the HTML fragment for the Dynamic Component Presentations in your Deployer extension: the merging of the DCP fragments into the Page shell only happens when the page is requested, not when it's deployed.

Related

Tridion ASCX DCP does not render child control

When publishing dynamic component presentations using SDL Tridion 2011 SP1, I mostly use REL as the output format, however I now want to publish a DCP that contains an ASP.NET control tag. I therefore changed the output format of the template to ASCX, and configured the storage for ASCX component presentations to go to the file system within my web application. I can see the ascx files on disk, and as expected, I can see the control tag inside.
If I create an aspx page that contains the same control tag, the output is as I expect, however, when the ASCX component presentation is executed by the component presentation assembler, instead of rendering the output from the control tag, it comes up blank. Plain text within the DCP does show up.
The functionality I need is very similar to a Tridion Dynamic Component link control, and I had already tried one of these with this architecture, and succeeded. I've even gone as far as putting both my tag and the tridion one, one after the other, in the template. In this case I see the output from the tridion tag, but not from my own, even though the references are wired up in the same web.config.
So I can see that it is possible to have Tridion's component presentation assembler execute an ASCX DCP and successfully render its child controls. Are there perhaps requirements when authoring such a control to ensure that it can be rendered in this way?
UPDATE:
The DCP is published to an ascx file within my site. For test purposes, I am now publishing the tridion control in the same DCP, so the output on disk looks like this:
<tridion:DynamicComponentLink PageURI="tcm:34-667-64" ComponentURI="tcm:34-876"
TemplateURI="tcm:34-864-32" LinkText="Some page" runat="server" />
<xxx:ComponentLinkQS runat="server" ComponentUri="tcm:34-945"
QueryString="item=876" Text="Some page" />
When the DCP is published like this, and executed by the ComponentPresentationAssembler the first control produces the expected output, and the second one doesn't. If I place a <xxx:ComponentLinkQS/> tag directly on an ASPX page, it renders fine.
I think that I've seen this before (full credit for the solution goes to Neil Gibbons and Hoang Chu).
The problem is caused by the ComponentPresentation server control inside the Tridion.ContentDelivery DLL and in particular the way this control loads in the DCP user control during it's Render method:
protected override void Render(HtmlTextWriter writer)
{
if (HttpContext.Current != null && HttpContext.Current.Application != null)
{
ComponentPresentationAssembler componentPresentationAssembler = new ComponentPresentationAssembler(this.pageUri, base.Page);
writer.Write(componentPresentationAssembler.GetContent(this.componentUri, this.templateUri));
base.RenderChildren(writer);
}
}
The Render method is too late in the control life-cycle for any other controls to have their events wired up - hence my user controls Page_load is never triggered.
There is a solution proposed for this on the Tridion forums on the link below which involves overriding the standard Content Delivery user controls to execute your embedded controls earlier in the life cycle: https://forum.tridion.com/topic.asp?TOPIC_ID=5709&whichpage=3&SearchTerms=Page_Load
(I am not sure about the legalities of copying code from the forums and adding it here. If someone from Tridion gives me the nod then I can add it in.)

Custom Server Control and Image Handling

I am currently trying to create a custom server control in asp.net c# and am using VS2010.
I am trying to create a custom server control that can load images straight into a separate web project. E.g. Custom Server Control and a separate web project where I can drag and drop my control onto it with minimal installation and config. The point being it can be re used anywhere on other web projects.
I have created a basic custom control, but I need to be able to load images directly through the custom server control and display them in my separate web project. The images will be coming from a static location for the time being.
So basically I have an image, I want to load and pass that image into the control and then display it on a webpage where the custom control is placed. I have investigated image handlers, and having separate generic handlers but am not having any luck.
Image location --> Custom Control --> Web page displaying image that has been passed into custom control.
Anyone have any idea how to do this, or go about this?
UPDATE:
I am sorry I was not clear enough first time round.
I have two projects, one custom control project, and one asp.net website project. The first project (Custom Control) takes a byte stream from a webservice and converts it to an Image object. At this point I want the control to add that image to a webpage in the website. The custom control is then registered with the asp.net website and the controls I have added are rendered to the page. However I want to render the image I have recovered from the buffer, then converted to a file locally onto the web page.
I have no problem getting the image from the bytestream, and storing the image in a directory. The issue I am having is that I want the image to be rendered on the webpage, without having the image stored in the web project at first. I have thought about storing the image in a web directory so when I run the project I can set an image url to localhost/images/myimagefrombystream.jpg but am unsure whether this is the correct approach.
Any ideas?
We have a server controls library that contains some images that are reused across a number of other web projects.
The approach we took was to mark the each images build action as Embedded Resource. Then in the AssemblyInfo file we have lines like the following:
[assembly: WebResource("AssemblyName.SubDirectory.ImageName.png", "image/png")]
Where AssemblyName is the actual project name, the SubDirectory is the directory in the project the image(s) are located in, etc.
This project also emits CSS files; which are also Embedded Resources. The CSS files refer to these images using:
.someImage {
height: 85px;
background-image: url(<%=WebResource("AssemblyName.SubDirectory.Image.png") %>);
background-repeat: repeat-x;
margin: 0px;
padding: 0px;
}
In the class code, we'll refer to those css files like:
HtmlLink cssLink = new HtmlLink();
cssLink.Href = Page.ClientScript.GetWebResourceUrl(this.GetType(), "AssemblyName.css.SomeCssFile.css");
cssLink.Attributes.Add("rel", "stylesheet");
cssLink.Attributes.Add("type", "text/css");
We could just as easily refer to the images directly using something like the above.
At this point the assembly is 100% portable. All of the CSS files and required images are embedded into it so you don't have to worry if the calling application has those same images at all.
Incidentally, this is how a number of control vendors do things; at least the better ones.
I don't know why you're complicating. Simply, add ImageUrl property (not public field) to your custom control, expect the client-code of your control to set it, and if not null, in CreateChildControls add an Image control to the control tree. Alternatively, add the image to control-tree always, but make it visible/invisible from within the setter of that property (or elsewhere you see fit). I didn't understand half of what you said related to your envisioned solution, to be honest - so, I hope I didn't miss the topic here :)
I'm not sure I understood the question, but let me try anyway.
As far as I understood you have two projects, in one you want to upload an image to a certain location, in the other one you want to show that image.
I would simply have a file upload control in the 1st application, and use it to upload the image to the desired location.
In the other application you can use a generic handler. The handler can get the image file name from the 1st application using query string parameters, then it will locate the image on disk and return a response with a proper header, for example:
response.ContentType = "image/jpeg";
response.OutputStream.Write(image, 0, (int)request.InputStream.Length);
response.Flush();
response.End();
I assume that you have created this custom control in a class library. of the image source is static (some fixed base url) and just that image name changes you can expose a ImageUrl property (string) and render a tag based on the attributes (all can be default) with the custom ImageUrl as the src attribute of the tag.
Hope that helps!

ASP.NET 2.0 -how do I include files containing server-side code?

I want to be able to load a customized log in page depending on a couple of parameters passed into the querystring.
Each customized login page needs to be able to dynamically display log in errors and possibly have other variables passed in.
Let's say the dynamic login page looks like this (over-simplification here):
<form>
<% if (has_errors) { Response.Write(error_msg); } %>
<input type="text" name="email">
</form>
If the aspx page loads the file like this:
Response.writefile("path/to/custom/page");
the code shows up in the output and doesn't get processed. I have tried other ways to load the file contents (something similar to classic ASP includes) but get the same results every time.
I could have all the custom pages set up as user controls, but I need 100% control over the css, js, and html - and the documentation I read here indicates that I won't have that level of granularity.
link text
PLUS - I'm stuck in a .net 2.0 environment - so .NET MVC is not available to me
Any help/suggestions?
but I need 100% control over the css,
js, and html
You won't get 100% over the page but you will have control inside the User Control instance. Also, many times, you can override these technologies like CSS, from within your control.
In the end because all controls are solified into one big HTML page you will have the same level of control as you would in any single web page with client-side technologies.
You can build a Web UserControl to represent log/in and then include an instance of that control onto any page, in any place, across multiple pages if you wish.
(See the Topics on that MSDN help page about how to create and use it).
Other useful references (these are various angles on the same subject).
Creating a Web user Control in .NET
ASP 101 - User Controls
This should provide a good start to keep looking, if this is the kind of info you think you need.
Internals
The User Control can have its own logic, access the browser querystring, access the page Session, Application, etc. pretty much anything it needs to know for itself to work.
Object Oriented
Additionally, because a User Control is also an object, you can add your own public methods and properties to it through which you can interact to communicate with the control intance on the page (just like you interact with other web controls like Button.Text="click", TextBox.BackColor = System.Drawing.Color.Blue, etc).
Other Options - Dynamic control loading
You might want to consider loading controls dynamically at runtime using the Page.LoadControl(..) method:
Loads a Control object from a file
based on a specified virtual path.
MyControl myControl1 = (MyControl)LoadControl("TempControl_Samples1.cs.ascx");
PlaceHolder1.Controls.Add(myControl1);

Write binary data as a response in an ASP.NET MVC web control

I am trying to get a control (not a controller -- a subclass of System.Web.UI.WebControls.WebControl), that can be used that I wrote for ASP.NET to work in an ASP.NET MVC environment. Normally, the control does the normal thing, and that works fine
Sometimes it needs to respond by clearing the response, writing an image to the response stream and changing the content type. When you do this, you get an exception "OutputStream is not available when a custom TextWriter is used".
If I were a page or controller, I see how I can create custom responses with binary data, but I can't see how to do this from inside a control's render functions.
To simplify it -- imagine I want to make a web control that renders to:
<img src="pageThatControlIsOn?controlImage">
And I know how to look at incoming requests and recognize query strings that should be routed to the control. Now the control is supposed to respond with a generated image (content-type: image/png -- and the encoded image). In ASP.NET, we:
Response.Clear();
Response.OutputStream.Write(thePngData); // this throws in MVC
// set the content type, etc
Response.End();
How am I supposed to do that in an ASP.NET MVC control?
You could create a custom ActionResult. Here is a link to a blog post for creating a custom ImageResult class that subclasses ActionResult. http://blog.maartenballiauw.be/post/2008/05/13/ASPNET-MVC-custom-ActionResult.aspx

How to create another page class in a aspx c# page

Results r = (Results)Page.LoadControl("Results.ascx");
In my Page i cannot access USER CONTROL CLASS(Results)
Gives error.I cannot resolve.
No namespaces at all.
Even i cannot access other aspx class in same folder's other page also..
Can you please help me.
ASP.NET compiles pages in batches, and there's no way you can be sure that your currect page is compiled with the Results page. You need to define an interface that you store in App_Code (which all pages are compiled with), implement this interface in your Results page, and use the interface to access whatever you're trying to do.
You could move logic from your Results page into your domain, or into a helper class, instead of keeping it in the view (the page).

Resources