Friday, 27 June 2014

Alternative way of using RedirectToAction() in Sitecore MVC

Leave a Comment
Today I’ve noticed a post in Sitecore SDN forum regarding RedirectToAction() is not working in Sitecore MVC. In this blog post I am going to explain how we can redirect to regular MVC controller action in Sitecore MVC project. We cannot use RedirectToAction() in Sitecore MVC as it interrupts the page rendering process in Sitecore. See below diagram made by David Morrison to get the overview of Sitecore MVC Request Pipeline Execution Lifecycle.
For the demo purpose; I’ve created a controller rendering GetBook which will get the book id using data source and will display specific book details. If data source is set to null then I’ve to redirect to Error Page (or Redirect to anywhere as per your requirement).
Below are the few ways to perform redirection (returning/rendering a view) in Sitecore MVC:
  1. Redirect to specified URL (Sitecore Page / ASPX Page / External URL) using Redirect(): Redirect() tells MVC to redirect to specified URL instead of rendering HTML. In this case, browser receives the redirect notification and makes a new request for the specified URL. URL in the browser's address bar gets updated. This acts similar to Response.Redirect() in Asp.Net WebForm. Moreover, Redirect() also cause the browser to receive a 302 redirect response status code within your application.
    public ActionResult DisplayBookDetail()
            {
                string DataSourceId = RenderingContext.Current.Rendering.DataSource;
                if (DataSourceId != null)
                {
                    // Write your logic here
                    return View();
                }
                else
                {
                    return Redirect("~/CustomASPXPages/Error.aspx");
                }
            }
    
    Use RedirectPermanent() instead of Redirect() if you want to return 301 redirect response status code.
  2. Redirect to another View: return View("ViewName") tells MVC to generate HTML to be displayed for the specified view and sends it to the browser. This acts similar to Server.Transfer() in Asp.Net WebForm. return View() doesn't make a new requests, it just renders the view without changing URLs in the browser's address bar.
    public ActionResult DisplayBookDetail()
            {
                string DataSourceId = RenderingContext.Current.Rendering.DataSource;
                if (DataSourceId != null)
                {
                    // Write your logic here
                    return View();
                }
                else
                {
                    return View("Error");
                }
            }
    
  3. Redirect to non-Sitecore Page using RedirectToRoute(): In RouteConfig.cs file you need to add a route that triggers MVC action. The routes for the MVC Web Application are defined in the RouteConfig.cs under the App_Start folder of the MVC Project.
    You can modify RouteConfig.cs and use the RegisterRoutes function to register the custom route. The route maps the first segment of a URL to a controller name, the second segment of a URL to a controller action, and the third segment to a parameter named id. The RouteConfig.cs contains the following code:
    public class RouteConfig
        {
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
                RouteTable.Routes.MapRoute("ErrorDetails", "GetBook/Error", new { controller = "GetBook", action = "Error" });
            }
        }
    
    The RouteConfig.cs contains a static RegisterRoutes function which is called from the Global.asax file.
    protected void Application_Start(object sender, EventArgs e)
            {
               RouteConfig.RegisterRoutes(RouteTable.Routes);        
            }
    
    RedirectToRoute redirects to a specific route defined in the Route table.
    public ActionResult DisplayBookDetail()
            {
                string DataSourceId = RenderingContext.Current.Rendering.DataSource;
                if (DataSourceId != null)
                {
                    // Write your logic here
                    return View();
                }
                else
                {
                    return RedirectToRoute("ErrorDetails");
                }
            }
    
  4. Redirect to Sitecore Page using RedirectToRoute():Use below code to redirect to Sitecore Page using RedirectToRoute()
    public ActionResult DisplayBookDetail()
            {
                string DataSourceId = RenderingContext.Current.Rendering.DataSource;
                if (DataSourceId != null)
                {
                    // Write your logic here
                    return View();
                }
                else
                {
                    //Get Sitecore Item where you want to redirect
                    Item item = Sitecore.Context.Database.GetItem(Sitecore.Data.ID.Parse("{24240FF2-B4AA-4EB2-B0A4-63E027934C38}"));
    
                    var pathInfo = LinkManager.GetItemUrl(item, UrlOptions.DefaultOptions);
    
                    return RedirectToRoute(MvcSettings.SitecoreRouteName, new { pathInfo = pathInfo.TrimStart(new char[] { '/' }) });
                }
            }
    
