Showing posts with label BDC. Show all posts
Showing posts with label BDC. Show all posts

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

Monday, March 2, 2009

Custom Web Part using BDC Object Model

Sharepoint ( MOSS 2007 ) provides two BDC related web parts namely Business Data List Web Part and Business Data Related List Web Part. This blog will demonstrate writing custom web parts that read data through BDC APIs.

In this example a simple web part reads data from BDC APIs and displays it in web part panel. The custom web part (XBdc) is shown in the following figure.


Figure 1 : Custom web part reading data from BDC APIs


To create a custom web part, I will be using Visual Studio 2008 without Visual Studio .NET Extensions for SharePoint 3.0. If you download Visual Studio .NET Extensions for SharePoint, it will be a bit easier. Since extensions are not available ( as of March2009 ) for x64, I will create XBdc Web Part without using extensions.

First create a Visual Studio project of "Class Library" type. Lets name the project "XBdc" for extended BDC. The name is not important and can be anything. After creating the project add references to Microsoft.SharePoint.Portal.dll ( the dll can be found in %system drive%\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI folder ).



Figure 2 : Class Library project in Visual Studio


You will also need to sign the assembly as the web part assembly will be deployed to GAC. For signing the assembly, load project properties and check the "Sign the assembly" checkbox and choose private key file.( see following figure ).



Figure 3 : Signing custom web part assembly


The goal of the web part is to display BDC entities in a DataGrid. For this we will need references to System.Data.dll and System.Web.dll in the project.

Implementation

XBdc web part class needs to inherit from
System.Web.UI.WebControls.WebParts.WebPart . There is another WebPart class in SharePoint, but it should be avoided for the reasons listed here. Also XBdc class will override
CreateChildControls and Render methods to attach DataGrid and populate it with BDC entities.


[System.Xml.Serialization.XmlRoot(Namespace = "http://jardalu/Samples")]
public class XBdc : System.Web.UI.WebControls.WebParts.WebPart
{
protected override void CreateChildControls(){ ... }
protected override void Render(System.Web.UI.HtmlTextWriter writer){ ... }
}

To use BDC APIs, we will need to use the following namespaces

using Microsoft.Office.Server.ApplicationRegistry.MetadataModel;
using Microsoft.Office.Server.ApplicationRegistry.Runtime;

For simplicity sake, only these two namespaces are used. For complete list of APIs please visit MSDN site. Also, to keep things simple the Entity Name/Lob System Instance Name/Entity columns is hardcoded in the code.


// hardcoded entity fields
private string[] headers = { "Id", "Name", "Contact", "Phone", "Address" };

Method LoadCustomersFromBdc() will read entities from BDC and create a DataTable that can be bounded to the DataGrid in the web part. In the method, LobSystemInstance and Entity is searched through ApplicationRegistry object. Once entity is found, the method instance of type Finder is loaded. MethodInstance is executed to get all the entity instances for the finder. Finally instances are added in the data table using EntityAsDataRow method. Please note BDC also provides EntityAsDataTable property to create the data table itself.

private DataTable LoadCustomersFromBdc()
{
DataTable dt = new DataTable();
foreach (string header in headers)
{
dt.Columns.Add(new DataColumn(header));
}

// hardcoded LobSystemInstance and Entity name
LobSystemInstance lsi = ApplicationRegistry.GetLobSystemInstanceByName("CustomerLobSystemInstance");
Entity entity = lsi.GetEntities()["Customer"];
MethodInstance mi = entity.GetFinderMethodInstance();
IEntityInstanceEnumerator enumerator = entity.FindFiltered(mi.GetFilters(), lsi);
while (enumerator.MoveNext())
{
IEntityInstance instance = enumerator.Current;
if (instance == null) continue;
instance.EntityAsDataRow(dt);
}

return dt;
}

Its time now to create the DataGrid control and attach the control to Web Part ( see method CreateChildControls() )

protected override void CreateChildControls()
{
this.grid = new DataGrid();
this.grid.Width = new Unit(100, UnitType.Percentage);

this.grid.HeaderStyle.Font.Size = 10;
this.grid.HeaderStyle.Font.Bold = true;
this.grid.AlternatingItemStyle.BackColor = Color.Gray;

foreach (string header in headers)
{
BoundColumn column = new BoundColumn();
column.HeaderText = header;
column.DataField = header;
this.grid.Columns.Add(column);
}
this.grid.AutoGenerateColumns = false;

this.Controls.Add(this.grid);
base.CreateChildControls();
}

Finally DataGrid is bond to the BDC entities

protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
this.grid.DataSource = this.LoadCustomersFromBdc();
this.grid.DataBind();

this.grid.RenderControl(writer);
}


