Thursday, February 23, 2017

Preview Transform and Add Transform OOB Issue with other config type

Configuration Transformation: Evironment Configuration


XDT: Transform

In recent times I have been working sitecore configuration config transformation for different environment and I came across the scenario where Add transform and Preview is supported in Visual studio only for web.config files not for other configuration. To fix this I just install Slow Cheetah extension and restarted my visual studio with project solution , everything works fine.

https://marketplace.visualstudio.com/items?itemName=WillBuikMSFT.SlowCheetah-XMLTransforms


Sitecore config builder
https://marketplace.sitecore.net/Modules/S/Sitecore_Custom_Config_Builder.aspx?sc_lang=en
https://marketplace.sitecore.net/modules/sitecore_configbuilder.aspx

Saturday, December 10, 2016

Sitecore Item browser and technical doco viewer tool

Jumpstart

This module is available in Sitecore Market place and source code in git.

This tools saves time in creating and extracting sitecore item defination. This browser and viewer can be used for review, quick lookup and extract for technical documentation.
Support Prerequisites
  • Tested in Sitecore Xp
  • Worked well with sitecore mvc renderings. Not tested for components with sublayout

Work in progress
  • Root element such home is not displayed and view. Will be available in next release.
  • Must be installed only in development environment in CMS content authoring server or local 
  • Not suitable for CD or production or test env.

This module is about browsing and viewing sitecore item technical definition such as template, layout, device, presentation and fields definition for given sitecore item in content tree. This is very useful tool to extract content for technical document for any project. It gives all details of given item its template, base template, renderings, datasource and all. So all we need to do is to browse and extra the definition for our technical documentation. 
Once this package is installed ,you can browse item defination and details using below url.

  • http://website/sitecore/admin/browsedoco.aspx 
  • http://website/sitecore/admin/knowMe.aspx 

you can also find the source code available in  
https://github.com/poojarsn/MyDoco





Saturday, November 26, 2016

LINQ Performance pitfall instead a Pit stop!

I would rather named the title as Linq performance pit stop. Anyway in the interest of time, here is, one of the good examples of how we can start with something very trivial linq query to something convoluted one. Always remember the query in memory or on fly comes with its own pros and cons. One must understand how to use them and when. I took this particular example from pluralsight and thought it to be worth sharing.

Courtesy
https://app.pluralsight.com/library/courses/linq-more-effective/table-of-contents

by Mark Heath.

Slow
var longest=books.First(b => b.Pages==books.Max(a => a.Pages));

Better
var mostBooks= books.Max(a => a.Pages);
var longest=books.First(b => b.Pages == mostBooks);

Best
var longest= books.MaxBy(p => p.Pages);

Hope this useful.


Wednesday, September 28, 2016

Check field Template Source value using sitecore powershell SPE

Use Case :Review

Suppose we have a custom rich text  and it has been sourced with custom component or css .This is added when developer creates template field in data template. The below code snippet can be used as part of your review and refactoring process to clean up sitecore items. 

Here is the quick pick..Check Source field of rich text is empy or null.

$targetTemplate    = Get-item 'master:/sitecore/templates/User Defined/Common/Data';
$templateFilter    = Get-Item "master:/sitecore/templates/System/Templates/Template Field";


Get-ChildItem $targetTemplate.FullPath -recurse 
| Where-Object { $_.TemplateName -eq $templateFilter.Name -and $_.type -eq 'Rich Text' -and $_["source"] -eq ''} 
| ForEach-Object {
    $_.Name
    $_.Type
    $_["Source"] 
}

Reference


http://sitecore.stackexchange.com/questions/203/unable-to-get-value-of-source-using-spe

Add base template using sitecore powershell extension

Use Case

It might happen you may have to add base template to all your user defined template. Below is the script to help doing this. I used Adam's code as reference to get this working. During development we could have reach to a stage where we end up with lot of user defined templates and at some point we review and refactor template to have uniform approach. One of the script below can come handy to save some of our refactoring time.

# Add base template programmatically


$targetTemplate    = Get-item 'master:/sitecore/templates/User Defined/Common/Data';
$templateFilter    = Get-Item "master:/sitecore/templates/System/Templates/Template";
$templateToBeAddAsBaseTemplate     = Get-Item 'master:/sitecore/templates/User Defined/Common/Data/Carousel'


