Just another WordPress.com site

Posts tagged ‘programming’

How to store custom class object in SharePoint property bag?

What is Property Bag?

SharePoint property bag is a place to store metadata or custom property value to different SharePoint objects. Property bag is implemented as a Key-Value pair hash-table.

Why to Use SharePoint Property Bag?

Generally developer use configuration file to store configurable properties like ConnectionString, some FilePath, some other custom setting. Since config file is allowed to store values as Key-Value pair, how property bag is useful to store information?


<configuration>
  <appSettings>
    <add key="WebAppLevelKey" value="MyValue1" />
    <add key="SiteLevelKey" value="MyValue2" />
    <add key="WebLevelKey" value="MyValue3" />
  </appSettings>
</configuration>

In SharePoint config file scope to web-application level so

  • We need to maintain different key-value for different scope because any value in config is same for all SPSite and SPWeb inside the web-application.
  • Config value is same for all users.
  • We should know the value at compile time. Information that is change or decide at run-time can’t be store here.

Levels

Property bag is available to SharePoint objects from SPFarm scope to SPList. Following SharePoint objects provide property bag: –

  • SPFarm
  • SPWebApplication
  • SPSite
  • SPWeb
  • SPList

UI to manage Property Bag

SharePoint doesn’t provide any interface inside the web to manage property bag. Although SharePoint designer provides a interface to manage property bag.

When you open a site in SharePoint Designer 2010, in the ribbon, all the way over to the right, you’ll see a button for Site Options

SiteOptions

By clicking on it,  a new window is opened. The first tab labeled Parameters. This parameters window is nothing else but a Property Bag window.

SiteOptionsWindow

From this window, you can add/modify/delete the property bag.

Access Property Bag through code

Most of the time property bag is useful to store information decide at run-time. As mention above different level of SharePoint object provides property bag to store data. To manage property bag through code, SharePoint API class exposes.

// Use this RunWithElevatedPrivileges to
// avoid error if user doesn't have permission to update.
SPSecurity.RunWithElevatedPrivileges(delegate()
 {
   try
    {
    using (SPSite RootSite = new SPSite(URL))
     {
      using (SPWeb rootWeb = RootSite.OpenWeb())
       {
       try
        {
         rootWeb.AllowUnsafeUpdates = true;
         // Get property value against MyKey key from Property bag
         if (rootWeb.AllProperties.ContainsKey("MyKey"))
          {
           string myValue = rootWeb.AllProperties["MyKey"].ToString();
          }
          // Set siteID in the Property bag
          rootWeb.Properties["siteID"] = siteID;
          rootWeb.Properties.Update();
          rootWeb.AllowUnsafeUpdates = false;
         }
         catch (Exception ex)
         {
           //Handle Exception
         }
        }
       }
      }
      catch(Exception ex)
      {
      }
   }
);

Store Custom Class Object INTO Property Bag

SharePoint property bag is allow to store any type of data that can be serialize. So to store custom class object, custom class should be mark as Serializable.


[System.Serializable]

public class CustomClass{

public string Name{

get;

set;

}

}

 

Advertisements

How to programmatically start sharepoint workflow

SharePoint workflow is great way to automate the business process.  SharePoint workflow can be configured to start automatic or manually. But sometimes our requirement lies in between two default options i.e. we want to start workflow automatically if and only if certain condition met e.g.  workflow initiation depends on certain business logic or depends on some field value entered by user.  If condition met we need to start workflow otherwise not. In this scenario, SharePoint default options ( Automatic OR Manual) to start workflow do not work and developer requires to start workflow at run time using code.

To start a workflow at run-time  we need two important values: –

  1. Workflow Association Reference Id OR Workflow association name: – Workflow association id that we want to start. OR workflow association name can also use to identify it.
  2. Workflow Initiation Data: – Its optional but most of the workflow requires some initiation data. Initiation data that requires by workflow to take decision. To know more about the initiation data and how to pass it, please refer http://wp.me/p1nAw1-m

