in SharePoint 2010

Using DynamicType in Custom BCS Connectors

Using BCS in SharePoint 2010, you can not only build custom BDC models (using SharePoint Designer 2010 & Visual Studio 2010), but also custom BCS Connectors to integrate external data into SharePoint.

Here is the MSDN article that differentiates between using the out of the box .NET assembly connector and writing a custom connector – http://msdn.microsoft.com/en-us/library/ee554911.aspx

Consider the custom connector as the mediator between the BDC model and the external system. The model usually defines the connector:

<LobSystem Type="Database" Name="AdventureWorksLT2008R2">

The above tells the model to use the Database connector.

SharePoint currently provides connectors for Database, WCF and .NET Assembly. If this list doesn’t satisfy your needs, you can build your own custom connector.

Here is the MSDN article on how to build your own BCS Connector – http://msdn.microsoft.com/en-us/library/ff953161.aspx

I am not going to go through the steps of building a BCS connector as the article linked above explains it really well and you can also download the FileSystemConnector sample (linked in the article).

What I am going to discuss is what is a DynamicType and how to use it in your custom connector

A brief look at the FileSystemConnector sample

If you look at the FileSystemConnector sample, the SpecificFinder and Finder return FileInfo objects:

//This connector works based on the type of the MethodInstance
//Most other connectors work on the name of the method
if (methodInstance.MethodInstanceType == MethodInstanceType.Finder)
{
    //Connector assumption:
    //First parameter will always be a wildcarded search string for file name
    //Second parameter will always be the return value
    String wildcard = methodSignatureArgs[0] as string;
    IList<FileInfo> results = new List<FileInfo>();
    methodSignatureArgs[1] = baseFolder.GetFiles(wildcard);
}
else if (methodInstance.MethodInstanceType == MethodInstanceType.SpecificFinder)
{
    //Connector assumption: 
    //First parameter will always be the file name
    //Second parameter will always be the return value
    string fileName = methodSignatureArgs[0] as string;
    FileInfo result = new FileInfo(Path.Combine(baseFolder.FullName, fileName));
    if (result.Exists && result.Directory.FullName.Equals(baseFolder.FullName))
    {
        methodSignatureArgs[1] = result;
    }
}

and in the model:

<Parameter Direction="Return" Name="FileDetails">
  <TypeDescriptor TypeName="System.IO.FileInfo, mscorlib, Version=2.0.0.0, 
Culture=neutral, PublicKeyToken=b77a5c561934e089"  Name="FileDetails">
    <TypeDescriptors>
      <TypeDescriptor Name="Name" TypeName="System.String" IdentifierName="FileName" 
                                      ReadOnly="true" />
      <TypeDescriptor Name="Attributes" 
            TypeName="System.IO.FileAttributes, mscorlib, Version=2.0.0.0, Culture=neutral, 
                                                    PublicKeyToken=b77a5c561934e089" 
            ReadOnly="true"/>
      <TypeDescriptor Name="LastWriteTimeUtc" TypeName="System.DateTime" ReadOnly="true">
        <Interpretation>
          <NormalizeDateTime LobDateTimeMode="UTC"/>
        </Interpretation>
      </TypeDescriptor>
    </TypeDescriptors>
  </TypeDescriptor>
</Parameter>

This is all good as long as the type you want to return back remains static all the time.

What is a DynamicType?

What if the properties/type keep changing in the external system? You can no longer have a class defined for it. You are pushed to create dynamic types on the fly, and DynamicType to the rescue!

From MSDN:

This type can be used with assemblies to be used with a .Net Assembly connector when the data structure on the external system is not static. The default type reflector in Business Data Connectivity (BDC) service can work with the DynamicType as if it is a complex .Net structure.

How to use DynamicType?

I modified the FileSystemConnector to use DynamicType.

Below is my Finder and SpecificFinder methods using the DynamicType:

private IList<DynamicType> GetFiles(DirectoryInfo baseFolder, string wildcard)
{
    List<DynamicType> files = null;
    DynamicType dynFileType = null;

    IList<FileInfo> results = new List<FileInfo>();
    results = baseFolder.GetFiles(wildcard);

    if (results != null)
    {
        files = new List<DynamicType>();

        foreach (FileInfo fileInfo in results)
        {
            dynFileType = new DynamicType("File");
            dynFileType.Add("Name", fileInfo.Name);
            dynFileType.Add("Extension", fileInfo.Extension);

            files.Add(dynFileType);
        }
    }

    return files;
}

private DynamicType GetFile(DirectoryInfo baseFolder, FileInfo fileInfo)
{
    DynamicType dynFileType = null;

    if (fileInfo.Exists && fileInfo.Directory.FullName.Equals(baseFolder.FullName))
    {
        dynFileType = new DynamicType("File");
        dynFileType.Add("Name", fileInfo.Name);
        dynFileType.Add("Extension", fileInfo.Extension);
    }

    return dynFileType;
}

