Перейти к содержимому

SharePoint + WCF + jqGrid + jQueryUI. Создание справочника на сайте SharePoint

24.02.2010

Этот пост будет посвящен описанию создания справочника на сайте SharePoint с использованием WCF-сервиса, библиотеки jQuery и плагинов к ней.

Введение

В рамках запуска нового сайта ИНГГ СО РАН, который построен на SharePoint Server 2007, было решено разработать новую версию телефонного справочника сотрудников. Для клиентской части был выбран jqGrid в качестве элемента для таблицы сотрудников и jQueryUI для отображения подробной информации о сотруднике. Данные клиентская часть получает от RESTful веб-сервиса, реализованного на WCF, который развернут тут же, на сайте SharePoint.

Пара картинок того, что получилось:

WCF-сервис и PhoneBookWebpart

Справочник сотрудников отображается на странице веб-частей на сайте SharePoint в виде веб-части, содержимое которой загружается из ascx-контрола.

protected override void CreateChildControls()
{
    if (!_error)
    {
        try
        {
            base.CreateChildControls();

            if (!this.WebPartManager.DisplayMode.AllowPageDesign)
            {
                var gridControl = (JqGridPhoneBookControl)Page
                    .LoadControl("~/_controltemplates/IPGG.IntegrationSystem/PhoneBook/JqGridPhoneBookControl.ascx");
                gridControl.DivisionNumber = DivisionNumber;
                Controls.Add(gridControl);
            }
        }
        catch (Exception ex)
        {
            HandleException(ex);
        }
    }
}

Контрол JqGridPhoneBookControl.ascx практически не содержит серверного кода, за исключением значения скрытого тега <input>, с помощью которого через свойства веб-части передается номер подразделения для начальной фильтации.

<input type"hidden" id="divisionNumberFromWebpart" value='<%=DivisionNumber %>'/>
<table id="phoneBookGrid"></table>
<div id="phoneBookPager"></div>
<div id="employeeInfoContainer">
    ...
</div>

Сервис, предоставляющий данные, имеет следующий интерфейс.

[ServiceContract]
public interface IPhoneBookService
{
	[OperationContract]
	[WebInvoke(Method = &quot;GET&quot;, ResponseFormat = WebMessageFormat.Json)]
	JqGridResult<Employee> GetAllRecordsForJqGrid();

	[OperationContract]
	[WebInvoke(Method = "GET")]
	Stream GetPhoto(int employeeId);

	[OperationContract]
	[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json)]
	Employee GetRecord(int employeeId);
}

JqGridResult – класс, возвращаемый методом GetAllRecordsForJqGrid и принимаемый reader’ом jqGrid.

[DataContract]
public class JqGridResult<T>
{
	[DataMember]
	public int CurrentPage { get; set; }
	[DataMember]
	public int TotalPages { get; set; }
	[DataMember]
	public int TotalRecords { get; set; }
	[DataMember]
	public List<T> Records { get; set; }
}

Код сервиса разворачивается в GAC вместе с остальными сборками wsp-решения для SharePoint, svc-файл веб-сервиса помещается в подпапке папки c:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\LAYOUTS\ вместе с файлом web.config, в котором необходимо указать webHttpBinding

<?xml version="1.0"?>
<configuration>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="serviceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="endpointBehavior">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <services>
      <service name="IPGG.IntegrationSystem.Web.Services.PhoneBookService" behaviorConfiguration="serviceBehavior">
        <endpoint address="" binding="webHttpBinding" contract="IPGG.IntegrationSystem.Web.Services.IPhoneBookService" behaviorConfiguration="endpointBehavior"/>
      </service>
    </services>
  </system.serviceModel>
</configuration>

Для корректной работы WCF-сервисов в приложении SharePoint, необходимо установить SPWCFSupport, либо реализовать подобный код у себя в решении. Подробности зачем это нужно – здесь.

jqGrid и jQueryUI

Содержимое таблицы phoneBookGrid (см. JqGridPhoneBookControl.ascx) формируется с помощью jqGrid, плагина к jQuery, который берет данные из WCF-сервиса, описанного выше, посредством ajax-запроса, в формате json.