To start any workflow, we requires following objects: –

  1. WorkflowManager: – With each SPSite object a SPWorkflowManager object is associated , enabling you to centrally control the workflow templates and instances across the site collection.  We can get WorkflowManager instace by SPSite instace.
    E.g.

     WorkflowManager = SPContext.Current.Web.Site.WorkflowManager;
    
  2.  SPWorkflowAssociation: – Workflow association is a binding between list/library and workflow template.  When a workflow is added to SharePoint list/library an workflow association is crated. We can get the workflow association by list/library where workflow is associated.
  3. E.g.
      SPWorkflowAssociationCollection associationColl = ParentList.WorkflowAssociations;
      foreach (SPWorkflowAssociation association in associationCollection) {
        // We can find the association by BaseId or by workflow association name.
        // if (String.Compare(objWorkflowAssociation.BaseId.ToString("B"), {"Workflow_GUID"}, true) == 0)
       // you can identify the workflow association by association name, entered during association creation.
      if (association.Name == wfName)        {
        association.AutoStartChange = true;
        association.AutoStartCreate = false;
        // We can change the
        association.AssociationData = string.Empty;
        // We can use other overload StartWorkflow methods.
       spSite.WorkflowManager.StartWorkflow(listItem, association,  association.AssociationData);
      }
    }
    

So complete code to start workflow at runtime is

public void StartWorkflow(SPListItem listItem, SPSite spSite, string wfName)  {
    SPList parentList = listItem.ParentList;
    SPWorkflowAssociationCollection associationCollection = parentList.WorkflowAssociations;
    foreach (SPWorkflowAssociation association in associationCollection)  {
      if (association.Name == wfName){
       association.AutoStartChange = true;
       association.AutoStartCreate = false;
       association.AssociationData = string.Empty;
       spSite.WorkflowManager.StartWorkflow(listItem, association,  association.AssociationData);
       }
     }
}

Implementation of Interface Dependency Injection using Microsoft Unity Block 2.0

In my previous article I try to elaborate interface dependency injection. Here I implemented a simple example. For the injection we use the Microsoft Unity 2.0 container. For more information about the Unity 2.0 container please refer MSDN.

This sample has on Project entity class as mention below:


// Project entity class
public class Project {

 public Project(string title, string id) {
  this.title = title;
  this.id = id;
 }

 private string title;

 public string Title {
  get {
   return title;
  }
  set {
   title = value;
  }
 }

 private string id;

 public string ID {
  get {
   return id;
  }
  set {
   id = value;
  }
 }

}

To access Project information from database, we have one data layer class
and another is business layer class to implement business logic.

I am assuming that different user have different database so data layer classes
implementation vary for each database type.

So sample project have two data layer class one for sql server and another for Oracle.


// Project Data Layer to interact with sql server database.
public class ProjectDLForSQLServer : IProjectDL {

 public Project GetProjectById(int id) {
   Console.WriteLine("IProjectDL is resolved as ProjectDLForSQLServer.");
   Project project = null;
   // logic to access database and return the mapped data object to project entity.
   return project;
 }

 public List<Project> GetProjects() {
   List<Project> projects = null;
   // logic to access database and return the mapped data object to project entity.
   return projects;
 }
}

Another datalayer class for Oracle.


// Project Data Layer to interact with sql server database.
public class ProjectDLForOracle : IProjectDL {

  public Project GetProjectById(int id) {
    Console.WriteLine("IProjectDL is resolved as ProjectDLForOracle.");
    Project project = null;
    // logic to get project from oracle database.
    return project;
  }

  public List<Project> GetProjects() {
    List<Project> projects = null;
    // logic to get projects from oracle database.
    return projects;
  }
}

We have single business layer class for project entity. If this business class directly instantiate data layer class as mention below:


// Project Business Layer class
public class ProjectBL {

  IProjectDL _projectDL;

  public ProjectBL() {
    // Here it directly instantiating data layer class.
    _projectDL = new ProjectDLForSQLServer();
  }

  public ProjectBL(IProjectDL projectDL) {
    _projectDL = projectDL;
  }

  public Project GetProjectById(int id) {
    return _projectDL.GetProjectById(id);
  }

  public List<Project> GetProjects() {
    return _projectDL.GetProjects();
  }
}

So if we want to deploy same dll on another client using Oracle as a back end.
We need to change in business layer and recompile whole project once again.
And also need to maintain two version of same dll just because of this kind of tight coupling.

