Kentico Web Part Zone(s) generated by Transformations - asp.net

I am using a Repeater web part in Kentico to pick out pages from the content tree, to generate nicely repeatable snippets of structured HTML, based on an ASCX transformation. (No surprises here - its been working great!).
However, a new requirement landed whereby alongside the existing HTML structure mentioned above, each repeated item must also have an area where we can add any amount of additional content; based on other web parts.
I have previously written a few "layout" type web parts; implementing CMSAbstractLayoutWebPart, as described here, which has allowed me to generate a repeating amount of web part zones, so I feel like I'm half way there. The issue with that though is that as it stands, I don't seem to be able to make use of the great power and flexibility of the transformations on the page type (which I really think I need to do, and seems like it should be possible..).
I thought I may be able to specify the WebPartZone control in the transformation markup directly, like in the following:
<%# Register Src="~/CMSInlineControls/WebPartZone.ascx" TagName="CMSWebPartZone" TagPrefix="cms" %>
<cms:CMSWebPartZone ZoneID="ZoneIDHere" runat="server" />
<div>
<h3><%# Eval("Heading") %></h3>
<p><%# Eval("Summary") %></p>
</div>
But the design view doesn't seem to pick up the web part zone; so I'm assuming the page lifecycle may not allow me to do this as I'd hoped.
So what I would like to know is:
Is it possible to include WebPartZone control in a transformation such that I can then bring in new web parts in Design view?
If not, what is the recommended way to go about this? (If a custom web part is the way to go, I'd like to clone the Repeater web part in the first instance, as many of its existing properties will be needed - but presumably this must still inherit from CMSAbstractLayoutWebPart?
Thanks!
Update
Good point about the editor's experience; I would definitely like to keep this as consistent as possible. The issue for me is that the requirements that drive my data structures are not always fully understood - and are certainly subject to change. Also, they are liable to vary (albeit subtly) across different products. So I've been trying to keep templates and page types more or less the same across the board, and push out the differences into page properties that drive web part config through macros. So given that the transformation approach won't work, I expect a custom web part is the right fit for me.
I shall post my findings!

I think adding a web part zone into transformation is not a right direction as web part zone should be a part of page template (not transformation) in order to utilize it.
I'd probably try to organize my content so each item you currently showing in the repeater has any number of child pages (potentially of a different type) and use something like hierarchical viewer in order to present all of them on the page. It allows using different transformation based on either page type or node level. Another advantage of this approach is that you keep editors experience consistent.

In the end, I was able to use transformation markup to specify the generation of web part zones. I went down the route of creating a custom web part that inherits from CMSAbstractLayoutWebPart, rather than using CMSRepeater web part or similar...
Here's a breakdown of things I needed to do this:
Gave the custom layout-type web part some properties with which to query the content tree, and supply them to a TreeProvider.SelectNodes() method in the web part code once it has initialised (by overriding the OnInit() method)
Gave the web part a TransformationName property so that the raw markup can be retrieved using TransformationInfoProvider.GetTransformation(this.TransformationName)
Used the markup above and resolved macros within it using each node from the node query
Example of macro resolution code (HTML transformations with macros)
protected virtual string ResolveNode(TreeNode node)
{
var resolver = this.ContextResolver.CreateChild();
resolver.AddAnonymousSourceData(node);
return resolver.ResolveMacros(rawTransformationMarkup);
}
Then I go looking for placeholder text in the transformation markup and use the methods available in the CMSAbstractLayoutWebPart parent class(es), as detailed here, to Append() the resolved markup and also call AddZone() as necessary to tap into the response string builder
Summary: The great functionality of the API allowed me to completely avoid the use of any repeater controls. I could generate web part zones as part of the layout web part usual layout generation process.
It would be nice if I could figure out how to resolve the expressions in SCRIPT tags in ASCX transformations to complete the story, but by using HTML transformations I can use the above to accomplish what I need.

Related

Convert query parameters to "pretty urls"

I have an Episerver site with a JobDetailsPageController with a Index method that takes a jobId parameter and creates a view with some details about that job. The urls looks something like this: https://hostname/<root-depending-on-site-tree>/jobs/?jobid=44.
What I would like is having urls on the form .../jobs/manager-position-telco-44, essentiallly creating a slug of the job title and appending the id. I have done this in the past using standard ASP.NET MVC Attribute Routing on a non-Episerver site, but EpiServer has a routing of its own that I don't know too well and can't figure out.
Also, adding non-query strings after the slash consistently sends me (no surprise) to a 404 page, so I would need to somehow customise this behaviour. I need to use EpiServers standard routing to end up at the right "parent", but ignore the latter part (the pretty bit).
Is it possible to create such urls on a normal page in page tree in EpiServer? I do understand it is possible to create static routes, but this node can be moved around like any other page so I cannot avoid EpiServer.
Please see this blog post. What you're looking for is partial routing.
#johan is right, partial routing is one way of doing this. Just wanted to add other possible solutions that might or might not match your needs.
Import data as content
Instead of serving content dynamically, you could consider importing your job ads from whatever source you have directly in content tree as separate pages below particular root page. That would give you a lot benefits - pages would be cached, it would support multiple languages, editors would see content directly in EPiServer CMS, data could be adjusted manually, etc.
This would be a good solution if your data does not change often and you need to provide a way for editor to create a new job ad manually as well.
Implement you own content provider
Another way to serve your dynamic data to EPiServer is to write your own custom content provider. You can find documentation here: http://world.episerver.com/documentation/Items/Developers-Guide/Episerver-CMS/7/Content-Providers/Content-Providers/
This solution requires more coding and is more complex, but it has some benefits as well. If one wanted, it would be possible to not just serve content from external data source, but also update that data by changing values directly in EPiServer UI.

When creating web pages, what is the recommended approach for Add/Edit?

Lets say you are developing an web app that requires that you are able to Add/Edit items. The item form contains several input control. Would you separate the add/edit pages or use the page for add/edit and control via querystring (i.e. ItemAddEdit.aspx?isEdit=1)
The advantage I see in separating is that it is easier for the (non-technical) user to type the page and to determine whether it is add or edit. Also, when there would be specific changes to each page (if ever), it would be easier to change.
For the single page, well, you reuse code which eliminates some duplicate code and avoid possible problems.
And no, I can't use routing.
This is generally something which could be a subjective thing, because there's as many ways of doing things as there are coders, and a lot of it can be depending on how your system is set up generally.
But, if I were to recommend, I'd say the way you should do it if working with asp.net web-forms is to make two web pages (add/ edit) and then you use a user-control on those to group up the shared logic between the two pages. After all - that's why we have user controls.
In this way you can have both of your situations, by keeping logic in one file/class, but still have two entry points.
This would also mirror more how MVC does it, which could be considered a plus.
That being said - if your administration functionality is behind login etc, there's nothing to hinder for actually doing it in one and separate with the query string approach, and then just load the data if editing or display "empty"/base data when creating.
You shouldn't have the user type the addresses anyway, but click through the links to follow your flow, so the query string should be a minimal issue.
But for the sake of keeping your functionality clean and divided, I'd personally recommend going for two page / usercontrol approach.

How to keep DRY a Ajax web forms solution

At the moment we have a solution which is Web forms ASP.Net 4.0. We do a number of things such as using web methods and services either calling them using the standard web forms way or sometimes to reduce the footprint directly calling them with jQuery ajax posts and gets.
We are looking to improve the way we work but we have heavy constricts regarding how the solution is at the moment and not being able to completely rewrite it.
Updating the page using Ajaxs for data, forms and for example pulling "the next 20" items and displaying them on the page it what I would like to heavily stream line.
Using template's due as PURE and jQuery Templates is fantastic way to produce fast calls back and forth between the servers but results in having two copies of the html. (the template for the jQuery and the code in the actual first render of the page)
We have thought about possible producing a empty template and then always populating it via json data we post down to the server but I feel this isn't how things should be done...
can anyone reckoned the best way we can do this without having two copies of our 'template' (e.g. a row of a table)
You mean you have a template in asp and the same template in javascript, but you'd rather just have 1 or the other?
I think that is really subjective. It is always different based on use case. That being said I'd do it by modifying my views and templates. My views (non-js) would simply have containers for that dynamic content. In other words I'd never load the dynamic portions of content into the views initially. Rather, on page load I would simply load up the template and the json that fills it in.
If you think about it that's 2 more requests, but it makes your life easier. The user also is able to see something on the page sooner.
This is one of those questions that really depends on what you are doing. There are trade-offs to be analyzed with every solution.

How to make embeddable code in ASP.Net

you must have seen widgets like code which people place inside their HTML and it starts showing a small widget in there, how we can we do it in ASP.net, for example if i want to show some specific data of my site to anywhere some specific code is placed, how can i generate that embeddable code that can start showing my specific block of data to anywhere from any site?
Here are a few methods used by various people to embed a snippet of content on an external website.
1) An iframe!
iframe's can be a right old pest, but are quite good at displaying a bit of external content. They have been added back into the HTML standards in the HTML 5 draft specification, so you should get futureproof support for them in the future.
<iframe src="http://www.widget-address.com/Widgets/SomeWidget/" title="Some Widget"></iframe>
You can style your iframe (give it a width and height) and all that jazz.
2) External Image
This is largely used by advertising engines. You pop an image on the page and the image is dynamically created to display some advert - each time it appears it is different. This isn't great if you want information to be screen-readable (i.e. accessible).
<img src="http://www.widget-addrees.com/Widgets/SomeWidget.jpg" alt="Some Widget">
3) Server Side API
You could make an API available so people can call a "service" on your site that supplies them with the information for the widget. For example, their ASP.NET code or PHP code (or whatever language) calls http://www.widget-address.com/Widgets/WidgetService/ and it returns some data that they can format and display on their page. This would give you the benefit of inline HTML, which is the most accessible and valid way of displaying the data.
There are lots of other methods, so if you don't fancy one of these, I'm sure more suggestions will flood in - including (be careful...) JavaScript / AJAX.
I'm not quite sure I understand the question, so I'm sorry if I'm way off here. But I guess you are using the webforms framework for asp.net? If you are there is something called server controls. Those can be used to create widgets like calenders for example (that is already included in the framework, so no need to build it again).
If you are looking for code block, similar to <?php [[code]] ?> in php (if you have used that), then the answer is <% %>. Those are code blocks in the .net world. If you want to write something out you use Response.Write("string to write"); inside the code block. Or you can use the faster way: <%="string to write"%> that will render the same think (string to write).
If you are using the webforms framework you can also take advantage of the built in server controls in the framework. You can read more about the framework here or simply google asp.net webforms.