$("#phoneBookGrid").jqGrid({
		url: "/_layouts/IPGG.IntegrationSystem/PhoneBookService.svc/GetAllRecordsForJqGrid",
		datatype: "json",
		jsonReader: gridJsonReader,
		colNames: columnNames,
		colModel: columns,
		width: 850,
		height: 460,
		shrinkToFit: false,
		pager: "#phoneBookPager",
		rowList: [20, 50, 100, 1000],
		onSelectRow: GetEmployeeDetails,
		loadComplete: gridLoaded
	}).navGrid("#phoneBookPager", { add: false, edit: false, del: false, search: false, refresh: true }).filterToolbar();

	$("#phoneBookGrid").jqGrid("navButtonAdd", "#phoneBookPager", {
		caption: "Отобразить/Скрыть столбцы",
		title: "Изменить порядок столбцов",
		onClickButton: function() {
			$("#phoneBookGrid").jqGrid("columnChooser");
		}
	});

	$("#employeeInfoContainer").dialog({
		bgiframe: true,
		modal: true,
		autoOpen: false,
		width: 550,
		resizable: false,
		close: ClearDialog,
		buttons: {
			Ok: function() {
				$(this).dialog('close');
			}
		}
	});

jqGrid принимает json-объект с определенными именами свойств, однако можно настроить jsonReader и передавать какой угодно json-объект. В нашем случае – это JqGridResult.

var gridJsonReader = {
		root: "Records",
		page: "CurrentPage",
		total: "TotalPages",
		records: "TotalRecords",
		repeatitems: false,
		id: "Id"
	};

При щелчке по строке таблицы вызывается функция GetEmployeeDetails, которая отправляет еще один ajax-запрос к веб-сервису и отображает данные в модальном диалоге jQueryUI

function GetEmployeeDetails(id) {
	$("#employeeInfoContainer").dialog("open");
	$.ajax({
		url: "/_layouts/IPGG.IntegrationSystem/PhoneBookService.svc/GetRecord",
		data: "employeeId=" + id,
		success: ProcessInfo,
		error: ProcessError
	});
	GetImage(id);
	...
}

Фотография сотрудника берется из веб-сервиса с помощью GET-запроса

function GetImage(employeeId) {
	$("#employeeImage").attr("src", "/_layouts/IPGG.IntegrationSystem/PhoneBookService.svc/GetPhoto?employeeId=" + employeeId);
}

Вместо заключения

В данной статье не приведен код, реализующий доступ к данным. Могу лишь сказать, что это простая реализация паттерна Репозиторий на Linq To SQL. Для фильтрации, поиска и постраничного вывода использован интерфейс IQueryable<T>.

Как оказалось, нет ничего сложного в реализации и развертывании решений на jQuery и WCF под SharePoint.

Однако, если SharePoint работает на IIS7, то может возникнуть проблема, на решение которой мне пришлось потратить некоторое время.

После развертывания решения на production-сервере, выдавалась 404 ошибка при запросах на URL типа “~/_layouts/IPGG.IntegrationSystem/PhoneBookService.svc/GetRecord”.

Решение состоит в том, что необходимо зарегистрировать обработчник запросов для .svc. По умолчанию, в IIS7 для SharePoint-сайта этого не сделано.

{
if (!_error)
{
try
{
base.CreateChildControls();

if (!this.WebPartManager.DisplayMode.AllowPageDesign)
{
var gridControl =
(JqGridPhoneBookControl)Page.LoadControl(
“~/_controltemplates/IPGG.IntegrationSystem/PhoneBook/JqGridPhoneBookControl.ascx”);
gridControl.DivisionNumber = DivisionNumber;
Controls.Add(gridControl);
}
}
catch (Exception ex)
{
HandleException(ex);
}
}
}

Комментарии (2) leave one →
  1. 06.12.2010 14:53

    Скажите пожалуйста, сколько примерно ушло времени на реализацию данного решения?

Добавить комментарий

Fill in your details below or click an icon to log in:

Логотип WordPress.com

You are commenting using your WordPress.com account. Log Out / Изменить )

Фотография Twitter

You are commenting using your Twitter account. Log Out / Изменить )

Фотография Facebook

You are commenting using your Facebook account. Log Out / Изменить )

Connecting to %s

Follow

Get every new post delivered to your Inbox.