Interface interception will solve this problem. By mean of interface interception we can decide at runtime that which class implementation should our code use.

By using Unity 2.0, we can achieve the same. Binding of interface and class implementation can be done either in code or by using xml configuration file.
Here I am using second approach i.e. by xml configuration.


<?xml version="1.0" encoding="utf-8" ?>
<configuration>

<configSections>
<!--A reference to unity dll-->
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<!--Defing assembly reference and namespace of policy injection and our custom dll-->
<assembly name="Microsoft.Practices.EnterpriseLibrary.PolicyInjection"/>
<namespace name="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers"/>

<assembly name="InterfaceInterception" />
<namespace name="InterfaceInterception, InterfaceInterception"/>

<assembly name="ITDataService" />
<namespace name="ITDataService, ITDataService"/>

<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>

<alias alias="IProjectDL" type="InterfaceInterception.IProjectDL, InterfaceInterception"/>
<alias alias="ProjectDLForSQLServer" type="InterfaceInterception.ProjectDLForSQLServer, InterfaceInterception"/>
<alias alias="ProjectDLForOracle" type="InterfaceInterception.ProjectDLForOracle, InterfaceInterception"/>

<alias alias="IewAppsSessionHandler" type="ITDataService.IewAppsSessionHandler, ITDataService"/>
<alias alias="ewAppWebSessionHandler" type="ewAppWeb.ewAppWebSessionHandler, ewAppWeb"/>

<container>

<extension type="Interception"/>
<!-- Here is the mapping of interface to class -->
<register name="IProjectMapper" type="IProjectDL" mapTo="ProjectDLForOracle">
<interceptor type="TransparentProxyInterceptor"/>
<interceptionBehavior type="PolicyInjectionBehavior"/>
</register>

</container>

</unity>

</configuration>

Above config file have complete configuration. To use this unity container class
we have created a wrapper class “UContainer”


public class UContainer : IContainerAccessor {

  private static IUnityContainer _container = null;

  public static IUnityContainer Container {
    get {
     return _container;
    }
    set {
     _container = value;
    }
  }

#region IContainerAccessor Members

  IUnityContainer IContainerAccessor.Container {
    get {
     return Container;
    }
  }

#endregion

}

public interface IContainerAccessor {

   IUnityContainer Container {
    get;
   }
}

Now all the required configuration and class implementation is completed.
Now time to use configuration to know the binding at runtime. Our business
layer class now have little different implementation.


// Project Business Layer class
public class ProjectBL {

  IProjectDL _projectDL;

  public ProjectBL() {
    // Here we are calling unity container to resolve the IProjectDL implementation.
    _projectDL = UContainer.Container.Resolve<IProjectDL>("IProjectMapper");
  }

  public ProjectBL(IProjectDL projectDL) {
    _projectDL = projectDL;
  }

  public Project GetProjectById(int id) {
    return _projectDL.GetProjectById(id);
  }

  public List<Project> GetProjects() {
    return _projectDL.GetProjects();
  }
}

In above class I don’t use any class, to resolve the current implementation to be use, use unity container.

We just missing one thing that is initialization of UContainer class.


public class UContainer : IContainerAccessor {

  private static IUnityContainer _container = null;

  public static IUnityContainer Container {
   get {
    return _container;
   }
   set {
    _container = value;
   }
 }

#region IContainerAccessor Members

  IUnityContainer IContainerAccessor.Container {
    get {
     return Container;
    }
   }

#endregion

}

public interface IContainerAccessor {

  IUnityContainer Container {
    get;
  }
}

I am using a console application to test our sample code. So in Program class, main function I am initializing UContainer class as mention below:


class Program {
 static void Main(string[] args) {
  IUnityContainer container = new UnityContainer();
  UnityConfigurationSection configSection = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
  configSection.Configure(container);
  container.AddNewExtension<EnterpriseLibraryCoreExtension>();
  UContainer.Container = container;
  ProjectBL bl = new ProjectBL();
  bl.GetProjectById(1);
  Console.ReadLine();
 }
}

Unity container instance look into default config file of project for configuration information. If any error is found in configuration file like some syntax error or some of the defined types are not able to resolve an runtime exception has been thrown.

So when you run application, you get the following output.