Comments and suggestions are most welcome. Happy coding!
Read More...

Thursday, 26 June 2014

How to add a sublayout to Sitecore item programmatically

Leave a Comment
Today I've noticed a post in Sitecore SDN forum regarding how to add a sublayout to multiple items programmatically. Below function AddSublayoutToItem(string itemId, string sublayoutId) takes Sitecore item id and Sublayout id as input parameter and add specific sublayout to Sitecore item. I’ve added inline comments in below code to make it more understandable. Call this function iteratively for adding sublayout to multiple Sitecore items.
  public void AddSublayoutToItem(string itemId, string sublayoutId)
        {
            using (new Sitecore.SecurityModel.SecurityDisabler())
            {
                if (Sitecore.Data.ID.IsID(itemId) && Sitecore.Data.ID.IsID(sublayoutId))
                {
                    //Get the master database and get the item on which you want to add sublayout
                    Database masterDatabase = Database.GetDatabase("master");
                    Item item = masterDatabase.GetItem(Sitecore.Data.ID.Parse(itemId));

                    //  Or you can also get Sitecore Item from Context Database as per your requirement
                    //  Item item = Sitecore.Context.Database.GetItem(Sitecore.Data.ID.Parse(itemId));

                    if (item != null)
                    {
                        // Get the layout definitions and the device definition
                        LayoutField layoutField = new LayoutField(item.Fields[Sitecore.FieldIDs.LayoutField]);
                        LayoutDefinition layoutDefinition = LayoutDefinition.Parse(layoutField.Value);
                        DeviceDefinition deviceDefinition = layoutDefinition.GetDevice(Sitecore.Context.Device.ID.ToString());

                        //Create a RenderingDefinition and add the reference of sublayout or rendering
                        RenderingDefinition renderingDefinition = new RenderingDefinition();
                        renderingDefinition.ItemID = sublayoutId;
                        //Set placeholder where the rendering should be displayed
                        renderingDefinition.Placeholder = "content"; 
                        // Set the datasource of sublayout, if any
                        renderingDefinition.Datasource = "{24240FF2-B4AA-4EB2-B0A4-63E027934C38}";

                        // you can also set datasource of sublayout using Sitecore Path
                        // renderingDefinition.Datasource = "/sitecore/content/Home/Books";

                        //Add the RenderingReference to the DeviceDefinition
                        deviceDefinition.AddRendering(renderingDefinition);

                        // Save the layout changes
                        item.Editing.BeginEdit();
                        layoutField.Value = layoutDefinition.ToXml(); ;
                        item.Editing.EndEdit();
                    }
                }
            }
        }
Note: This code is tested on Sitecore 7.2 version. Comments and suggestions are most welcome. Happy coding!
Read More...

Tuesday, 24 June 2014

Error: Could not resolve type name Glass.Mapper.Sc.Pipelines.Response. GetModel, Glass.Mapper

4 comments
Today I was trying to use Sitecore Glass Mapping framework for my Sitecore MVC project. I’ve installed Glass Mapper from nuget and configured it for Sitecore MVC project. For more information on the Glass.Sitecore.Mapper visit the official website. Below are the few details about my development environment:
  • MVC Version:  4
  • Sitecore Version:  7.0
  • Glass.Mapper version:  3.0.10.23
  • Glass.Mapper.Sc version:  3.2.0.39
  • Glass.Mapper.Sc.Mvc version:  3.2.0.35
  • Glass.Mapper.Sc.Razor version:  3.0.9.13
Below config files will be added into App_Config\Includes folder once you install Glass Mapper framework:
  • Glass.Mapper.Sc.Razor.config
  • Glass.Mapper.Sc.Mvc.config
