19 February, 2015

Error pages in DD4T (404 and 500)

In DD4T the 404 page can be retrieved as below, Override the Action Page, and when the Page is null return the NotFound Action. In the NotFound action, Query the Broker for the 404  page and return the view.


The 500 Error page can be throw from the Global level as below, when error occurred handle it the global level and return just view with error information



23 January, 2015

DD4TFormRouteHandler (posting a form as tridion page url)

ASP.NET routing enables us to use URLs that are not physical files, In DD4T we have the default page route definition. In which all page request redirct to Page controller and process the page.
DD4TFormRouteHandler is a custom route handler responsible for mapping incoming browser requests to particular MVC controller actions, this works along with DD4TFormHelper (that generate the route information for the form)
Posting a form in DD4T is not complicated, you can create the mvc form as a normal controller and action, then post it via AJAX. But, when we need to do post the form as normal page, It would need a tweak as the controller/action is not a page existed in tridion. This can be achieved by implementing a custom Mvc RoutHandler and reroute the posted form to the encrypted action and controller. It works as below daigram.

So, how to do this. to render out the form we have BeginDD4TForm html helper as below that generate the form with encrypted route values.
@using (Html.BeginDD4TForm("Post""Contact"FormMethod.Post))
{ 
    @Html.TextBox("username")
    <input type="submit" name="submit" value="Submit" />
}
BeginDD4TForm is a helper in the custom class DD4TFormHelper, which is responsible for generating encrypted route information.
Once this is done, then we need to add the custom handler to read the route information and route to the proper controller and action instead of the tridion page, this is the responsibilty of the class DD4TFormRouteHandler. To use this add this handler in your default page router as below.
  //Tridion page route
            routes.MapRoute(
               "TridionPage",
               "{*PageId}",
               new { controller = "Page"action = "Page" }, // Parameter defaults
               new { pageId = @"^(.*)?$" } // Parameter constraints
            ).RouteHandler = new DD4TFormRouteHandler();
This is the important step (Register the custom route handler)

In the action of form, once form is posted redirect to the current URL, so that it will load the Tridion page once the form is posted.

Both the helper and RouteHandler source code is below.

DD4TFormRouteHandler.cs
DD4TFormHelper.cs

17 January, 2015

Handling images and on the fly re-sizing in DD4T

When it comes with DD4T we have plenty of control on the data and we can decided on how we wanted the page to be rendered.
The traditional approach of having difference size of same image is replaced in DD4T to have one single image and generate the thumbnail on the fly. In this approach, we will have only one image published in tridion, and rest will be created on the fly based on the request.

Just by adding below configuration on the web.config modules session will enable this feature
<modules runAllManagedModulesForAllRequests="true">
  <add name="BinaryModule" 
       type="DD4T.Web.Binaries.BinaryDistributionModule" />
 </modules>
The BinaryDistributionModule process the request as below
  1. Process the Binary Request
  2. Check if the file is already in the file system.
    1. If file is available compare the last published date of the binary against the broker.
    2. If the file is updated, update the existing file in the file system.
    3. If the file is removed, delete the existing file in the file system.
  3. If the file is not there in the file system.
    1. Query the broker and create the file on local file system
  4. Deliver the file.

The below Html helper method helps to generate thumbnails as below.
<img src="@Model.Fields["image"].LinkedComponentValues[0].Multimedia.Url.ResizeToWidth(150)" />
<img src="@Model.Fields["image"].LinkedComponentValues[0].Multimedia.Url.ResizeToWidthAndHeight(150,150)" />
This will generate the images as
<img src=" /images/sample_image_tcm4-102_w150.jpg" />
<img src=" /images/sample_image_tcm4-102_w150_h150.jpg" />

The width and height feature has a bug in the framework, you can extract the BinaryDistributionModule and BinaryFileManager Class from the DD4T.Web project and bit customization on the method "private string StripDimensions(string path, out Dimensions dimensions)" will solve the issue, This method can be found in BinaryFileManager.cs. Update this method as in below would work for both width and height.

Later update the web.config to use the updated custom Binary Module, instead of default one,

13 December, 2014

DD4T: Customizing RenderComponentPresentation

Sometime when we work with Component presentation, we might come up with the scenario to have customized RenderComponentPresentation, when we deal with Area/View or splitting view into more organized structure. We can fetch and send the area from the Template.
Currently DD4T doesn’t allow injecting the ComponentPresentationRenderer, instead it allows us to write our own renderer and call it along with RenderComponentPresentation as below