Get-ChildItem $targetTemplate.FullPath -recurse | Where-Object { $_.TemplateName -eq $templateFilter.Name -and $_.Name -eq "promo"} | ForEach-Object {
    if(-not ($_."__Base template" -match "$($templateToBeAddAsBaseTemplate.Id)")){
           #If not exist then add
         $_."__Base template" = "$( $_."__Base template")|$($templateToBeAddAsBaseTemplate.Id)" 
    }
}

Reference

http://stackoverflow.com/questions/18990973/append-base-template-to-template-using-sitecore-powershell

Add base template using sitecore powershell extension

Use Case

It might happen you may have to add base template to all your user defined template. Below is the script to help doing this. I used Adam's code as reference to get this working. During development we could have reach to a stage where we end up with lot of user defined templates and at some point we review and refactor template to have uniform approach. One of the script below can come handy to save some of our refactoring time.



$targetTemplate    = Get-item 'master:/sitecore/templates/User Defined/Common/Data';
$templateFilter    = Get-Item "master:/sitecore/templates/System/Templates/Template";
$templateToBeAddAsBaseTemplate     = Get-Item 'master:/sitecore/templates/User Defined/Common/Data/Carousel'


Get-ChildItem $targetTemplate.FullPath -recurse | Where-Object { $_.TemplateName -eq $templateFilter.Name -and $_.Name -eq "promo"} | ForEach-Object {
    if(-not ($_."__Base template" -match "$($templateToBeAddAsBaseTemplate.Id)")){
           #If not exist then add
         $_."__Base template" = "$( $_."__Base template")|$($templateToBeAddAsBaseTemplate.Id)" 
    }
}

Reference

http://stackoverflow.com/questions/18990973/append-base-template-to-template-using-sitecore-powershell

Monday, September 12, 2016

Sitecore CMS Active Directory Module and LDAP integration.

Introduction

I'm not going to reinvent the wheel. The idea is to help fellow developer to troubleshoot and few show stoppers that can come as a problem during integration of ldap to sitecore AD Module. I just try to put my experience altogether so as to address some issues and useful tool that can help you get started.

Use Cases

Enabling LDAP authentication in content authoring aka CMS system will provide additional level of security access control in place. This will ensure limited access and no misuse even we have CMS -CA accessible only to internal network non accessible publicly.

Assumption:

You've LDAP /AD account in place. Say. There is dev, test and prod group account created in AD. To each of these group set of AD users are assigned. Each of these group must be assigned with Service account say sv_dev_user.and so on. The Service account act as primary source of authentication to allow any external system seek access to AD group. Later it will enable set of users to access application or system.

  • Development/Test/Production Environment
    • AD GROUP 
      • AD User(s) 
      • One Service Account
Note : The service account is one that is used by sitecore AD Module.

This is used by one of the sitecore configuration.
add name="customAD" type="LightLDAP.SitecoreADMembershipProvider" connectionStringName="LDAPConnString" applicationName="sitecore" minRequiredPasswordLength="1" minRequiredNonalphanumericCharacters="0" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
connectionUsername="[Enter SERVICE Account User Name]" connectionPassword="[Enter Password]" connectionProtection="Secure" attributeMapUsername="sAMAccountName" enableSearchMethods="true"

***Facts About:AD Service Account Vs AD User Account

In certain scenarios we have systems running under AD Credentials (i.e. under a Service Account). These Service Accounts are created in exactly the same way as user accounts; the only difference being the name and description. A few things have been done to make a distinction between the two account types (e.g. which OU the account is in, whether "password never expires" is enabled, if "service account" is in the description), but there's no one rule which can be applied to everything to clearly distinguish between the two.

How to get Started?

Follow this blog , this more precise and easy steps to start with.

Troubleshooting?  

1. OU Group wrongly used in LDAP Connection string?

Always look at the right form of LDAP connection string. 99% of the cases Ldap connection is wrongly used in terms of OU group. There may be nested OU group. The best way to figure out OU group is use LDAPAdmin.exe. Check download section.

Connect LdapAdmin with service account userId and pwd. Once connected to LDAPAdmin try to locate AD Group and take one member(user) of that group and check its property . You can easily find the right hierarchy of OU aswell as right OU group.

2. Check LDAP Port in Ldap connection string?

  • Port 389(used for ldap browsing) vs 636 (secure)
add name="LDAPConnString" connectionString="LDAP://Mydomain:389/OU=SomePrimaryOU,OU=SomeChildOU,DC=Mydomain,DC=myCompany,DC=com,DC=au"

3. Always verify connectivity of LDAP AD account from server

One way to check directly using ldapAdmin.exe or you can check through this simple code base.

