SharePoint Business Connectivity Services: Новые возможности

Записал скринкаст по Business Connectivity Services.

  • Принципы построения интеграционных решений на SharePoint
  • Работа с внешними данными
  • Демонстрация возможностей SharePoint BCS.
  • Обсуждение принципов работы, дистрибуции и потенциала платформы.
  • Демонстрация примеров работы с сервисом.

SharePoint 2010: Примеры работы с BCS

Введение

Предлагаю рассмотреть несколько примеров работы с SharePoint 2010 Business Connectivity Services.

Все ресурсы, связанные с Business Connectivity Services можно найти на Business Connectivity Services Resource Center. Кстати на нём же можно скачать замечательный постер-шпаргалку по технологии.

image

Для работы с рассматриваемыми примерами предлагаю вам скачать SharePoint 2010 SDK.

Adventure Works Web Service

В данном примере показана реализация стандартного asp.net asmx сервиса, ориентированного на работу с BCS. Этот сервис представляет доступ к данным из SQL Server. С помощью LINQ to SQL реализовано объектно-реляционное преобразование.

Вы наверняка согласитесь с утверждением, что при прочих равных условиях asmx сервисы создаются намного проще WCF сервисов

Для работы с ним понадобится sample database с соответствующим названием “AdventureWorks”.

Примеры баз данных (таких как AdventureWorks) для основных версий SQL Server, а так же решений для них, теперь централизованны и хранятся на CodePlex: http://msftdbprodsamples.codeplex.com/

Сервис WebService.asmx предоставляет ряд методов для стандартных операций взаимодействия с данными (Create, Read, Update, Delete).

Для наглядности предметной области основные сущности определены в виде POCO классов, к примеру:

public class SalesCustomer 
{ 
    public int CustomerId { get; set; } 

    public String Title { get; set; } 
    public String FirstName { get; set; } 
    public String MiddleName { get; set; } 
    public String LastName   { get; set; } 
    public String EmailAddress { get; set; } 
    public String Phone { get; set; } 
    public DateTime ModifiedDate { get; set; } 
}

Классы же, генерируемые LINQ to SQL используются по назначению, т.е. в качестве DataModel, которая в последствии отображается на модель предметной области. Хоть пример и учебный, было очень приятно, что он имеет довольно таки логичное и обоснованное применение технологий по назначению.

Предметная область в данном случае состоит из 3 основных сущностей:

  1. SalesCustomer
  2. SalesOrderDetail
  3. SalesOrderHeader

Причём дизайн данных сущностей ориентирован на работу с BCS, это можно проследить по построению ассоциаций между сущностями не по ссылке, а по идентификатору. К примеру, связь между SalesCostumer и SalesOrderHeader:

public class SalesOrderHeader 
{

    public int CustomerID { get; set; }

    …

}


Здесь стоит пояснить механизм работы с ассоциациями в BCS. Ассоциации в BCS – основной механизм связи нескольких “внешних типов содержимого”. Для его реализации используются так называемые Association Methods. По организации работы принцип вторит тому, что применяется в реляционных базах данных для реализации отношений, т.е. через доступ по внешнему ключу (Foreign Key).

В связи с данными особенностями в сервисе определяются специализированные методы, например этот:

[WebMethod] 
public SalesOrderHeader[] GetOrdersForCustomer(int customerId) 
{ 
    List<SalesOrderHeader> salesOrderHeaders = new List<SalesOrderHeader>(); 
    Adventureworks.SalesOrderHeader[] sohArr = 
        (from soh in dataContext.SalesOrderHeaders 
         where soh.CustomerID == customerId 
         select soh).ToArray(); 
    PopulateSalesOrderHeader(salesOrderHeaders, sohArr); 
    return salesOrderHeaders.ToArray(); 
}

Данные методы в дальнейшем будут привязаны к BCS Associations Methods, которые и будут работать для связанных сущностей.

Представленный веб-сервис следует опубликовать в IIS.

Далее, воспользовавшись SharePoint Designer 2010 создать и опубликовать BDC Model:

  • Открыть в SharePoint Designer 2010 интересующий вас узел
  • Перейти в секцию External Content Types
  • Создать новый “внешний тип содержимого”
  • В качестве источника данных выбрать WCF Service
  • Указать URL подключения и тип соединения
  • С помощью мастера произвести отображение всех необходимых веб-методов на методы BDС Model
  • Сохранить внешний тип содержимого

Данный процесс наглядно описан в SDK http://msdn.microsoft.com/en-us/library/ee556431(office.14).aspx

 