The custom ComponentPresenationRenderer can be created based on the scenario, so when we use the area, we could have the custom ComponentPresentation as below
SDL Reference implementation, customized Renderer beautifully and implemented the Renderor to use Area view concept.

25 November, 2014

Navigation in DD4T

There always been a question on What is the best approach for building navigation with DD4T and ASP.NET MVC?
Answer is: There is TridionSiteMapProvider as part of the DD4T.Mvc project, which can be used out of the box. The  DD4T.Examples.Templates project also have a example on how Sitemap can be generated from the template (TBB)
Many organization will have different kinds of navigation structure, It can be from very simple structure or it can be a heavily complex in nature. In this article you can see how the default SitemapProvider can be used and how we could customize to achieve complex Navigations like Megamenu or similar using TridionSiteMapProvider.

Setting up the default TridionSiteMapProvider

The only configuration you would need to do in web.config is set the your default sitemap provider is as below.
<system.web>
  <siteMap defaultProvider="TridionSiteMapProvider" enabled="true">
    <providers>
      <clear/>
      <add name="TridionSiteMapProvider" type="DD4T.Mvc.Providers.TridionSiteMapProvider, DD4T.Mvc"/>
    </providers>
  </siteMap>
</system.web>

By default the sitemap path url looks in /system/sitemap/sitemap.xml, or based on web config.

In the example project, you have an Html extension to render the sitemap, it will return just the Html list. This helper can be called as @Html.SiteMapMenu(MenuType.Top)

In simple, it works as below diagram.


Customizing the default TridionSiteMapProvider

The TridionSiteMapProvider out of box is handling most of the scenarios; Sometime when we work with Mega menu or complex navigation, we might have the situation to handle more data other than normal sitemap node attributes. Below I am intent to explain how we could customize the TridionSiteMapProvider.
I have a custom TBB which generate a sitemap.xml or navigation.xml looks something like below by navigating the structure.

<root>
  <node id="tcm:8-4450-4" title="010. Personal" url="/en/personal/" description="tcm:8-337-64" compTitle="Personal Site" vanityURL="">
   <navTitle>Personal</navTitle>
    <NavConf>
      <NavUseFulLinks>
        <UseFulLinks>
          <Links>
            <Title>Utility Links for Personal</Title><TitleComponentLink>tcm:8-1224</TitleComponentLink>
            <Links>
              <LinkText>Some Text</LinkText>
              <ComponentLink>tcm:8-1000</ComponentLink>
            </Links>
            <Links>
              <LinkText>Some title text</LinkText>
              <ComponentLink>tcm:8-1018</ComponentLink>
        </Links>
            <Links>
              <LinkText>Some Title Text</LinkText>
              <ComponentLink>tcm:8-1950</ComponentLink>
            </Links></Links>
        </UseFulLinks>
      </NavUseFulLinks>
    </NavConf>
  </node>
</root>

In above xml, I have additional Node named NavConf with some more utilities links, which are obtained from Page Metadata. In such scenarios we could add the custom property to TridionSiteMapNode and then we can customize our sitemap helper to return the custom view template based on request.

In above scenario I have add a new Property named NavConf, in the class TridionSiteMapNode, and then In the TridionSiteMapProvider.cs class, I have customized the CreateNodeFromElement method to looks like below,
SiteMapNode childNode = new TridionSiteMapNode(this,
element.Attribute("id").Value, //key
uri,
element.Attribute("url") != null ? element.Attribute("url").Value : "", //url
element.Attribute("title") != null ? element.Attribute("title").Value : "", //title
element.Attribute("description") != null ? element.Attribute("description").Value : "", //description
null, //roles
attributes, //attributes
null, //explicitresourceKeys
null
)
{
Level = currentLevel,
NavConf = element.Element("NavConf") != null ? element.Element("NavConf") : null
}; 

The default navigation Helper class can be customized more generic so that we can customize the html in the view rather than in the Helper class. The extension CreateHtmlHelperForModel below will return the template view from the shared template folder based on the request e.g: Top, Left or Full. Only concern is you should have the below views on the Shared folder, because the Template will look for the view in DisplayTemplate Folder.

