Friday, January 22, 2010

Reading BDC model properties in .NET Assembly Connector

Introduction

BDC in SharePoint 2010 support connectors for "Web Service", "Wcf Service", "Database", ".NET Assembly" and "Custom". ( BDC in MOSS 2007 has support for "Web Service" and "Database" only ).

.NET Assembly Connector basically allows to host a virtual LobSystem. The concept for .NET assembly connector is very similar to my suggestions of hosting .NET assembly in MOSS 2007 - BDC : Beyond Web-Service and Database.  Since .NET assembly is natively supported in SharePoint 2010, it has way more capabilities than my suggested approach. The following article (http://msdn.microsoft.com/en-us/library/aa868997.aspx) explains how to create a .NET Assembly Connector in BDC.

This blog explains how you can use BDC model properties within your .NET assembly code.

IContextProperty Interface

To use the BDC model in the .NET assembly, lets first take a look at the IContextProperty interface [r1]. IContextProperty interface is defined in Microsoft.BusinessData.SystemSpecific namespace ( in Microsoft.BusinessData.dll )

namespace Microsoft.BusinessData.SystemSpecific
{
    public interface IContextProperty
    {
        IExecutionContext ExecutionContext { get; set; }
        ILobSystemInstance LobSystemInstance { get; set; }
        IMethodInstance MethodInstance { get; set; }
    }
}
Figure 1: IContextProperty interface

.NET assembly connector in BDC uses IContextProperty interface to communicate the context in which BDC is executing the method in the class. If your class implements IContextProperty interface, BDC will initialize the three properties of the interface. Here is an example how you can write your class to implement the interface.

using Microsoft.BusinessData.SystemSpecific;

namespace MyNamespace
{
    public class MyClass : IContextProperty
    {
        private IExecutionContext context;
        private ILobSystemInstance lobSystemInstance;
        private IMethodInstance methodInstance;

        #region Implementing IContextProperty interface

        public IExecutionContext ExecutionContext 
        { 
            get { return this.context; } 
            set { this.context = value; }
        }

        public ILobSystemInstance LobSystemInstance
        { 
            get { return this.lobSystemInstance; } 
            set { this.lobSystemInstance = value; }
        }

        public IMethodInstance MethodInstance
        { 
            get { return this.methodInstance; } 
            set { this.methodInstance= value; }
        }

        #endregion
    }
}
Figure 2: IContextProperty implementation

At this time "MyClass" class is ready to get the context from BDC.


Defining properties in BDC Model

Depending on what kind of information you need in the .NET code, you can define your property at appropriate element in the BDC model. For example, if your class needs to connect to different server for different region, LobSystemInstance would be a good place to define your property. In the case method needs to know which Locale is preferred by the user, it can look into the properties of Method or MethodInstance.

In this example, the class connects to a different database server based on which region the code is getting executed.

private string GetDbConnectionString(string region)
{
    string dbConnectionStringFormat = "Data Source={0};Initial Catalog=myDataBase;Integrated Security=SSPI;";
 
    // default DB Server
    string regionDbServer = "northamericaDBServer"; 

    if (region == "emea")
    {
        regionDbServer = "emeaDbServer";
    }
    else if (region == "asia")
    {
        regionDbServer = "asiaDbServer";
    }

    return string.Format(dbConnectionStringFormat, region);
}
Figure 3: Customize connection string

The above code relies on the region information to format DB connection string. Unfortunately, when the code gets executed in SharePoint, the method has no idea where it is being executed and would default to using north america db server.

To solve this issue, you can define a property in the BDC model which tells the code which DB server to use. Lets say the property name is "Region" and is defined within the LobSystemInstance.

<LobSystemInstances>
  <LobSystemInstance Name="NorthAmerica">
    <Properties>
      <Property Name="Region" Type="System.String">northamerica</Property>
    </Properties>
  </LobSystemInstance>
  <LobSystemInstance Name="Default">
    <Properties>
      <Property Name="Region" Type="System.String">northamerica</Property>
    </Properties>
  </LobSystemInstance>
  <LobSystemInstance Name="EMEA">
    <Properties>
      <Property Name="Region" Type="System.String">emea</Property>
    </Properties>
  </LobSystemInstance>
  <LobSystemInstance Name="Asia">
    <Properties>
      <Property Name="Region" Type="System.String">asia</Property>
    </Properties>
  </LobSystemInstance>
</LobSystemInstances>
Figure 4: BDC model properties

In this example, different LobSystemInstances are used for each region, where the "Region" property is defined in LobSystemInstance. This is particularly useful when the user creates an external list. The user can choose the appropriate LobSystemInstance depending on its region.

Reading properties in the method

So now that the properties are defined in the model, its time to read the property in the code. The class "MyClass" exposes a method ReadAllItems for Finder stereotype. In this method, LobSystemInstance property returns the LobSystemInstance (BDC context).  LobSystemInstance.GetProperties() method returns all the properties defined for the LobSystemInstance.

public MyItems ReadAllItems()
{
   // get the LobSystemInstance properties via context from BDC
   INamedPropertyDictionary properties = this.LobSystemInstance.GetProperties();

   string region = null;

   // search for "Region" property in model
   if (properties.ContainsKey("Region"))
   {
        region = properties["Region"] as string;
   }

   //get the db connection string
   string dbConnectionString = GetDbConnectionString(region);

   //do normal db processing
   //return the items for method

}
Figure 5: Use the BDC model property

Once we have all the properties, the code checks if the "Region" property has been defined or not and reads the "Region" property accordingly. Once the Region property is read, it is used to create the DB connection string and the DB query is executed against that particular DB server.

Conclusion

BDC model is the right place to define custom properties. These properties should be used in .NET assembly connector code to customize solutions.

References

r1: IContextProperty interface: http://msdn.microsoft.com/en-us/library/microsoft.businessdata.systemspecific.icontextproperty(office.14).aspx

No comments: