Расширенная функциональность
16
Фев
3

CRM 2013 или найди 10 отличий… Разработка

.Net

Асинхронное выполнение запросов

Новый SDK включает новый метод – ExecuteAsyncRequest – который позволяет выполнять запросы асинхронно и который, в данный момент, работает только для асинхронного импорта Решений (ImportSolutionRequest). Будем надеяться, что в ближайшее время список поддерживаемых запросов расширится.

Преимущества понятны: Вам не нужно ожидать окончания выполнения запроса, чтобы заняться другими делами. Это также положительно скажется на производительности системы, т.к. запрос может быть выполнен, когда имеется больше свободных ресурсов сервера.

Ответ запроса включает свойство AsyncJobId, которое Вы можете использовать, чтобы узнать в каком состоянии находится запрос в настоящее время.

Пример асинхронного импорта Решения:

var connection = new CrmConnection("Crm");
var service = new OrganizationService(connection);
var context = new CrmOrganizationServiceContext(connection);

IOrganizationService sdk = (IOrganizationService)context;
ExecuteAsyncRequest request = new ExecuteAsyncRequest
{
    Request = new ImportSolutionRequest
    {
        CustomizationFile = File.ReadAllBytes(pathToSolutionFile),
        PublishWorkflows = true,
    }
};

ExecuteAsyncResponse response = (ExecuteAsyncResponse)sdk.Execute(request);

JavaScript

Асинхронная загрузка скриптов

Скрипты в CRM 2013 обзавелись новым асинхронным загрузчиком. Сделано это было, чтобы ускорить загрузку формы. Но у любой медали две стороны и теперь Вам, возможно, придется учитывать некоторые особенности поведения скриптов:

  • Скрипты, подключенные к форме, загружаются асинхронно и параллельно (если они не будут уже загружены через EnableRule – об этом ниже). Что в свою очередь не гарантирует порядок их загрузки, определенный в свойствах формы. Поэтому, если у Вас имеется строгая зависимость выполнения кода в JS-библиотеках и этот код выполняется без инициации по какому-либо событию, то Вам необходимо в самом коде контролировать наличие связанных скриптов;
  • Событие onLoad будет выполнено только после загрузки всех скриптов, определенных в свойствах формы;
  • Скрипты, определенные в EnableRule, будут загружены и выполнены последовательно, в порядке определенном в EnableRule. Скрипты формы начнут загружаться после загрузки всех скриптов определенных EnableRule. По этой причине Командная панель будет доступна до выполнения скриптов на онлоад;
  • Интересный побочный эффект: если включить в EnableRule все скрипты, задействованные на форме, то можно гарантировать их последовательную загрузку и выполнение;
  • Скрипты Command Action загружаются и выполняются последовательно в том порядке, в каком они определены. Скрипты Command Action загружаются при нажатии кнопки, а не при загрузке страницы (если конечно они небыли определены в свойствах формы или в EnableRules);
  • Скрипты загружаются только один раз на страницу, даже если на них ссылаются из разных мест (Commands, EnableRule и скрипты подключенные к форме);
  • Отладка:
    • Скрипты, загруженные только формой (и не включенные в Enable Rules) появятся как «нормальный» отдельный элемент списка, в списке скриптов в отладчике ослика;
    • Скрипты EnableRule и Command Action появятся как динамический «script block» в отладчике ослика.

Новые методы


Время

Следующим методом можно скрыть/отобразить дату у поля типа дата/время:

Xrm.Page.getControl("new_datewithouttime").setShowTime(false);

З.Ы. К сожалению, пока нет поддерживаемой возможности скрыть дату и оставить только время.


Алерты и Подтверждения

В предыдущих версиях CRM Вы должны были бы использовать родные JS функции alert и confirm если Вам нужно было вывести уведомление или задать вопрос (на который требуется ответ Ди/Нет). Теперь CRM обзавелся собственными аналогами:
[b]Xrm.Utility.alertDialog[/b]
Принимает два параметра:

  • message: сообщение Вы хотите вывести на экран;
  • onCloseCallBack: функция, чтобы будет вызвана, когда пользователь нажмет OK или закроет окно с сообщением.

Пример:

Xrm.Utility.alertDialog("Заменить название", function () {
    Xrm.Page.getAttribute("name").setValue("Суперфирма");
});


[b]Xrm.Utility.confirmDialog[/b]