Creating NavigationHelper class


  public static class NavigationHelper
  {
      
        public static MvcHtmlString Navigation(this HtmlHelper helper,SiteMapNode rootNode, IPage page, NavigationTypes navigationType, string navigationXml = "/system/include/navigation.xml")
        {
            var langauge = helper.ViewContext.RouteData.Values["language"] as string;
            navigationXml = string.Format("/{0}/{1}", langauge, "system/include/navigation.xml");
            string template = string.Empty;
            switch (navigationType)
            {
                case NavigationTypes.Top:
                    template = "TopNavigation";
                    break;
                case NavigationTypes.Left:
                    template = "LeftNavigation";
                    break;
                case NavigationTypes.Right:
                    template = "RightNavigation";
                    break;
            }

         //   XmlDocument model = Utilities.GetXmlFile(navigationXml);

            var navigationHelper = new NavigationHtmlHelper(helper);
            return navigationHelper.CreateHtmlHelperForModel(rootNode).DisplayFor(x => rootNode, template,
                new
                {
                    NavParent = page.StructureGroup.Id,
                    PageUri = page.Id,
                    PublicationUri = page.Publication.Id
                }
            );
        }
    }

    public enum NavigationTypes
    {
        Top,
        Left,
        Bottom,
        Right,
        Breadcrum,
        Title,
        Canonical
    }

    public class NavigationHtmlHelper
    {
        /// <summary>
        /// Gets or sets the HTML helper.
        /// </summary>
        /// <value>The HTML helper.</value>
        public HtmlHelper HtmlHelper { get; protected set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="MvcSiteMapHtmlHelper"/> class.
        /// </summary>
        /// <param name="htmlHelper">The HTML helper.</param>
        /// <param name="provider">The sitemap.</param>
        public NavigationHtmlHelper(HtmlHelper htmlHelper)
        {
            if (htmlHelper == null)
                throw new ArgumentNullException("htmlHelper");

            HtmlHelper = htmlHelper;

        }

        /// <summary>
        /// Creates the HTML helper for model.
        /// </summary>
        /// <typeparam name="TModel">The type of the model.</typeparam>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        public HtmlHelper<TModel> CreateHtmlHelperForModel<TModel>(TModel model)
        {
            return new HtmlHelper<TModel>(HtmlHelper.ViewContext, new ViewDataContainer<TModel>(model));
        }
    }

    public class ViewDataContainer<TModel>
       : IViewDataContainer
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ViewDataContainer&lt;TModel&gt;"/> class.
        /// </summary>
        /// <param name="model">The model.</param>
        public ViewDataContainer(TModel model)
        {
            ViewData = new ViewDataDictionary<TModel>(model);
        }

        /// <summary>
        /// Gets or sets the view data dictionary.
        /// </summary>
        /// <value></value>
        /// <returns>The view data dictionary.</returns>
        public ViewDataDictionary ViewData { get; set; }
    }
In the view, we can have something like below as simple or as complex as based on requirement.

@model TridionSiteMapNode
@if (Model.HasChildNodes)
{
    <ul>
        @foreach (TridionSiteMapNode node in Model.ChildNodes)
        {
            <li><a href="@node.Url">@node.Title</a> </li>
        }
    </ul>
}

In short, we can easily customize the TridionSitemapNode to use it as they way we want for simple or complex navigations.

20 November, 2014

What is DD4T

Well, It's the high time to think about DD4T. What is DD4T? What makes more easier to the developer and Editor to talk about DD4T.!!  DD4T is a framework that developed by Tridion veterans. The framework makes it easier for Tridion developers to develop, deploy and maintain a project.

The basic building blocks of Tridion  like, schema, components, template etc. are still remain the same as below.

So what changes, if you look at the below diagram, you could see the different between both
So, the whole logic goes to the web server, CMS just plays the role of generating the pages and delivering it to the Broker, no Template logic or HTML in CMS any more. DD4T solves the problem by making sure the pages and content are published to the broker as data, without any HTML rendering.


If we summarize the diagram.
1) The role of editor and visitor are normal, and that is the main aspect of DD4T architecture.
2) Everything is published to the broker database.
3) Tridion templates uses DD4T to generate XML.
4) DD4T generate the html, not the templates
5) Web application has the complete role and logic for generating the html
6) Doesn't needs to be expert in tridion, Just a .NET developer can be done.
7) In simple the release can be managed well.
8) No dependency with templates.

14 November, 2014

Dynamic Publication Resolving in DD4T

DD4T is a great framework which would give you everything in place what you basically needed. Here we will see how we could resolve the publication based on the URL,  when we work with multiple publications accessing same web site, our DD4T would need to query dynamically to different publications.

Many times it can be based on URL, based on the domain or language we could resolve the publication. It’s obviously up to us how we implement it.

By default the DD4T framework queries the publication that we have mapped in the key: <add key="DD4T.PublicationId" value="7" /> or keep it 0 to query all publications

We can make it dynamic simply by implementing the IPublicationResolver class

Step 1: To resolve publication dynamically, we can write a class that implement DD4T.ContentModel.Contracts.Resolvers.IPublicationResolver


namespace Indivirtual.DD4T.Mvc.Resolver
{
    public class SitePublicationResolver : IPublicationResolver
    {
        public int ResolvePublicationId()
        {
            switch (HttpContext.Current.Request.Url.Host)
            {
                case "daimler.com": return 5;
                case "daimler.ae": return 7;
                default: return 5;
            }
        }
    }
}

It can be programmed either with domain or url, like daimer.com/en or daimer.com/ar, based on the scenario
Step 2: Add the resolver in the PageFactory in Ninject dependency


            Bind<IPublicationResolver>().To<SitePublicationResolver>();
            Bind<ICacheAgent>().To<DefaultCacheAgent>();
            Bind<IPageFactory>().ToMethod(context => new PageFactory()
            {
                PageProvider = context.Kernel.Get<IPageProvider>(),
                ComponentFactory = context.Kernel.Get<IComponentFactory>(),
                LinkFactory = context.Kernel.Get<ILinkFactory>(),
                PublicationResolver = context.Kernel.Get<IPublicationResolver>()
            });

That’s all you have your resolver, Rest all like PageController class will remain the same. After implementing IPublicationResolver, any request to PageFactory first try to resolve the publication and then queries the broker.

14 February, 2013

ASP.MVC in Umbraco 6

Umbraco 6 brings new lots of improvements for developers, new datalayer, new API’s and complete support for Asp.net MVC 4. This means developers will have greater control, simpler code and higher productivity when developing with Umbraco.

As the umbraco blog says, in Umbraco 6 we have:

  • MVC support, 
  • Native Razor support
  • Strongly typed views  
  • Building custom controllers
  • Whole new shiny API
  • Customizing routes.
  • and many more..
Download the latest version 6.0.0. from http://umbraco.codeplex.com/releases .

Create a blank MVC4 Application, and add the downloaded files to the newly created website. so that it will make the debugging easier.

OR run NuGet Package Manager Command : PM> Install-Package UmbracoCms

Now we can enable the mvc in ~/config/umbracoSettings.config 

<defaultRenderingEngine>Mvc</defaultRenderingEngine> by default it will be web forms change it to Mvc.

Add another blank MVC4 project to the existing project, and add reference to umbraco.dll, businesslogic.dll, and interface.dll. these dlls can be found in umbraco bin folder, and now are ready to create controller, or business logic that we will be using in our Umbraco project.

Create the controller that inherits from SufraceController, and add the logic what you would like to see in your page.
e.g: 
public class CommentsController : Umbraco.Web.Mvc.SurfaceController
{
        [HttpGet]
        public ActionResult Comments()
        {
            List<CommentViewModel> model = LoadComments();
            return View(model);
        }
}

Add a partial view to render this model, Build the MVC project, and copy the dll, and Views to Umbraco Bin and Views folder.

We are set now, add the controller, as action in the Umbraco Template. You could see the created controller and view getting fired on the Umbraco Page.

More information can be seen at http://our.umbraco.org/documentation/reference/mvc/

05 July, 2012

pjax with MVC, and form post like pjax

Last weekend I was working on a interesting project, and came across an interesting JavaScript library called pjax.

More information on pjax:

https://github.com/defunkt/jquery-pjax/

http://pjax.heroku.com/

pjax loads HTML from your server into the current page without a full reload. It's ajax with real permalinks, page titles, and a working back button that fully degrades, It just enhances the browsing experience.

I just loved the way we could use it with MVC; Below code sample explains how we could use the
same with MVC.
Clientside code would look as below:


    

Since the Form post is not handled with pjax, we can do a work around as below.


Updated _ViewStart.cshtml as below:
@{
    if (Request.Headers["X-PJAX"] != null || Request.Headers["AJAX-FORM"]!=null)
    {
        Layout = "~/Views/Shared/_PjaxLayout.cshtml";
    }
    else
        {
        Layout = "~/Views/Shared/_Layout.cshtml";
    }
}

_PjaxLayout.cshtml page content can be as simple as abelow
@{
    ViewBag.Title = "_PjaxLayout";
}
@RenderBody()

28 June, 2012

Why not to have a static const in c#

This is just a thought, that I was thinking why can't we have a constant with static in C#, and the answer is 'NO'; That we cannot have a static constant; e.g: I created a class as below:
 public class Constants1
    {
        public const string Const1 = "Hello";
        public const string Const2 = "World";

        public static string Static1 = "Hello Static";
    }
When we compile the program into IL, the C# compiler does a magic in IL, that the constants converts into static literals, of course it has to, that's why we are able to access the constants as Constants1.Const1