I got below error while browsing Sitecore MVC website.
Could not resolve type name: Glass.Mapper.Sc.Pipelines.Response.GetModel, Glass.Mapper.Sc (method: Sitecore.Configuration.Factory.CreateType(XmlNode configNode, String[] parameters, Boolean assert)).
While troubleshooting; I’ve checked Glass.Mapper.Sc.Mvc.config file.
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
      <settings></settings>
    <pipelines>
      <mvc.getModel>
        <processor type="Glass.Mapper.Sc.Pipelines.Response.GetModel, Glass.Mapper.Sc"/>
      </mvc.getModel>
    </pipelines>
  </sitecore>
</configuration>
I’ve checked Glass Mapper official website and got to know that few classes have been move to separate MVC assembly and somehow changes were not getting reflected into .config file. Class Glass.Mapper.Sc.Pipelines.Response.GetModel has been moved to Glass.Mapper.Sc.Mvc assembly which was earlier in Glass.Mapper.Sc assembly. I’d modified Glass.Mapper.Sc.Mvc.config as below:
<sitecore>
      <settings></settings>
    <pipelines>
      <mvc.getModel>
        <processor type="Glass.Mapper.Sc.Pipelines.Response.GetModel, Glass.Mapper.Sc.Mvc"/>
      </mvc.getModel>
    </pipelines>
  </sitecore>
</configuration>
I rebuild the solution and I was no longer getting the error.  
Download correct Glass.Mapper.Sc.Mvc nuget package for your Sitecore MVC project.
Glass.Mapper.Sc.Mvc nuget package.

Sitecore VersionMVC VersionGlass.Mapper.Sc.Mvc nuget package
Sitecore 6.xMVC 3Glass.Mapper.Sc.Mvc-3
Sitecore 7.0-7.1MVC 4Glass.Mapper.Sc.Mvc-4
Sitecore 7.2MVC 35Glass.Mapper.Sc.Mvc-5
Comments and suggestions are most welcome. Happy coding! 
Read More...

Saturday, 21 June 2014

Tutorial: How to make Ajax call in Sitecore MVC

Leave a Comment
Today I’ve stumbled upon a post in Sitecore SDN forum regarding how to make an AJAX call in SITECORE MVC. In this blog post I am going to explain how to implement AJAX call in SITECORE MVC solution by adding routes in RouteConfig. Also check how to make Ajax call in Sitecore without registering routes in RouteConfig. We can divide complete functionality in below steps:
  1. Create a MVC controller action: Create an action in MVC controller which will return JSON result set by using Json() method. This action method may accept input parameters to implement business logic and return JsonResult accordingly.
  2. Register route for controller: In RouteConfig.cs file you need to add a route that triggers the controller and action.
  3. Implement AJAX call and Update HTML: Implement AJAX Call to controller action using jQuery and pass the input parameters, if any.
Example:  I’ve created a data template in Sitecore which is having three fields as shown in figure.
I’ve created few items based on newly created data template. See below figure:

I’ve created a basic controller rendering which is displaying books in a dropdown list. Below is the code of controller rendering for your reference:

Controller Code
public class BookDetailsController : SitecoreController
    {       
        public override ActionResult Index()
        {           
            List<SelectListItem> bookItems = new List<SelectListItem>();
            bookItems.Add(new SelectListItem { Text = "--Select Book--", Value = ""});
            bookItems.Add(new SelectListItem { Text = "Learn ASP", Value = "{EC2B22FE-8A6E-431F-8114-6B2944AE81B8}" });
            bookItems.Add(new SelectListItem { Text = "Learn MVC", Value = "{EBB9F7D5-22DB-4B7A-A275-42D9B5C88715}" });
            bookItems.Add(new SelectListItem { Text = "Learn SITECORE", Value = "{C89AE332-9845-4379-8C45-E8D58AAA5685}" });
            ViewBag.Books = bookItems;          
            return View();
        }    
}  
View Code
Select Any Book :
@Html.DropDownList("Books")

