Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

13 August, 2012

Implementing the Service Locator Pattern

The idea of a service locator is to have a single point of reference to obtain a service needed by an application. The service locator acts as a registry for services and provides functionality for registering and retrieving references to services.

A service locator implementation consists of three components:

  1. Service interface(s)
  2. Service implementation(s)
  3. Service locator

The picture below illustrates how the service locator, the interfaces (I1, I2 and I3) and the service implementations (Service 1, Service 2 and Service 3) are connected.


The following illustrates an example of how the service locator pattern can be implemented.

All interfaces implement a global interface called IService:
public interface IService { }
This example uses two services Products and Users. For each service an interface is defined:
// Interface for product service
public interface IProductService : IService
{
    // Get all products
    List<Product> GetProducts();
}

// Interface for user service
public interface IUserService : IService
{
    // Get all products
    List<User> GetUsers();
}
The service implementations implement the interfaces:
public class ProductService : IProductService
{
    // Get all products
    List<Product> GetProducts()
    {
        // Return List of products
    }
}

public class UserService : IUserService
{
    // Get all products
    List<User> GetUsers()
    {
        // Return list of users
    }
}
The service locator is implemented using the singleton pattern and provides a registry for registering and retrieving service references. Services a registered using the service interfaces:
public class ServiceLocator
{
    // Service Locator
    private static ServiceLocator _serviceLocator;
        
    // Lock to make singleton pattern thread safe
    private static object _lock = new object();

    // Dictionary of all available services
    private Dictionary<Type, IService> _services;

    // Constructor to initialize all services
    private ServiceLocator() 
    {
        _services = new Dictionary<Type, IService>();
        _services.Add(typeof(IProductService), new ProductService());
        _services.Add(typeof(IUserService), new UserService());
    }

    // Get service locator
    public static ServiceLocator GetServiceLocator()
    {
        lock (_lock)
        {
            if (_serviceLocator == null)
                _serviceLocator = new ServiceLocator();
        }
        return _serviceLocator;
    }

    // Get service of type T
    public T GetService()
    {
        return (T)_services[typeof(T)];
    }
}
To receive a reference to a service through the service locator, the application calls the generic GetService method on the service locator:
var serviceLocator = ServiceLocator.GetServiceLocator();
var productService = serviceLocator.GetService<IProductService>();
var products = productService.GetProducts();
The service locator pattern reduces the dependency on the implementation and makes it easy to substitute service implementation without changing the entire application. In this case if products were read from a database, the implementation could be changed to read from an XML file by simply changing the service implementation.

18 July, 2012

Extension Methods for SharePoint fields

By combining the blog on 'Reading and writing SharePoint field values' and 'Extension Methods' the following extension methods for reading and writing data to SharePoint fields have been implemented:
namespace SharePointExtensions.ListItem
{
    public static class ListItemExtensions
    {
        // Get value from text/multiline/single-choice field
        public static string GetStringValue(this SPListItem item, string columnName)
        {
            return item[columnName] as String;
        }

        // Get value from number field
        public static Double? GetNumberValue(this SPListItem item, string columnName)
        {
            return item[columnName] as Double?;
        }

        // Get value from currency field
        public static Double? GetCurrencyValue(this SPListItem item, string columnName)
        {
            return item[columnName] as Double?;
        }

        // Get value from datetime field
        public static DateTime? GetDateTimeValue(this SPListItem item, string columnName)
        {
            return item[columnName] as DateTime?;
        }

        // Get value from multiple choice field
        public static SPFieldMultiChoiceValue GetMultipleChoiceValueCollection(this SPListItem item, string columnName)
        {
            if (item[columnName] == null) return null;
            return new SPFieldMultiChoiceValue(item[columnName] as string);
        }

        // Set multi choice field to the given choices
        public static void SetMultipleChoiceValueCollection(this SPListItem item, string columnName, string[] choices)
        {
            var value = new SPFieldMultiChoiceValue();
            foreach (var choice in choices)
                value.Add(choice);
            item[columnName] = value;
            item.Update();
        }

        // Add choice to multi choice field 
        public static void AddChoiceToMultipleChoiceValueCollection(this SPListItem item, string columnName, string choice)
        {
            SPFieldMultiChoiceValue value;
            if (item[columnName] != null)
                value = item[columnName] as SPFieldMultiChoiceValue;
            else
                value = new SPFieldMultiChoiceValue();

            value.Add(choice);
            item[columnName] = value;
            item.Update();
        }

        // Get value from lookup field
        public static SPFieldLookupValue GetLookupValue(this SPListItem item, string columnName)
        {
            if (item[columnName] == null) return null;
            return new SPFieldLookupValue(item[columnName] as string);
        }

        // Set value of a lookup field
        public static void SetLookupValue(this SPListItem item, string columnName, int itemId)
        {
            item[columnName] = itemId;
        }

        // Get value from multiple lookup field
        public static SPFieldLookupValueCollection GetLookupValueCollection(this SPListItem item, string columnName)
        {
            if (item[columnName] == null) return null;
            return new SPFieldLookupValueCollection(item[columnName] as string);
        }

        // Set value of multiple lookup field
        public static void SetLookupValueCollection(this SPListItem item, string columnName, int[] itemIds)
        {
            var value = new SPFieldLookupValueCollection();
            foreach (int i in itemIds)
                value.Add(new SPFieldLookupValue(i.ToString()));

            item[columnName] = value;
        }