Принимает три параметра:

  • message: сообщение которое будет выведено на экран;
  • yesCloseCallback: функция, которая будет вызвана если пользователь нажмет Да;
  • noCloseCallback: функция, которая будет вызвана если пользователь нажмет Отмена.

Пример:

Xrm.Utility.confirmDialog("A или Б?",
    function () {
        Xrm.Page.getAttribute("name").setValue("А");
    },
    function () {
        Xrm.Page.getAttribute("name").setValue("Б");
    }
);


Уведомления

Помимо двух выше описанных «оберток» стандартных JS-механизмов, в CRM появились две функции, реализовывающие более качественные и естественные для CRM уведомления.

Уведомления формы

Уведомление формы хорошо знакомо пользователем CRM – оно выводится в верху формы в виде желтой полоски с одной из трех иконок. Ранее данный механизм использовался только стандартным функционалом, а всем остальным был доступен в виде неподдерживаемых реализаций. Теперь же для этого можно использовать стандартную функцию…

Уведомление формы выводится при помощи функции Xrm.Page.ui.setFormNotification, которая принимает три параметра:

Xrm.Page.ui.setFormNotification(message, level, uniqueId);

, где:

  • message: текст сообщения;
  • level: тип уведомления, от которого зависит иконка, выводимая рядом с сообщением. Может быть одним из трех:
    • ERROR – ошибка;
    • WARNING – предупреждение;
    • INFO – информационное сообщение.
  • uniqueId: любой уникальный идентификатор, который будет в последствии использоваться для удаления какого-либо конкретного сообщения.

Пример:

Xrm.Page.ui.setFormNotification("Алярм, упячка!!!", "ERROR", "id1");


Для удаления уведомления используюется функция Xrm.Page.ui.clearFormNotification, которая принимает один параметр – уникальный идентификатор удаляемого сообщения:

Xrm.Page.ui.clearFormNotification(uniqueId);

Примечания:

  • Система не будет препятствовать сохранению, даже если у Вас есть уведомление формы об ошибке;
  • Новое уведомление добавляется сверху существующих, при этом всегда соблюдается порядок отображения:
    • Об ошибке;
    • Предупреждение;
    • Информационные.
  • Одновременно отображаются только 3 строки уведомления. Если их выведено больше, то появляется прокрутка в области уведомлений.

Уведомления полей

Уведомление полей это совершенно новый функционал для CRM, но довольно часто встречающийся в Интернете — когда происходит заполнение какой-либо формы, если данные в поле были введены не корректно, то тут же рядом с ним всплывает подсказка, реализованная в виде «облака», которая указывает на некорректность данных. Вот именно такой функционал появился в CRM.

Задается уведомление поля следующим образом:

Xrm.Page.getControl(fieldname).setNotification(message);

, где:

  •  fieldname: имя поля;
  • message: текст сообщения.

При этом рядом с полем появляется красный значок с крестиком.


А чтобы убрать сообщение используйте следующий метод:

Xrm.Page.getControl(fieldname).clearNotification();

Примечания:

  • Вы не сможете сохранить запись, пока имеются поля с выведенными уведомлениями полей;
  • Этот метод доступен только для объектов с новым интерфейсом;
  • Текст сообщения скрывается если провести по нему мышью, но красный значок останется.

Фильтрация лукапов

В CRM 2011, если нам нужна была фильтрация лукапа, мы должны создать для него кодм новое Представление и добавить его в лукап (addCustomView).

Теперь же мы можем просто применить фильтр к лукапу и все Представления, доступные для выбора, будут по нему фильтроваться. В дополнение к этому, теперь мы можем применить фильтр, в момент щелчка на лукапе, а не предварительно на онлоаде или по каким-либо другим событиям. Для этих целей нам доступен новый метод – addCustomFilter. Он работает в паре с событием PreSearch, которое происходит в момент клика на лукапе (и перед открытием диалога). Метод addCustomFilter принимает два параметра:

Xrm.Page.getControl("lookupid").addCustomFilter(fetchFilter, entityType);
  • Сам фильтр, заданный с помощью FetchXML;
  • entityType – опциональный параметр, определяющий, какие объекты лукапа необходимо фильтровать (для лукапов, в которых можно выбирать разные типы объектов). Если не передать этот параметр, то фильтр применяется ко всем объектам.

Пример фильтрации Головной организации на основе электропочты:

function addEventHandler() {
    // Добавляем обработчик для события PreSearch
    Xrm.Page.getControl("parentaccountid").addPreSearch(addFilter);
}

function addFilter() {
    // Создаем фильтр
    var filter = "<filter type='and'><condition attribute='emailaddress1' operator='eq' value='someone5@example.com' /></filter>";
    // Применяем фильтр к лукапу
    Xrm.Page.getControl("parentaccountid").addCustomFilter(filter);
}

Функция addEventHandler вызывается на загрузке формы и добавляет к лукапу на событие PreSearch вызов функции addFilter, которая и определяет фильтр для лукапа. Удаляется обработчик события методом removePreSearch (обработчик) методы. Обратите внимание, что формат фильтра зхадается обязательно с использованием тегов <filter> и <condition />.

Фильтр применен ко всем доступным Представлениям в лукапе, таким образом, Вам больше не нужно оставлять в лукапе одно единственное Представление с нужными фильтрами!


Прочие методы

  • Context
    • Xrm.Page.context.client.getClient() – возвращает «Outlook», «Web» или «Mobile»;
    • Xrm.Page.context.client.getClientState() – возвращает «Online» или «Offline»;
    • Xrm.Page.context.client.getUserName() – возвращает полное имя текущего пользователя (доступен только на обновленных объектах).
  • Data
    • Xrm.Page.data.refresh()
      • Асинхронно обновляет данные на форме (без перезагрузки страницы);
      • Может возвращать обратный вызов, чтобы обработать ошибку или успешное выполнение.
    • Xrm.Page.data.save()
      • Асинхронно сохраняет страницу;
      • Может возвращать обратный вызов, чтобы обработать ошибку или успешное выполнение.
    • Xrm.Page.data.getIsValid() – возвращает булевое значение: может ли форма быть сохранена или нет;
    • Xrm.Page.data.setFormDirty() – помечает форму как имеющую не сохранененные изменения.
  • Date
    • Xrm.Page.getControl(arg).setIsAllDay(bool) – определяет, должно ли поле дата/время включать весь день;
    • Xrm.Page.context.client.getClient() – возвращает «Outlook», «Web» или «Mobile»;
  • Entity
    • Xrm.Page.data.entity.getPrimaryAttributeValue() – возвращает строковое значение основоного атрибута.
  • Числовые поля
    • Xrm.Page.getAttribute(«new_precision»).setPrecision(2) – переопределяет количество знаков после запятой для десятичных полей.
  • Utility
    • Xrm.Utility.openWebResourceDialog(webResourceName, webResourceData, width, height) – открывает определенный HTML Веб-ресурс как диалоговое окно;
    • Xrm.Utility.isActivityType(entityName) – определяет, является ли объект Действием.

oAuth

С целью поддержки мобильных приложений в CRM 2013 включена поддержка протокола OAuth, (который построен по принципам REST) и который проще поддерживать для мобильных приложений. Эти приложения, после аутентификации через OAuth, могут использовать либо конечную точку SOAP, либо конечную точка OData. Конечная точка веб-сервиса OData также была улучшена и теперь поддерживает аутентификацию внешних мобильных и клиентских приложений. Ранее, конечная точка OData поддерживала только предварительно аутентифицируемый клиентский код (т.е. скрипты) заданный в веб-ресурсах. После получения маркера аутентификации из конечной точки OData, клиентские приложения могут использовать его для отправки SOAP-запросов к веб-сервисам.

FetchXML

Left Outer Join



FetchXML теперь поддерживает Left Outer Join (вот отчетам то повезло 🙂 ). Данная фича позволит одним только FetchXML запросом отбирать записи у которых чего-то нет. Например, отобрать Организации у которых нет Звонков.

А зается это с помощью атрибута link-type в тэге link-entity:

<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true">
  <entity name="account">
    <attribute name="fullname" />
    <link-entity name="phonecall" from="regardingobjectid" to="accountid" alias="ab" link-type="outer">
      <attribute name="regardingobjectid" />
    </link-entity>
    <filter type="’and’">
      <condition entityname="ab" attribute="regardingobjectid" operator="null" />
    </filter>
  </entity>
<fetch/>

Или так:

<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true">
  <entity name="account">
    <attribute name="fullname" />
    <link-entity name="phonecall" from="regardingobjectid" to="accountid" link-type="outer">
      <filter type="’and’">
        <condition entityname="ab" attribute="regardingobjectid" operator="null" />
      </filter>
    </link-entity>
  </entity>