<div id="BookDetail" style="white-space: pre;">

</div>
On change event of dropdown list; I’ll display book details (book title, book author and book language) of selected book. I’ll use AJAX to achieve this functionality.
  1. Create a MVC controller action: I’ve written GetBookDetails action with [HttpPost] attribute in BookDetails Controller where I am passing Sitecore item id of selected book as input parameter. I’ll get book details by using item id of book item and return book details as JsonResult.
    [HttpPost]
            public JsonResult GetBookDetails (string itemId)
            {
                Book book = new Book();
                if (Sitecore.Data.ID.IsID(itemId))
                {
                    Item item = Sitecore.Context.Database.GetItem(Sitecore.Data.ID.Parse(itemId));
                    if (item != null)
                    {                   
                        book.BookTitle= item.Fields["Book Title"].Value;
                        book.BookAuthor = item.Fields["Author"].Value;
                        book.BookLanguage = item.Fields["Language"].Value;
                    }
                }
                return Json(book);
            }
        }
    public class Book
        {
            public string BookTitle { get; set; }
            public string BookAuthor { get; set; }
            public string BookLanguage { get; set; }
        }
    
  2. Register route for controller: In RouteConfig.cs file you need to add a route that triggers GetBookDetails action. The routes for the MVC Web Application are defined in the RouteConfig.cs under the App_Start folder of the MVC Project.
    You can modify RouteConfig.cs and use the RegisterRoutes function to register the custom route to perform Ajax calls. The route maps the first segment of a URL to a controller name, the second segment of a URL to a controller action, and the third segment to a parameter named id. The RouteConfig.cs contains the following code: 
    public static class RouteConfig
        {
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
                RouteTable.Routes.MapRoute("BookDetails", "BookDetails/GetBookDetails", new { controller = "BookDetails", action = "GetBookDetails" });
            }
        }
    
    The RouteConfig.cs contains a static RegisterRoutes function which is called from the Global.asax file.
            protected void Application_Start(object sender, EventArgs e)
            {
               RouteConfig.RegisterRoutes(RouteTable.Routes);        
            }
  3. Implement AJAX call: I’ll use jQuery to make Ajax call. In the below code, I am reading the value of selected book from dropdown list and passing book item id as an input parameter while making Ajax call to get book details. Use the returned JsonResult set to update the HTML div BookDetail.
    <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.1.js"> </script>
    <script type="text/javascript">
        $(function () {
            $("#Books").bind("keyup change", function () {
                var itemId = $(this).val();
                if (itemId != "") {
                    $.ajax({
                        url: "BookDetails/GetBookDetails",
                        type: "POST",
                        data: { itemId: itemId },
                        context: this,
                        success: function (data) {
                            var BookString = "Book Title: " + data.BookTitle + "\n" + "Book Author: " + data.BookAuthor + "\n" + "Book Language:" + data.BookLanguage;
                            $("#BookDetail").text(BookString);
                            console.log("success", data);
                        },
                        error: function (data) {
                            console.log("error", data);
                        }
                    });
                }
                else {
                    $("#BookDetail").text("");
                }
            });
        });
    </script>
Comments and suggestions are most welcome. Happy coding! 
Read More...

Sunday, 15 June 2014

Remove specific language version from items in Sitecore

Leave a Comment
In this blog post; I am going to explain how to remove a specific language version from items in Sitecore programmatically. Currently; I have got into a situation where I have to remove a specific language version (fr-FR in my case) from Sitecore items of a multilingual website. Below function RemoveLanguageVersion(string rootItemPath, string languageName) takes the root item path and language name  as input parameter and remove given language version from root item and child items of root item.
public void RemoveLanguageVersion(string rootItemPath, string languageName)
        {
            Language languageRemove = Sitecore.Globalization.Language.Parse(languageName);
            Item rootItem = Sitecore.Context.Database.GetItem(rootItemPath, languageRemove);

            if (rootItem != null)
            {
                using (new Sitecore.SecurityModel.SecurityDisabler())
                {
                    //Remove language version from root item               
                    rootItem.Versions.RemoveVersion();

                    //Remove language version recursively from child items of root item
                    foreach (Item child in rootItem.Axes.GetDescendants().Where(l => l.Language == languageRemove))
                    {
                        child.Versions.RemoveVersion();
                    }
                }
            }
        }
