Pages

Sunday, August 29, 2010

Ajax Control Toolkit with SharePoint 2010

I had to use Ajax control toolkit with sharepoint and I had download the latest version from codeplex. We usually download latest versions of software because we believe that with latest version we can get more features and more bug-free. I had used Ajax Control Toolkit with SharePoint 2007 and it was much easier to configure and use Ajax Control Toolkit. With that belief in mind I had started using Ajax Control Toolkit in SharePoint 2010 downloading latest version for .net framework 3.5. But I failed  and after investigating I had found the following errors.

  • AjaxControlToolkit requires ASP.NET Ajax 4.0 scripts. Ensure the correct version of the scripts are referenced. If you are using an ASP.NET ScriptManager, switch to the ToolkitScriptManager in AjaxControlToolkit.dll.
  • Sys.registerComponent is not a function


The problem here is that latest versions of Ajax Control Toolkit is more optimized or targeted with .net framework 4.0. Even the Ajax control toolkit for .net framework 3.5 doesn’t work with SharePoint 2010. If you try to use Ajax Control Toolkit for 3.5 with SharePoint 2010, you may get the exceptions shown above.

How to make Ajax Control Toolkit working with SharePoint 2010?

Here are the steps to make Ajax Control Toolkit working with SharePoint 2010.

  1. Download Correct (compatible) version of Ajax Control Toolkit.

    Since current release of Ajax Control Toolkit doesn’t work with SharePoint 2010, you need to download previous release. Maybe Ajax Control Toolkit team will address this issue and we’ll be able to use current Toolkit version with SharePoint in future. Until the current release is made compatible, please download the SharePoint 2010 compatible Ajax Control Toolkit from here.

  2. Add AjaxControlToolkit.dll reference to your project

    To use the Ajax Control Toolkit in your SharePoint project, add reference to the AjaxControlToolkit.dll in your project. To use the Ajax Control Toolkit in any web part control add the following lines to register the Ajax Control Toolkit namespace.

    <%@ Register Assembly="AjaxControlToolkit, Version=3.0.30930.28736,
    Culture=neutral,
    PublicKeyToken=28f01b0e84b6d53e"
    Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>
  3. Remember, here version 3.x version of Ajax Control Toolkit is used instead 3.5.

  4. Add Ajax Control Toolkit ScriptManager in master page.

    Open the Master page in SharePoint Designer. By default the v4.Master file is the default master page can be found “_catalogs/masterpage” folder. Before modifying the master page, keep a backup copy.

    • First register the Ajax Control Toolkit namespace in the masterpage file by putting the following line at the top of the file:
      <%@ Register Assembly="AjaxControlToolkit, Version=3.0.30930.28736,
      Culture=neutral, PublicKeyToken=28f01b0e84b6d53e"

      Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>
    • Then remove the ScriptManager registration from the master page by removing the following line:
      <asp:ScriptManager id="ScriptManager" runat="server" EnablePageMethods="false"  
      EnablePartialRendering="true" EnableScriptGlobalization="false" EnableScriptLocalization="true"/>
    • Finally Add the following line in place of the above line to register Ajax Control Toolkit
      <ajaxToolkit:ToolkitScriptManager id="ScriptManager" runat="server" EnablePageMethods="false" 
      EnablePartialRendering="true" EnableScriptGlobalization="false" EnableScriptLocalization="true"/>
  5. Register Ajax Control Toolkit namespaces in SharePoint package Designer 

    Finally, you need to register the Ajax Control Toolkit namespace with SharePoint Package designer. Registering Ajax Control Toolkit namespaces will add Ajax Control Toolkit namespaces in web.config’s safecontrol list. First open the Package designer in Visual Studio (Package usually exists under Package folder in Visual Studio). And then click the “Advanced” button in package designer window as shown in the image below. In that advanced tab you can add/edit assemblies to be registered safe as part of the deployment of the solution package. Click Add ==> “Add Existing Assembly”. The following image shows wizard to follow.

    image

    Figure 1: Package Designer’s Advance tab

    In the “Add existing Assembly” window, add the following namespaces for Ajax Control Toolkit.

    Namespace Type Name Assembly Name
    AjaxControlToolkit * AjaxControlToolkit
    AjaxControlToolkit.Design * AjaxControlToolkit
    AjaxControlToolkit.HTMLEditor * AjaxControlToolkit
    AjaxControlToolkit.HTMLEditor.Popups * AjaxControlToolkit
    AjaxControlToolkit.HTMLEditor.ToolbarButton * AjaxControlToolkit
    AjaxControlToolkit.MaskedEditValidatorCompatibility * AjaxControlToolkit

    The following image shows the “Add Existing Assembly” window for AjaxControlToolkit dll.

    image

    Figure 2: Add/Edit Existing Assembly window

    Now you can build and deploy the package and as a result of deployment, Ajax Control Toolkit namespaces will be registered as safe controls in web.config.