Once the custom Web Part is compiled, its time to hook it up in the SharePoint. Before hooking the XBdc Web Part, we will upload the "Customer" application definition file as the custom Web Part has hardcoded entity/lob system instance names ( see accompaning source code for model file and LOB code ).

Uploading Customer Model

  1. Compile the project CustomersLob accompanying in the source code

  2. GAC the assembly using gacutil tool

  3. Upload the accompaning model (customer.xml) into BDC



Registering XBdc Web Part in SharePoint

  1. GAC the Web Part assembly using gacutil. Please note the public key token for the assembly.

  2. Locate the virtual directory for SharePoint web site ( in the IIS Manager ). Typically the virtual directory is %system drive%\INETPUB\WWROOT\WSS\80 ( assuming web site is on port 80 )

  3. In the virtual directory, edit the web.config and add XBdc custom part in SafeControls section ( choose appropriate assembly and namespace ).

    <SafeControl
    Assembly="XBdcWebPart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def61931772d3147"
    Namespace="Jardalu.Samples.XBdcWebPart"
    TypeName="*" Safe="True" AllowRemoteDesigner="True" />

  4. Then browse to the WebSite, and go to Site Actions -> Site Settings -> Modify All Site Settings. Under that, click on "Web Parts" under Galleries.

  5. Click on "New" in the toolbar, and find the XBdc custom webpart as shown below

  6. Check the checkbox, go to the top, click on "Populate Gallery".

  7. At this time XBdc custom web part is ready to be consumed.



Source Code

Sample with complete source code can be downloaded from here.

As-is
The source code/software is provided "as-is". No claim of suitability, guarantee, or any warranty whatsoever is provided. Source Code and executable files can not be used in commercial applications.

Tuesday, January 13, 2009

Implementing custom SSO Provider

Single Sign-On (SSO*) is a feature in MOSS that provides storage and mapping of credentials. BDC and SSO are two different components in MOSS, however, SSO discussions in this article is tied with BDC and how SSO is used in BDC.

Following article (http://technet.microsoft.com/en-us/library/cc262932.aspx) shows how SSO can be configured in MOSS.

Limitations of SSO:

a) SSO works when MOSS is installed in domain ( SSO does not work when SharePoint is installed in Workgroup ).
b) SSO does not work when MOSS is configured in Forms Based Authentication mode ( FBA ).
c) Master key backup is allowed only on a floppy disk (A:)
d) No localization
e) No tools for bulk upload (credentials)

Fortunately, MOSS allows us to write our own "SSO" by implementing ISsoProvider interface. ISsoProvider interface is defined in Microsoft.SharePoint.SingleSignOn namespace and Microsoft.SharePoint.Portal.SingleSignOn.dll assembly ( url: http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.portal.singlesignon.issoprovider.aspx )

Implementing ISsoProvider:

Rather than iterating the implementation of the ISsoProvider, here is a walkthrough (http://msdn.microsoft.com/en-us/library/ms566925.aspx) of implementing ISsoProvider.

Registering SSO with BDC

MOSS allows only one default SSO provider ( default is SpsSsoProvider ), however BDC can work with multiple SSO providers. SSO provider for BDC is defined in BDC metadata model.

In the metadata model, register your SSO provider with the following code

<Property Name="SsoApplicationId" Type="System.String">AppId</Property>
<Property Name="SsoProviderImplementation" Type="System.String">MySsoProvider, My.SingleSignon, Version=1.0.0.0, Culture=neutral, PublicKeyToken=71e9def111e9429c</Property>

The above code assumes that your SSO provider is "MySsoProvider" and is present in "My.SingleSignOn" assembly.

Notes:
* SSO in MOSS is a misnomer. From the name, Single Sign-On, it appears that SSO will automatically log user into other systems. However, in reality, it only provides storage, retrieval and mapping of credentials. Other components ( such as BDC, Excel Services, Access Services etc. ) logs the user to other systems by retrieving user credentials from SSO.

Sunday, October 19, 2008

BDC : Beyond Web-Service and Database

As discussed in the previous post, Business Data Catalog only supports LOB of type web-service and database. What if you want to display your business data from your LOB through adapters ?

A little known fact of BDC is, its support of web-service through GACed proxy. Typically BDC generates web-service proxy at runtime from the WsdlFetchUrl property specified in the metadata. Instead of using WsdlFetchUrl property if
WebServiceProxyType property is used, BDC loads the proxy from GAC. The property WebServiceProxyType is specified at the LOBSystem level.

Sample

In this sample, an entity Employee will be displayed in the Business Data List where the entity is is fetched from local assembly ( GACed assembly ).



Figure 1: Employee Business Data List



Employee entity contains the following fields as described below


Employee
Id - int
LoginId - string
FirstName - string
LastName - string
Title - string


AdventureWorks class (data fetched from AdventureWorks sample database) defines finder and specific finder (namely GetEmployees and GetEmployee methods).


public class AdventureWorks : HttpWebClientProtocol
{
public IList GetEmployees(string filterName){ ... }
public Employee GetEmployee(int id){ ... }
}


The point to note is AdventureWorks is a subclass of HttpWebClientProtocol. Once the assembly is created with AdventureWorks class and Employee class and GACed, its time to hook Employee entity with BDC.

Assuming the namespace of the AdventureWorks and Employee class to "Beyond" and FullName of the assembly is "BeyondAdvWorks, Version=1.0.0.0, Culture=neutral, PublicKeyToken=22c970e70e320837".

The following metadata defines a LobSystem of type WebService and registers Beyond.AdventureWorks class as the proxy for the webservice using WebServiceProxyType property.

Click on the following figure to see the LobSystem definition.



Figure 2 : LobSystem



Entity Employee is defined in the metadata, with identity "Id" of type int ( see following figure ).



Figure 3 : Entity



Finally the two methods are modeled in the metadata ( the figure contains Finder method, download the sample for complete metadata ).



Figure 4 : Methods



In the methods, fully qualified name is used to define the TypeDescriptor for Employee class.

After hooking the Employee entity with Business Data List, the following figure shows the individual Employee.



Figure 5 : Individual entity page



See the previous post for how to hook finder and specific finder methods to the Business Data List.

Source Code

Sample with complete source code can be downloaded from here.

As-is
The source code/software is provided "as-is". No claim of suitability, guarantee, or any warranty whatsoever is provided. Source Code and executable files can not be used in commercial applications.

Friday, September 19, 2008

Business Data Catalog

Business Data Catalog (BDC) is a feature of Microsoft Office SharePoint Server ( MOSS 2007) which provides a mechanism to bring and display business data on SharePoint. BDC is simple yet powerful to use because of its no-code solution.

Power of BDC

Consider this, there is a web-service (or database) which exposes your Line of Business (LOB) data and you want to see the data on SharePoint. This can be done by writing a custom web-part. You will need a developer to write that custom web-part. Now assume the web-service requires credentials based authentication. Hopefully the developer can still handle that. If the web-service requires unique credentials for each SharePoint user, you will require a smart developer. What about you want to search the data fetched by the web-part ?

BDC's goal is to enable you to surface business data (some of the aspects described above) in Office SharePoint Server 2007 with minimal coding effort. BDC requires one to write [n1] XML based metadata.

BDC Web Part - Adventure Works Sample

MOSS 2007 comes with five Business Data Web Parts [r3] which can display a list of entity instances, display details of an entity instance, display list of related entity instances, display a list of actions associated with an entity and create a Business Data item.

In this sample, a list of entity instances are displayed using Business Data List (BDL) with Adventure Works [r4] database as LOB.


List of Products
Figure - List of Products in Adventure Works.

Steps in displaying the products list
Step 1 : Install the adventure works 2000 database [r4]
Step 2 : Install SharePoint Server 2007 SDK [r5]
Step 3 : Upload BDC metadata model for Adventure Works from SDK
- Open MOSS Central Administration
- Goto Shared Services Administration page for your shared service
- Click on "Import application definition" in the Business Data Catalog block
- Browse the adventure works model XML from SDK (C:\Program Files\2007 Office System Developer Resources\Samples\Business Data Catalog\AdventureWorks Samples\AdventureWorks2000.xml)
- Click upload




Figure - Model for Adventure Works uploaded.

At this step the BDC application definition for adventure works is uploaded.

Step 4 : Add BDL for AdventureWorks products.
- Goto your site (MySite)
- Click on Site Actions > Edit Page
- Choose to add a new Web Part




- Select Business Data List and Click OK
- A Business Data List will appear within the "Add a web part" block
- Click on "Open the tool pane"
- A Business Data List tool bar will open on the right side
- Click on the picker button and choose "Product"




- Click OK in BDL pane
- Exit the edit mode




- In the search criteria, enter your criteria where you will get all the products associated with the criteria.


Limitation of BDC
  • BDC only allows read functionality on business data. That means BDC does not support CUD (Create, Update, Delete) on business entities.
  • BDC metadata XML is tough to understand. If one is not using tools, model is hard to manage and will not necessarily qualify as "no code" solution.
  • BDC supports only web-service and database based LOB.


References
r1 : Business Data Catalog Overview [link]
r2 : SharePoint 2007: BDC - The Business Data Catalog [link]
r3 : Business Data Web Parts [link]
r4 : Adventure Works [link]
r5 : SharePoint Server 2007 SDK [link]

Notes
n1 : There are tools (Microsoft and Third parties) that help write BDC metadata XML.