Strategic Advice: Upgrading the Design of a Web App

I have an ASP.NET web site dedicated to reporting on PBX extension stats. It comprises many report pages, with HTML generated almost purely by code-behind (setting a Label control's Text property instead of using Response.Write), using un-parameterised string literal SQL queries that populate By Reference DataTable parameters.
Maintenance pages at least comprise DataGrids and detail forms, but use the same DAL, on e thing for which can be said is that it supports multiple DB servers, with sub-classes each overriding these access methods with their own string literal queries.
What do I need to consider cleaning up this mess? I've already made an almost obvious decision to use a third party reporting solution, and move the queries to stored procs in their respective DB languages, narrowing the diversity of the different DAL classes, and to separate CSS out to shared files, as lots of it is very hidden in C# files!
For your back-end design, I suggest having a class to represent each main table of your database (i.e. a Report class and a User class, for example). Anything that's not an event handler should go in the back-end class files / namespace.
For your GUI, looks like you're on the right track using ASP.NET controls instead of just streaming your data out to the user. However, you may consider objectifying the areas of the page. For example, one of my favorite tricks is to open semitransparent "popup" panels when requiring user input or a something like the Information Bar when displaying a short message.
Consider AJAX and the AJAX Control Toolkit. It's easy to implement (especially in the case of a rewrite) and provides great flexibility. Specifically, I've found Accordions - sometimes even nested within other Accordions - are excellent at organizing overabundances of information.
Edit:
Note that if you were to use AJAX, you basically can't even consider using response.write anymore.
As far as having too much content on the screen, remember Panels have a "Scrollbar" property and DIVs don't without some heavy changes.
Also, I tend to separate my code files by Namespace; but the popular trend is to do so by Class. This is a better option if you have many Developers or if it's likely several classes within a namespace will be checked out or simultaneously modified by different people.
I would consider ditching any custom written DAL and use one of:
iBATIS.NET
NHibernate
SubSonic
You might even end up dropping sprocs entirely.
If you're daring you could try the redesign using Microsoft's MVC implementation.
Whatever approach you take, make sure you write unit tests prior to refactoring any code, verify the tests pass before and after refactoring.

Resources