It is as simple as using KeyValuePair! If you have another look at the DynamicType’s MSDN link, it is indeed collection KeyValuePair:

public sealed class DynamicType : MarshalByRefObject,
    IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>,
    IEnumerable<KeyValuePair<string, Object>>, IDictionary, ICollection,
    IEnumerable, IXmlSerializable

And below is the model XML for SpecificFinder:

<Method Name="ReadFile">
  <Parameters>
    <Parameter Direction="In" Name="FileName">
      <TypeDescriptor TypeName="System.String" IdentifierName="FileName" Name="FileName" />
    </Parameter>
    <Parameter Direction="Return" Name="File">
      <TypeDescriptor TypeName="Microsoft.BusinessData.Runtime.DynamicType"  Name="File">
        <TypeDescriptors>
          <TypeDescriptor Name="Name" TypeName="System.String" IdentifierName="FileName" 
                       ReadOnly="true" />
          <TypeDescriptor Name="Extension" TypeName="System.String" ReadOnly="true" />
        </TypeDescriptors>
      </TypeDescriptor>
    </Parameter>
  </Parameters>
  <MethodInstances>
    <MethodInstance Type="SpecificFinder"
            ReturnParameterName="File"
            Name="FileSystemFinder">
    </MethodInstance>
  </MethodInstances>
</Method>

and for Finder:

<Method Name="ReadFiles">
  <FilterDescriptors>
    <FilterDescriptor Type="Wildcard" Name="FileFilter" />
  </FilterDescriptors>
  <Parameters>
    <Parameter Direction="In" Name="FileName">
      <TypeDescriptor TypeName="System.String"  Name="FileName" AssociatedFilter="FileFilter">
        <DefaultValues>
          <DefaultValue MethodInstanceName="FileSystemFinders" Type="System.String">*</DefaultValue>
        </DefaultValues>
      </TypeDescriptor>
    </Parameter>
    <Parameter Direction="Return" Name="Files">
      <TypeDescriptor TypeName="Microsoft.BusinessData.Runtime.DynamicType[]" Name="Files" 
                                                     IsCollection="true">
        <TypeDescriptors>
          <TypeDescriptor TypeName="Microsoft.BusinessData.Runtime.DynamicType" Name="File">
            <TypeDescriptors>
              <TypeDescriptor Name="Name" TypeName="System.String" IdentifierName="FileName" 
                                                        ReadOnly="true" />
              <TypeDescriptor Name="Extension" TypeName="System.String" ReadOnly="true" />
            </TypeDescriptors>
          </TypeDescriptor>
        </TypeDescriptors>
      </TypeDescriptor>
    </Parameter>
  </Parameters>
  <MethodInstances>
    <MethodInstance Type="Finder"
                    ReturnParameterName="Files"
                    Name="FileSystemFinders">
    </MethodInstance>
  </MethodInstances>
</Method>

and here is the external list:

image

Where to use DynamicType?

At present, there is no documentation from Microsoft on the best practices of using DynamicType.

From my experience so far, you should be using the DynamicType only when building custom connectors.

Even though the MSDN link says that DynamicType can be used with assemblies to be used with a .Net Assembly connector, I wouldn’t. In .NET assembly connectors, you always build the model ( in other words, the type remains static) and actually simplifies the development by interpreting types as standard .NET framework types.

You can download the DynamicType FileSystemConnector sample here – http://www.box.net/shared/5fub7mnmr8

Write a Comment

Comment


× seven = 7

  1. Hi

    very nice artcle on returning dynamic types.
    However got a little doubt on recompiling.
    The MSDN article

    http://msdn.microsoft.com/en-us/library/ee554911.aspx?ocid=soc-n-SA-loc-EPG-v-ayele&lc=1033

    says (at last)
    If the back-end interfaces frequently change, the custom connector approach is recommended. By using this approach, [b]only changes to the model are required[/b].

    Does it mean the assembly doesn’t need to be recompiled?
    we will obviousbly be changing the proxy class to accomplish changes in the schema where we need recompilation.

    Or does it convery somethign like we need to make our proxy class implementation very generic to avoid recompilation?

    please clarify.

  2. @Thiru – If your business logic & business models in the runtime change, then you need to recompile the custom connector and deploy to the GAC.

    The ECT(BDC model) can remain the same if the business models do not change. So, in my exammple I could update the GetFiles method with a new logic but my ECT will remain the same – in this case, I re-compile my custom connector and deploy to GAC. End users and administrators will not see any difference. However, you might want to edit the ECT(BDC model) if you want to include more properties.

    Hope that helps.

    Cheers,
    Chaks