Conclusion

Its really hard to believe that Ajax Control Toolkit’s  latest version doesn’t work with SharePoint. We expect to have the latest version of Ajax Control Toolkit to be compatible with SharePoint 2010. Until then we might have to use an old version of Ajax Control Toolkit.

Saturday, August 21, 2010

SharePoint 2010: Conditional Scope

In my previous post I had explained about Exception Handling Scope. If you have not read the post already then I’ll suggest you to read the post as the idea behind this scope in SharePoint Client Object Model has been described in that previous post.

In Client Object Model, if you need to load data based on some condition. But if the condition is based on some server side values then you need to use two different requests. First request will be to get the values from the server to check the condition. Second request will be to load data or not, based on the condition expression value.

In SharePoint Client Object Model API, there’s a new class called ConditionalScope to load data conditionally. Here’s how to use the ConditionalScope:

  • In ConditionalScope constructor pass the ClientContext instance as first parameter. In the second parameter, pass the condition to be evaluated on the server. As shown below, the condition to check is whether the list is hidden or not.
var conditionalScope = new ConditionalScope(clientContext, () => !list.Hidden);
  • The second step is to put the load expression in ConditionalScope’s StartScope method. As shown below, if the list is not hidden, then load the Title of the list.
using (conditionalScope.StartScope())
{
    clientContext.Load(list, ol => ol.Title);
}

In the above statement, the load will be executed if the condition specified in ConditionalScope’s constructor is true (in this case, not hidden).

  • Finally, after executing ClientContext.ExecutQuery method, you need to find out if the expression passed in Coditional Scope was true or false. If condition was true then u know the data has been loaded (in this case the title of the list). If the condition was not true then data was not loaded. To check whether the condition evaluated true of false, check conditional scope’s TestResult. Remember, you will only get this property value after executing Executing query to the server.
clientContext.ExecuteQuery();
if (conditionalScope.TestResult.HasValue && conditionalScope.TestResult.Value)
{
    Console.WriteLine("Title:" + list.Title);
}

As shown in the code snippet above, if the TestResult has been evaluated to true then the title property is available.

The whole code will look like below:

var clientContext = new ClientContext(siteUrl);
var web = clientContext.Web;
var list = web.Lists.GetByTitle(listName);

var conditionalScope = new ConditionalScope(clientContext, () => !list.Hidden);


using (conditionalScope.StartScope())
{
    clientContext.Load(list, ol => ol.Title);
}

clientContext.ExecuteQuery();
if (conditionalScope.TestResult.HasValue && conditionalScope.TestResult.Value)
{
    Console.WriteLine("Title:" + list.Title);
}

 

Limitations

You can not use Conditional scope in all cases for all operations:

  • You can only load data using Conditional Scope. You can not however call any method or set properties in Conditional Scope’s StartScope method. If you use the ConditionalScope to set properties or to call server side method, you may get the following error:
Incorrect usage of conditional scope. Some actions, such as setting a property or invoking a method, are not allowed inside a conditional scope.
  • expression passed in ConditionalScope’s second argument has restrictions. You can not use all kinds of expressions. For example you can not use expression like, list.Fields.Count. However, you can use List.ItemCount. I have not found any documentation on MSDN with the supported expression for ConditionalScope.
  • Before using ConditionalScope.TestResult in your decision to access data, you need to execute Query.

Thursday, August 19, 2010

SharePoint Service Locator: Register Singleton Type

In my previous post I have described how to register type with SharePoint Service Locator. Today I’ll explain how to register singleton instance. We usually use Feature Receiver to register types. The following code snippet shows how to register singleton instance.