<fetch/>

К сожалению, данное улучшение пока нельзя задать в Расширенном поиске – только кодом.

ИЛИ между объектами

В CRM 2011 следующий запрос вернет Возможные сделки, у которых Статус «В работе» и есть Контакт, который родился ранее 1993 года:

<fetch mapping="logical" version="1.0">
    <entity name="opportunity">
        <attribute name="name" />
            <link-entity name="contact" from="contactid" to="customerid">
                <attribute name="fullname" />
                <filter>
                    <condition attribute="birthdate" operator="on-or-before" 
                               value="1993-04-17T00:00:00" />
                </filter>
            </link-entity>
            <filter>
                <condition attribute="statuscode" operator="eq" value="1" />
            </filter>
    </entity>
</fetch> 

Фетч в CRM 2013 позволяет с помощью указания объекта в условии использовать оператор ИЛИ между условиями, касающихся различных объектов. Т.е. мы можем вернуть Возможные сделки, у которых Статус «В работе» ИЛИ есть Контакт, который родился ранее 1993 года:

<fetch mapping="logical" version="1.0">
    <entity name="opportunity">
        <attribute name="name" />
            <link-entity name="contact" from="contactid" to="customerid">
                <attribute name="fullname" />
            </link-entity>
            <filter type="or">
                <condition attribute="statuscode" operator="eq" value="1" />
                <condition entityname="contact" attribute="birthdate" operator="on-or-before" 
                           value="1993-04-17T00:00:00" />
            </filter>
    </entity>
</fetch>

Если же у Вас в запросе более одного раза встречается один и тот же объект, то для ссылке на «нужный» объект необходимо использовать алиас:

<fetch mapping="logical" version="1.0">
    <entity name="opportunity">
        <attribute name="name" />
            <link-entity name="contact" from="contactid" to="customerid" alias="oppCustomer">
                <attribute name="fullname" />
                <link-entity name="contact" from="contactid" to="parentcustomerid">
                    <attribute name="fullname" />
                </link-entity>
            </link-entity>
            <filter type="or">
                <condition attribute="statuscode" operator="eq" value="1" />
                <condition entityname="oppCustomer" attribute="birthdate" operator="on-or-before" 
                           value="1993-04-17T00:00:00" />
            </filter>
    </entity>
</fetch>

NuGet

Сборки SDK теперь размещаются в NuGet.

NuGet – диспетчер пакетов для платформы разработки Microsoft, у которого также есть аддон для Visual Studio, который помогает разработчикам управлять обновлениями и получением более старых версий.

Когда Вы разрабатываете программы для CRM (консольное приложение или плагины), Вы сначала скачиваете пакет SDK и добавляете в проект ссылки на необходимые библиотеки. И каждый раз, когда выходит новая версия SDK, Вам необходимо повторно скачать пакет SDK и вручную обновить ссылки.

При помощи NuGet Вы можете загрузить необходимые блоки из своего проекта, и это автоматически добавляет дополнительные ссылки, также! Когда более новая версия блоков будет доступна, Visual Studio предупредит Вас, и Вы можете легко обновить блоки единственным щелчком!

  • Откройте VS и создайте новый проект (в данном примере – консольное приложение);
  • Щелкните правой кнопкой по проекту – Manage NuGet Packages…;
  • Выберите Online на левой панели и ищите «crmsdk». Будет найдено 5 пакетов – установите Microsoft Dynamics CRM 2013 SDK core assemblies;

В References появятся ссылки на библиотеки CRM SDK.


Когда выйдет новая версия система уведомит Вас об этом. Вы также можете выполнить проверку вручную:

  • Щелкните правой кнопкой по проекту и нажмите Manage NuGet Packages…;
  • На левой панели перейдите к Updates – автоматически будут найдены все обновления – кликните напротив нужного Update;


Комментарии (3)
  • Roman 16.02.2014

    Спасибо за статью!
    Вопрос — Вы написали — «Следующим методом можно скрыть/отобразить дату у поля типа дата/время:». Думаю, Вы всё-таки имелии в виду ‘скрыть/отобразить время’. Что скажете?

  • slivka_83 16.02.2014

    Да, верно. Ошибся 🙂

  • slivka_83 16.02.2014

    Добавил про улучшения фетча.

*

code