        // Add value tos multiple lookup field
        public static void AddLookupToLookupValueCollection(this SPListItem item, string columnName, int itemId)
        {
            SPFieldLookupValueCollection value;
            if (item[columnName] != null)
                value = item[columnName] as SPFieldLookupValueCollection;
            else
                value = new SPFieldLookupValueCollection();

            value.Add(new SPFieldLookupValue(itemId.ToString()));
            item[columnName] = value;
        }

        // Get value from true/false field
        public static Boolean? GetTrueFalseValue(this SPListItem item, string columnName)
        {
            return item[columnName] as Boolean?;
        }

        // Get value from user field
        public static SPFieldUserValue GetUserValue(this SPListItem item, string columnName)
        {
            if (item[columnName] == null) return null;
            var userField = item.ParentList.Fields.GetFieldByInternalName(columnName);
            return userField.GetFieldValue(item[columnName] as string) as SPFieldUserValue;
        }

        // Get value from multi user field
        public static SPFieldUserValueCollection GetUserValueCollection(this SPListItem item, string columnName)
        {
            if (item[columnName] == null) return null;
            return item[columnName] as SPFieldUserValueCollection;
        }

        // Set value of multi user field
        public static void SetUserValueCollection(this SPListItem item, string columnName, int[] userIds)
        {
            var web = item.Web;
            var value = new SPFieldUserValueCollection();
            foreach (int i in userIds)
                value.Add(new SPFieldUserValue(web, i.ToString()));
            item[columnName] = value;
        }

        // Add value to multi user field
        public static void AddUserToValueCollection(this SPListItem item, string columnName, int userId)
        {
            var web = item.Web;
            SPFieldUserValueCollection value;
            if (item[columnName] != null)
                value = item[columnName] as SPFieldUserValueCollection;
            else
                value = new SPFieldUserValueCollection();

            value.Add(new SPFieldUserValue(web, userId.ToString()));
            item[columnName] = value;
        }

        // Get value for url and image field
        public static SPFieldUrlValue GetUrlValue(this SPListItem item, string columnName)
        {
            if (item[columnName] == null) return null;
            return new SPFieldUrlValue(item[columnName] as string);
        }

        // Set value for url and image field
        public static void SetUrlValue(this SPListItem item, string columnName, string url, string description)
        {
            var value = new SPFieldUrlValue { Url = url, Description = description };
            item[columnName] = value;
        }

        // Get value for Managed Metadata field
        public static TaxonomyFieldValue GetTaxonomyValue(this SPListItem item, string columnName)
        {
            return item[columnName] as TaxonomyFieldValue;
        }

        // Set value for Managed Metadata field
        public static void SetTaxonomyValue(this SPListItem item, string columnName, Guid termId)
        {
            var field = item.Fields[columnName] as TaxonomyField;
            var session = new TaxonomySession(item.Web.Site);
            var term = session.GetTerm(termId);
            field.SetFieldValue(item, term);
        }

        // Get values for Managed Metadata field
        public static TaxonomyFieldValueCollection GetTaxonomyValueCollection(this SPListItem item, string columnName)
        {
            return item[columnName] as TaxonomyFieldValueCollection;
        }

        // Set values for Managed Metadata field
        public static void SetTaxonomyValueCollection(this SPListItem item, string columnName, Guid[] termIds)
        {
            var field = item.Fields[columnName] as TaxonomyField;
            var session = new TaxonomySession(item.Web.Site);
            var terms = session.GetTerms(termIds);
            field.SetFieldValue(item, terms);
        }
    }
}

Extension Methods

Extension methods were introduced with C# 3.0 and allow the developer to extend an existing type with new functionality without modifying the original type. Extension methods are implemented as static methods that reference the target type by using the ‘this’ keyword. Visual Studio automatically provides intellisense support and compile time checking for all extension methods.

The following example adds an extension method to the string type that determines if the length of a sting is equal to or larger than a given length:
namespace ExtensionMethods
{
    public static class ExtensionMethods
    {
        public static bool HasMinLength(this string s, int minLength)
        {
            return s == null ? false : s.Length >= minLength;
        }
    }
}
To use the extension method the namespace of the extension method must either be imported or part of a parent namespace of the current class:
using ExtensionMethods;

namespace MyProgram
{
    class Program
    {
        public static void Main(string[] args)
        {
            var s = "MyString";
            
            if(s.HasMinLength(5))
                Console.WriteLine("Length is not to short");
            else
                Console.WriteLine("Length is to short");
        }
    }
}
Extension methods support inheritance of classes which means that an extension method for a parent type is also available to inherited types. By creating an extension method for the object type the extension method is available to all types since the object type is the base class of every type:
public static bool IsOfType(this object o, Type t)
{
    return o.GetType() == t;
}
This method can now be used on all objects to determine if an object is of a particular type:
var s = "MyString";
var i = 11;

s.IsOfType(typeof(string));  // Returns true
i.IsOfType(typeof(double));  // Returns false
There are no security risks by using extension methods since extension methods cannot be used to override instance methods and the extension method is not able to access any private variables of the class. This means that if an extension method contains the same name and signature as an instance method, the instance method will always be called during execution.