public class ServiceLocatorFeatureEventReceiver : SPFeatureReceiver
{
    public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
        var currentSite=properties.Feature.Parent as SPSite;
        var serviceLocator = SharePointServiceLocator.GetCurrent();
        var typeMapper = serviceLocator.GetInstance<IServiceLocatorConfig>();
        typeMapper.Site = currentSite;
        typeMapper.RegisterTypeMapping<INonsingletonInterface, NonsingletonType>();
        
        var singletonTypeMapper = typeMapper as ServiceLocatorConfig;
        singletonTypeMapper.RegisterTypeMapping<ISingletonInterface, SingletonType>(null, InstantiationType.AsSingleton);

        SharePointServiceLocator.Reset();
    }


    public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
    {
        var currentSite=properties.Feature.Parent as SPSite;
        var serviceLocator = SharePointServiceLocator.GetCurrent();
        var typeMapper = serviceLocator.GetInstance<IServiceLocatorConfig>();
        typeMapper.Site = currentSite;
        typeMapper.RemoveTypeMapping<INonsingletonInterface>(null);

        var singletonTypeMapper = typeMapper as ServiceLocatorConfig;
        singletonTypeMapper.RemoveTypeMapping<ISingletonInterface>(null);

        SharePointServiceLocator.Reset();
    }
}

As shown in above code block, to register singleton instance, you need to cast the IserviceLocatorConfig instance to ServiceLocatorConfig. Then you can specify the InstantiationType.AsSingleton for registering the type as singleton.

 

When you register a type as singleton, on first request the type will be instantiated and for later requests the instance created on first request will be delivered. However, if IIS is reset then the instance will be destroyed and create anew on first request.

Tuesday, August 10, 2010

SharePoint 2010: Exception Handling Scope

Sometimes in coding we need to make decision based on exception. For example the following code snippet try to enable versioning and folder creation in a list using SharePoint Client Object Model. However, if the list doesn’t exist then the code also create the list.

public static void EnableListVersioningAndFolderCreation(string siteUrl, string listName, string description)
{
    using(var clientContext=new ClientContext(siteUrl))
    {
        List list = null;
        try
        {
            list = clientContext.Web.Lists.GetByTitle(listName);
            clientContext.Load(list);
            clientContext.ExecuteQuery();
        }
        catch (Exception)
        {
            var listCreationInformation=new ListCreationInformation();
            listCreationInformation.Title = listName;
            listCreationInformation.TemplateType = (int)ListTemplateType.GenericList;
            listCreationInformation.Description = description;
            list = clientContext.Web.Lists.Add(listCreationInformation);
            clientContext.ExecuteQuery();
        }
        finally
        {
            list.EnableVersioning = true;
            list.EnableFolderCreation = true;
            list.Update();
            clientContext.ExecuteQuery();
        }
    }
}

Figure 1: Code snippet using Try/Catch/Finally approach

The above scenario is rife in SharePoint programming.  Based on exception you get the sign that something is missing and you need to fill the missing part.

 

Problem with this try/catch/finally approach

The code block shown in Figure 1, is using try/catch/finally approach to apply logic. We can’t change the try/catch approach as for some SharePoint items there’s no way to find if the item (list, library, web) exists or not without getting an exception. So we decide based on exception. However, in Client Object Model we are concerned with the number of requests are sent to the server. In the code snippet of Figure 1, its obvious that the ClientContext.ExecuteQuery can be executed more than once. If ExecutedQuery method in try block is failed then the ExecutedQuery method in catch block is tried and at last finally block ExecutedQuery method is executed. It would be better if we could just call the ExecutedQuery once only. That’s what we are going to get with ExceptionHandlingScope. Also the code block will look much smarter and easier to read with ExceptionHandlingScope.

 

How to use ExceptionHandlingScope?

Unfortunately, ExceptionHandlingScope is available in Microsoft.SharePoint.Client namespace and targeted to use in SharePoint Client Object Model Programming. The Exception Handling Scope block starts with StartScope() method. Inside StartScope block, you will have three different sections: StartTry, StratCatch and StartFinally. In StartScope block the first block must be StartTry followed by StartCatch and then StartFinally. the basic structure is shown below:

var clientContext = new ClientContext("http://server/site");
var exceptionHandlingScope = new ExceptionHandlingScope(clientContext);