Example:
string rootItemPath = "/sitecore/content/Home/Audience";
string languageName = "fr-FR";

RemoveLanguageVersion(rootItemPath, languageName);
Above code will remove fr-FR language version from item /sitecore/content/Home/Audience and its child item recursively.

Comments and suggestions are most welcome. Happy coding!
Read More...

Wednesday, 11 June 2014

Update data source of sublayout or rendering in Sitecore

Leave a Comment
In this article I am going to explain how to change data source of sublayout or rendering in Sitecore programmatically. Also you can check article on how to get data source of sublayout or rendering in Sitecore programmatically.

Several sublayouts or renderings have been added in Sitecore item presentation details. We need to change data source of each sublayout and set data source value to any other value. Below function UpdateRenderingDatasource(string itemId) takes Sitecore item id as input and change data source of sublayouts or renderings.
      public void UpdateRenderingDatasource(string itemId)
        {
            using (new Sitecore.SecurityModel.SecurityDisabler())
            {
                if (Sitecore.Data.ID.IsID(itemId))
                {
                    Item item = Sitecore.Context.Database.GetItem(Sitecore.Data.ID.Parse(itemId));
                    if (item != null)
                    {
                        //Get all added renderings
                        Sitecore.Layouts.RenderingReference[] renderings = item.Visualization.GetRenderings(Sitecore.Context.Device, true);
                   
                        // Get the layout definitions and the device
                        LayoutField layoutField = new LayoutField(item.Fields[Sitecore.FieldIDs.LayoutField]);
                        LayoutDefinition layoutDefinition = LayoutDefinition.Parse(layoutField.Value);
                        DeviceDefinition deviceDefinition = layoutDefinition.GetDevice(Sitecore.Context.Device.ID.ToString());
                        foreach (RenderingReference rendering in renderings)
                        {
                            // Update the renderings datasource value accordingly 
                            deviceDefinition.GetRendering(rendering.RenderingID.ToString()).Datasource = "{EDDF6E49-28C4-4699-9E12-4E69B5A64D1A}";
                            // Save the layout changes
                            item.Editing.BeginEdit();
                            layoutField.Value = layoutDefinition.ToXml();
                            item.Editing.EndEdit();
                        }
                    }
                }
            }
        }
Explanation: First of all we need to get list of sublayouts or renderings used by item in Sitecore. Below code gets all added renderings or sublayouts.
Sitecore.Layouts.RenderingReference[] renderings = item.Visualization.GetRenderings(Sitecore.Context.Device, true);
If you want to get particular sublayout or rendering then use below code by using specific sublayout id.
  Sitecore.Layouts.RenderingReference[] renderings = item.Visualization.GetRenderings(Sitecore.Context.Device, true).Where(r => r.RenderingID == Sitecore.Data.ID.Parse(sublayoutId)).ToArray();
Once you get list of renderings then get the layout definition and device definition. Iterate through every rendering and update the rendering data source accordingly and save the layout changes.

Comments and suggestions are most welcome. Happy coding!

Read More...

Monday, 9 June 2014

Active Directory Integration with Sitecore: Quick Steps

Leave a Comment
In this blog post; I am going to explain how to integrate Active Directory with Sitecore. The Sitecore CMS Active Directory module provides the integration of Active Directory domain with the Sitecore CMS solution. You can integrate the domain users and groups available into Sitecore CMS as Sitecore users and Sitecore roles immediately after the module installation and configuration.  The Active Directory module is based on the ASP.NET security model architecture.

