Creating SharePoint 2010 external content types programmatically

In this code sample I provide an extension to the standard SharePoint Business Conectivity Services admin API that helps to create external content types and the related external lists using client side APIs. A console application is used to illustrate the usage of the extension.

C# (40.6 KB)
 
 
 
 
 
3.8 Star
(4)
2,182 times
Add to favorites
3/10/2011
E-mail Twitter del.icio.us Digg Facebook
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.BusinessData.Administration.Client;
using System.Reflection;
using Microsoft.BusinessData.MetadataModel;

namespace BCSModelGeneration
{
    public static class Extensions
    {

        // the listDataSource parameter is only a fake one to enable attaching the static method to ListDataSource type
        public static IDictionary<String, String> Initialize(this ListDataSource listDataSource, String entity, String entityNamespace, String lobSystemInstance, String specificFinder)
        {
            // BDCProperties (SPListDataSource internal class) are not available from client code, we should use string literals
            Dictionary<String, String> result = new Dictionary<String, String>();
            result.Add("Entity", entity);
            result.Add("EntityNamespace", entityNamespace);
            result.Add("LobSystemInstance", lobSystemInstance);
            result.Add("SpecificFinder", specificFinder);

            return result;
        }

        public static IdentifierReference GetReference(this Identifier identifier)
        {
            // to protect method against possible direct call with null value
            // should not happen when called like a "standard" extension method
            if (identifier == null)
            {
                throw new ArgumentNullException("identifier");
            }

            Entity entity = identifier.Entity;
            EntityReference entityReference = entity.GetReference();
            IdentifierReference result = new IdentifierReference(identifier.Name, entityReference, entity.GetCatalog());

            return result;
        }

        public static EntityReference GetReference(this Entity entity)
        {
            // to protect method against possible direct call with null value
            // should not happen when called like a "standard" extension method
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            // IMPORTANT! name and namespace parameters are in opposite order 
            // in the case of Entity.Create method and EntityReference constructor
            EntityReference result = new EntityReference(entity.Namespace, entity.Name, entity.GetCatalog());

            return result;
        }

        // unfortunately, there is no (yet) "extension property" in .NET
        // so we must create a "get" extension method instead
        public static AdministrationMetadataCatalog GetCatalog(this Entity entity)
        {
            // to protect method against possible direct call with null value
            // should not happen when called like a "standard" extension method
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            AdministrationMetadataCatalog result = null;

            MethodCollection methods = entity.Methods;

            // a new MethodColletion is created on each Entity creation (see internal Entity constructor)
            // so it shouldn't be null
            if (methods != null)
            {
                Type methodCollectionType = typeof(MethodCollection);
                FieldInfo fi_metadataCatalog = methodCollectionType.GetField("metadataCatalog", BindingFlags.NonPublic | BindingFlags.Instance);
                result = (AdministrationMetadataCatalog)fi_metadataCatalog.GetValue(methods);
            }

            return result;
        }

        public static TypeDescriptor CreateChildTypeDescriptor(this TypeDescriptor typeDescriptor, TypeDescriptorParams typeDescrParams)
        {
            // to protect method against possible direct call with null value
            // should not happen when called like a "standard" extension method
            if (typeDescriptor == null)
            {
                throw new ArgumentNullException("typeDescriptor");
            }

            typeDescrParams.ResolveNames();

            TypeDescriptor result = typeDescriptor.ChildTypeDescriptors.Create(
                typeDescrParams.Name,
                typeDescrParams.IsCached,
                ResolveForBcs(typeDescrParams.Type),
                typeDescrParams.LobName,
                typeDescrParams.IdentifierReference,
                typeDescrParams.FilterDescriptor,
                typeDescrParams.Flags,
                typeDescrParams.AssociationReference);

            return result;
        }

        public static TypeDescriptor CreateRootTypeDescriptor(this Parameter parameter, TypeDescriptorParams typeDescrParams)
        {
            // to protect method against possible direct call with null value
            // should not happen when called like a "standard" extension method
            if (parameter == null)
            {
                throw new ArgumentNullException("parameter");
            }

            typeDescrParams.ResolveNames();

            TypeDescriptor result = parameter.CreateRootTypeDescriptor(
                typeDescrParams.Name,
                typeDescrParams.IsCached,
                ResolveForBcs(typeDescrParams.Type),
                typeDescrParams.LobName,
                typeDescrParams.IdentifierReference,
                typeDescrParams.FilterDescriptor,
                typeDescrParams.Flags,
                typeDescrParams.AssociationReference,
                typeDescrParams.MetadataCatalog);

            return result;
        }

        public static Identifier CreateIdentifier(this Entity entity, String name, bool isCached, Type type)
        {
            // to protect method against possible direct call with null value
            // should not happen when called like a "standard" extension method
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            Identifier result =
                entity.Identifiers.Create(name, isCached, ResolveForBcs(type)); 

            return result;
        }

        private static string ResolveForBcs(Type type)
        {
            String typeName = null;
            
            if (type != null)
            {
                typeName = (type.Module.ScopeName == "CommonLanguageRuntimeLibrary") ? type.ToString() : type.AssemblyQualifiedName;
            }

            return typeName;
        }
    }

}