using (exceptionHandlingScope.StartScope())
{
    using (exceptionHandlingScope.StartTry())
    {
        //write code here that can throw exception.
    }
    using (exceptionHandlingScope.StartCatch())
    {
        //if exception is thrown in StartTry block, control will be here.
    }
    using (exceptionHandlingScope.StartFinally())
    {
        //this block will alwasy be executed
    }
}

Figure 2: Exception Handling scope code block structure

Now the following code block is just like code snippet shown in Figure 1 but the following code block uses ExceptionHandlingScope.

public static void EnableListVersioningAndFolderCreation(string siteUrl, string listName, string description)
{
    using (var clientContext = new ClientContext(siteUrl))
    {
        var exceptionHandlingScope = new ExceptionHandlingScope(clientContext);

        List list;
        using (exceptionHandlingScope.StartScope())
        {
            using (exceptionHandlingScope.StartTry())
            {
                list = clientContext.Web.Lists.GetByTitle(listName);
                clientContext.Load(list);
                //clientContext.ExecuteQuery();

            }
            using (exceptionHandlingScope.StartCatch())
            {
                var listCreationInformation = new ListCreationInformation();
                listCreationInformation.Title = listName;
                listCreationInformation.TemplateType = (int)ListTemplateType.GenericList;
                listCreationInformation.Description = description;
                list = clientContext.Web.Lists.Add(listCreationInformation);
                //clientContext.ExecuteQuery();
            }
            using (exceptionHandlingScope.StartFinally())
            {
                list.EnableVersioning = true;
                list.EnableFolderCreation = true;
                list.Update();
                //clientContext.ExecuteQuery();
            }
        }
        clientContext.ExecuteQuery();
                
    }
}

Figure 3: ExceptionHandlingScope in Action as a replacement of code snippet shown in Figure 1

As shown in figure 3, using ExceptionHandlingScope construct we can put the logic in different ExceptionHandlingScope block. Also the ExecuteQuery is executed only once. The following table shows the difference of try/catch/finally approach and ExceptionHandlingScope approach:

Try/Catch/Finally Approach

ExceptionHandlingScope approach

1.Sends more than one requests to the server. One in Try block. Another in Catch block if exception is thrown. And another one from finally block 1. Only one request is sent to the server. Logics in ExceptionHandlingScope are packed together and sent to the server which is executed as a whole in a single request.
2. Code looks much easier to read and understand. Though a bit uneasy for novice. 2. Code looks not comfortable as good developers don’t like to write complex logic in catch block.
3. Number of calls to ClientContexts gets higher which makes future modifications/debugging harder as developers need to find all the places from where calls are made to the server. 3. Reducing number of calls to the server makes the debugging and modification easier.

 

Conclusion

The overall benefits of using ExceptionHandlingScope are reduced number of calls to the server which in turn results rapid responsiveness and reduce load on server. So this ExceptionHandlingScope can be a handy for SharePoint developers.

Sunday, August 8, 2010

SharePoint Service Locator

Microsoft has released SharePoint Guidance 2010. One of the important part of the guidance is SharePoint Service Locator. With this SharePoint Service Locator, you can easily decouple interface consumers from its implementation. You can get more details on SharePoint Service Locator from MSDN.