Пример файла, описывающего BDC Model
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.microsoft.com/windows/2007/BusinessDataCatalog BDCMetadata.xsd" Name="AdventureWorksWSModel" IsCached="false" xmlns="http://schemas.microsoft.com/windows/2007/BusinessDataCatalog">
   <LobSystems>
    <LobSystem Type="Wcf" Name="AdventureWorksWS">
      <Properties>
        <Property Name="WsdlFetchAuthenticationMode" Type="System.String">PassThrough</Property>
        <Property Name="WcfMexDiscoMode" Type="System.String">Disco</Property>
        <Property Name="WcfMexDocumentUrl" Type="System.String">http://webserver:90/webservice.asmx?wsdl</Property>
        <Property Name="WcfProxyNamespace" Type="System.String">BCSServiceProxy</Property>
        <Property Name="WildcardCharacter" Type="System.String">*</Property>
      </Properties>
      <LobSystemInstances>
        <LobSystemInstance Name="AdventureWorksWS">
          <Properties>
            <Property Name="WcfAuthenticationMode" Type="System.String">PassThrough</Property>
            <Property Name="WcfEndpointAddress" Type="System.String">http://webserver:90/webservice.asmx</Property>
            <Property Name="ShowInSearchUI" Type="System.String"></Property>
          </Properties>
        </LobSystemInstance>
      </LobSystemInstances>
      <Entities>
        <Entity Namespace="AdventureWorks” Version="1.0.0.0" EstimatedInstanceCount="10000" Name="WSCustomer" DefaultDisplayName="WSCustomer">
          <Properties>
            <Property Name="OutlookItemType" Type="System.String">Contact</Property>
          </Properties>
          <Identifiers>
            <Identifier TypeName="System.Int32" Name="CustomerId" />
          </Identifiers>
          <Methods>
            <Method IsStatic="false" Name="GetCustomerById">
              <Parameters>
                <Parameter Direction="In" Name="customerId">
                  <TypeDescriptor TypeName="System.Int32" IdentifierName="CustomerId" Name="customerId" />
                </Parameter>
                <Parameter Direction="Return" Name="GetCustomerById">
                  <TypeDescriptor TypeName="BCSServiceProxy.SalesCustomer, AdventureWorksWS" Name="GetCustomerById">
                    <TypeDescriptors>
                      <TypeDescriptor TypeName="System.Int32" ReadOnly="true" IdentifierName="CustomerId" Name="CustomerId" />
                      <TypeDescriptor TypeName="System.String" Name="Title" />
                      <TypeDescriptor TypeName="System.String" Name="FirstName">
                        <Properties>
                          <Property Name="OfficeProperty" Type="System.String">FirstName</Property>
                        </Properties>
                      </TypeDescriptor>
                      <TypeDescriptor TypeName="System.String" Name="MiddleName" />
                      <TypeDescriptor TypeName="System.String" Name="LastName">
                        <Properties>
                          <Property Name="OfficeProperty" Type="System.String">LastName</Property>
                        </Properties>
                      </TypeDescriptor>
                      <TypeDescriptor TypeName="System.String" Name="EmailAddress" />
                      <TypeDescriptor TypeName="System.String" Name="Phone" />
                      <TypeDescriptor TypeName="System.DateTime" Name="ModifiedDate" />
                    </TypeDescriptors>
                  </TypeDescriptor>
                </Parameter>
              </Parameters>
               <MethodInstances>
                <MethodInstance Type="SpecificFinder" ReturnParameterName="GetCustomerById" Default="true" Name="GetCustomerById" DefaultDisplayName="Read Item WSCustomer">
                 <Properties>
                   <Property Name="LastDesignedOfficeItemType" Type="System.String">Contact</Property>
                 </Properties>
                </MethodInstance>
               </MethodInstances>
            </Method>
          </Methods>
        </Entity>
      </Entities>
    </LobSystem>
  </LobSystems>
</Model>

AdventureWorksDll

Данный пример ориентирован на подключение .NET типа в качестве источника данных для внешнего типа содержимого. Фактически пример не отличается от предыдущего. Принципиальная разница состоит в том, что в данном случае сборка должна находится локально по отношению к установленному SharePoint. Все принципы дизайна методов доступа сохранены.

Кстати, данный пример практически ничем не уступает в поддержке актуальности варианту с веб-сервисом, т.к. современные методы дистрибуции .NET решений (к примеру ClickOnce) позволяют поддерживать в актуальном состоянии решение у большого количества клиентов.

Так что же происходит в BCS при работе с веб-сервисами

Механизм вполне логичен и является стандартным во многих ситуациях. Запрашивается URL, который указан в качестве адреса сервиса. На основе полученной схемы (как правило в SOAP это WSDL). Далее происходит самое интересное, в рантайме генерятся прокси-объекты для доступа к данным. Данные объекты компилируются в памяти и кэшируются для дальнейших вызовов.

Custom Connector

Кроме подключения к .NET типу, так же существует возможность реализации “своего коннектора”. В чём же принципиальная разница? В том, что коннектор является свободной абстракцией над источником данных. Т.е. подразумевается его настройка пользователем, к примеру, в SharePoint Designer’e, в отличии от .NET типа, который будет отражаться на конкретный “внешний тип содержимого”. Подробнее можно узнать здесь: http://msdn.microsoft.com/en-us/library/ee554911(office.14).aspx

BCS Cache

В заключение хочу немного рассказать о способах оптимизации ваших решений на основе BCS.

В BCS существует мощных механизм кэширования. Реализуется он на основе так называемых Cache Description. Описываются они в XML файле subscription.xml и должны располагаться в папке вместе в XML описанием BDC Model. С помощью можно описывать правила кеширования определенных методов, определенных сущностей (по их идентификатору), а так же связанных сущностей.

Так выглядит Cache Description

  <?xml version="1.0" encoding="utf-8"?>
<Subscription xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Name="CustomerQuery Item List" IsCached="true" EntityName="Customer" EntityNamespace="http://example.com" RefreshIntervalInMinutes="60" View="CustomerRead Item" LobSystemInstanceName="AdventureWorks" xmlns="http://schemas.microsoft.com/office/2006/03/BusinessDataCatalog">
  <Queries>
    <Query Name="27aa2ba2-fd5f-452c-87bb-24cf505f6071" IsCached="true" RefreshIntervalInMinutes="60" MethodInstanceName="CustomerQuery Item List" Enabled="false" />
  </Queries>
</Subscription> 

Подробнее о кэшировании можно узнать здесь: http://msdn.microsoft.com/en-us/library/ee556385(office.14).aspx