using System.DirectoryServices;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //mycompany.com.au
            var entry = new DirectoryEntry(@"LDAP://yourdomain:636/OU=primary,OU=secondary,DC=yourdomain,DC=mycompany,DC=com,DC=au", "Active directory user name","password");

            var search = new DirectorySearcher(entry);
            SearchResult result = search.FindOne();  

      }
      }
}

4. Sitecore Provider Status

                                       http://mydemo/sitecore/admin/providerstatus.aspx


5. User Manager : AD User Import Status Successful!


6. Domain: Check CustomAD Domain appeared!


7. Role Manager: Assign Sitecore Role to User

Make sure Sitecore Client Role is assigned to AD users.


8. Finally Login with AD user account

Ensure you using the domain name that you added as one of the membership provider. say you got domain name mydomain and you have used membership provider as below. Then you should login with customAD\UserId

add name="customAD" type="LightLDAP.SitecoreADMembershipProvider" connectionStringName="LDAPConnString" applicationName="sitecore" 

Downloads

References

Azure Cloud

Friday, August 26, 2016

Sitecore MVC Session handling

It all started when we had session timeout and it resulted in error page. Yes session checks were not handled properly.All I was looking to solve this trivial problem with quick code fix but it turn out to be a bit of research again. This is indeed a sitecore world, where every request surface with filters, route and action. Each request is fragmented as we had controller rendering to serve all our dynamic data and transaction commits.

****Register Global Filter to check for session. 
This will not work as there are some workflow pages which are not session or authorization dependent. It bit the purpose.

Next thought of handling this in SessionEnd pipeline.
GlobalFilters.Filters.Add(new SessionExpireAttribute());

****SessionEnd Pipeline Response.Redirect and Server.Transfer will not work!

Session_End is fired internally by the server, based on an internal timer. And thus there is no HttpRequest associted when that happens. That is why Response.Redirect or Server.Transfer does not make sense and will not work. 

**** SessionEnd is not fired if session mode is outproc.
It will be fired only when using session mode set as inproc or Custom.

****Solution: Not elegant but it worked.
Let the session timeout and then eventually it will be send to the path of common error handling module where we can take appropriate action to redirect it to login page or some information page to notify user about session timeout.
 
****Post Session Timeout-  User action server side event.
****Post Session Timeout- User action cliend side event fired.(Check for IsAjaxRequest)
 public class RenderingControllerExceptionProcessor : ExceptionProcessor
{  
    public override void Process(ExceptionArgs args)
    {
            var userContext = SessionService.Get();
            if (userContext == null)
                if (args.ExceptionContext.HttpContext.Request.IsAjaxRequest())
                {
             //send something to response result.
                    args.ExceptionContext.Result = new JsonResult
                    {
                        Data = new
                        {
                            Error = "NotAuthorized",
                            LogOnUrl = "/login"
                        },
                        JsonRequestBehavior = JsonRequestBehavior.AllowGet
                    };
                }
                else
                {
                    WebUtil.RedirectToLoginPage();
                }
   }
}
OR
 private bool IsSessionExpired()
        {
            if (HttpContext.Current.Session != null)
            {
                
                if ( HttpContext.Current.Session.IsNewSession)
                {
                    //Note: Below code fails for Custom session.Works for Inproc
                    string cookieHeaders = HttpContext.Current.Request.Headers["Cookie"];

                    if ((null != cookieHeaders) &&
                       (cookieHeaders.IndexOf("ASP.NET_SessionId", StringComparison.Ordinal) >= 0))
                    
                        // IsNewSession is true, but session cookie exists,
                        // so, ASP.NET session is expired
                        return true;
                    
                }
                // Session is not expired and function will return false,
                // could be new session, or existing active session
                return false;
            }
            return false;
        }
The only solution is to handle through global application error event in sitecore rendering.


Always Consider these values when dealing with session:.

  1. Polling interval
  2. Compression
  3. Session type
  4. SlidingExpiration

Side Note:
If your worker process restarts and it causes your cache to clear, think of using agent to ping Keepalive.aspx.

Monday, August 22, 2016

How string Interpolation can simplify expression? No more string.format

Just this example 


Console.WriteLine($"When {condition} is true, {(condition ? "it's true!" : "It's False")}");

C# Simplify Dispose Object

public void RetireHenchman()
{
    var disposableMinion = Minion as IDisposable;
    if (disposableMinion != null)
        disposableMinion.Dispose();
    Minion = null;
}
 
The null coalescing operator can make this code more concise as well:
 
public void RetireHenchman()
{
    (Minion as IDisposable)?.Dispose();
    Minion = null;
}