How to use Service Locator?

  1. First of all download the SharePoint guidance from this MSDN link.
  2. Now add reference to the following two dlls in your project (SharePoint Project) to use SharePoint Service Locator. You may need to compile the source code after downloading from MSDN link as the guidance may not have dlls compiled.
    • Microsoft.Practices.SharePoint.Common.dll
    • Microsoft.Practices.ServiceLocation.dll
  3. Write a bootstrapper class which will register your type mappings. Let’s consider the following example, where I have an interface ILogger and it’s implementation EventLogger.
    public interface ILogger
    {
        void WriteLog(string message);
        void WriteException(Exception exception);
    }
    
    
    
    public class EventLogger:ILogger
    {
        public void WriteLog(string message)
        {
                
        }
    
        public void WriteException(Exception exception)
        {
                
        }
    }

    Now to map the ILogger to EventLogger using SharePoint Service Locator you’ll use the type mapping code block shown below:

    var serviceLocator = SharePointServiceLocator.GetCurrent();
    var typeMapper = serviceLocator.GetInstance<IServiceLocatorConfig>();
    typeMapper.Site = SPContext.Current.Site;
    typeMapper.RegisterTypeMapping<ILogger, EventLogger>();

    So the above code block shows how to register type mappings using SharePoint Service Locator.

  4. Finally you need to put the type mapping code (shown in step 3) in some startup place so that before any type is asked from the type mapping the type is registered. In desktop application, you could put the type mapping code during project startup and in web application we usually put the type mapping in Application_Start event. However in SharePoint we can do this type mappings using Feature Event Receiver.
    public class ServiceLocatorFeatureEventReceiver : SPFeatureReceiver
    {
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            var currentSite=properties.Feature.Parent as SPSite;
            var serviceLocator = SharePointServiceLocator.GetCurrent();
            var typeMapper = serviceLocator.GetInstance<IServiceLocatorConfig>();
            typeMapper.Site = currentSite;
            typeMapper.RegisterTypeMapping<ILogger, EventLogger>();
            SharePointServiceLocator.Reset();
        }
    
    
        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            var currentSite=properties.Feature.Parent as SPSite;
            var serviceLocator = SharePointServiceLocator.GetCurrent();
            var typeMapper = serviceLocator.GetInstance<IServiceLocatorConfig>();
            typeMapper.Site = currentSite;
            typeMapper.RemoveTypeMapping<ILogger>();
            SharePointServiceLocator.Reset();
        }
    }

    As shown in the above code snippet, activating/deactivating the feature will register/unregister type. The SharePointServiceLocator.Reset() method will reset the type mappings in current Appdomain.

  5. Now you can use the registered types in your code as shown below:
var logger  = SharePointServiceLocator.GetCurrent().GetInstance<ILogger>();

 

FAQ

  • Can I control the scope of type mappings available?

Yes, you can. However, there’s only two scopes you can define your type mappings: Farm and Site Collection. By default type mapping are kept in Farm Configuration settings. However, if you set the ServiceLocatorConfig.Site property (as I have done in step 4) then the type mapping is kept in site collection Configuration Settings. For site collection scope, your feature event receiver (for type mapping) will have Site scope. Similarly if you want your type mappings will be available at Farm level, then you need to use a feature receiver with Farm level scope. If you try to put your mappings in Farm level by using an feature event receiver from site or web level you’ll get access denied error

  • How to refresh type mappings?

Service locators for farm and site level are cached and refresh periodically. By default the time is 60sec. You can change the refresh interval time by calling  SetSiteCacheInterval method in IServiceLocatorConfig interface. However, if you need to refresh typemappings immediately, then you can deactivate/activate the feature of which event receiver is used for type mappings.

  • If I reset IIs will my mappings go away?

No, the type mappings not kept in w3p (IIS process) rather in site configuration settings (or property bags) which does not reset with IIS restart.

Access Deined Error:

During development you may get the following error:

Configsetting with key 'Microsoft.Practices.SharePoint.Common.TypeMappings' could not be set 'Microsoft.Practices.SharePoint.Common.ServiceLocation.ServiceLocationConfigData' with type 'Microsoft.Practices.SharePoint.Common.ServiceLocation.ServiceLocationConfigData'. The technical exception was: System.Security.SecurityException: Access denied.

You may get the error when you’ll try to use SharePoint Service locator to register types. The problem might be in this case, you have a feature with site or web level scope and you are trying to register types for firm level. You may even get the error if you try to register types for site scope from a feature with web scope. If you want to use Site scope for type mapping set the Site property of IServiceLocatorConfig interface before registering any type as shown below:

var serviceLocator = SharePointServiceLocator.GetCurrent();
var typeMapper = serviceLocator.GetInstance<IServiceLocatorConfig>();
typeMapper.Site = currentSite;
typeMapper.RegisterTypeMapping<ILogger, EventLogger>();

Conclusion

Service Locator usage will make the code loosely coupled. It’ll also make room for putting unit test in code as using Mock implementation of a class and Service Locator we can easily bypass the SharePoint Dependency in unit testing. I’ll try to explain the unit testing stuffs using Service Locator in another post hopefully. For more details on SharePoint Guidance 2010 you can download the whole guidance stuffs from this MSDN link which is surely very useful resource for SharePoint Developers.