Basic configuration steps:

  1. Download Active Directory Module: Download Active Directory Module from Sitecore SDN.
  2. Install Active Directory Module: After package installation, you have to modify few configuration files to complete the installation. In the main /App_Config/connectionstrings.config file, add a connection string to the <connectionStrings> section. For example:
    <connectionStrings>
    <add name="LDAPConnString" connectionString="LDAP://ADServer.domain.name/OU=Managers,DC=ADDomain,DC=company,DC=com"/>
    </connectionStrings>
    
    • In this example, Managers is just a sample organization unit. Replace it with the name of a real OU.
    • The LDAP prefix is case sensitive. You should use only capital letters when writing the LDAP prefix.
    • For more information about the format of the LDAP connection string, see the article LDAP ADsPath on MSDN.
  3. Configuring the Membership Provider: Open the web.config file, search for the <membership> element in the <system.web> section and paste the following definition inside it (the order is not important).
    <add name="customAD" type="LightLDAP.SitecoreADMembershipProvider" connectionStringName="LDAPConnString" applicationName="sitecore" minRequiredPasswordLength="1" minRequiredNonalphanumericCharacters="0" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" 
    connectionUsername="[Enter User Name]" connectionPassword="[Enter Password]" connectionProtection="Secure" attributeMapUsername="sAMAccountName" enableSearchMethods="true" />
    In above lines, replace connectionUsername and connectionPassword. To connect to the Active Directory domain, you should specify a user who has sufficient rights to perform the necessary operations. The provider uses these credentials when it connects to the AD domain.
  4. Configuring the Role Provider: Open the web.config file, search for the <roleManager> element in the <system.web> section and paste the following definition inside it (the order is not important).
    <add name="customAD" type="LightLDAP.SitecoreADRoleProvider" connectionStringName="LDAPConnString" applicationName="sitecore" 
    username="[Enter User Name]" password="[Enter Password]" attributeMapUsername="sAMAccountName" cacheSize="2MB" />
    In above lines, replace connectionUsername and connectionPassword.
  5. Activating Switching Providers: To make the Sitecore aware of an extra source of users and roles, the switching mechanism must be activated. To activate the switching mechanism make below changes:
    • In web.config file, in <system.web> section, browse for <membership> element and find the provider called sitecore and set its realProviderName attribute to switcher.
    • In web.config file, in <system.web> section, browse for <roleManager> element and find the provider called sitecore and set its realProviderName attribute to switcher.
  6. Adding a New Domain: Open the App_Config/Security/Domains.config.xml file and add the following line to the root element:
    <domain name="customAD" ensureAnonymousUser="false"/>
  7. Adding the Domain-Provider Mappings: Open web.config file and in <sitecore> section, browse to the <switchingProviders> element.
    • Add the following line to the <membership> group — the order is not important:
      <provider providerName="customAD" storeFullNames="false" wildcard="*" domains="customAD" /> 
    • Add the following line to the <roleManager> group — the order is not important:
      <provider providerName="customAD" storeFullNames="false" wildcard="*" domains="customAD" /> 
After you have configured the module, open Sitecore CMS, and log into the Sitecore Desktop as an administrator. Click Sitecore, Security Tools, Role Manager to open the Role Manager. You can see the roles from Active Directory along with the Sitecore CMS roles.
Any changes made in Sitecore CMS to the active directory users are done in LIVE mode. The changes are applied immediately to the real Active Directory objects. The only exception is user lock-out; in this case the users are locked out locally from Sitecore CMS and remain active in the Active Directory domain.
The Active Directory module also allows you to store the custom properties of a user profile in the attributes of the corresponding domain user object. Check official documentation of Active Directory Module in Sitecore SDN for advanced configuration like Single Sign On. This article is targeted for Sitecore 6.6-7.0 version.
You might get below error if you are using Sitecore MVC.

Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

Parser Error Message: This method cannot be called during the application's pre-start initialization phase.

Solution: Add this in your web.config (in the appSettings section):

<add key="enableSimpleMembership" value="false"/>
<add key="autoFormsAuthentication" value="false"/>
Read More...