Разработка
06
Сен
3

Хранение конфигурационных данных в CRM

Систематизируем способы хранения конфигурационных данных для двух расширений CRM: плагинов и JS-кода.

Плагины

Логика работы плагинов часто требует входящие или конфигурационные параметры, которые должны достаточно просто обновляться без перекомпилирования или перерегистрации плагина.

Начнем с…

Конфигурационный объект

Это возможно наиболее популярный метод. Суть его в том, что создается специальный служебный объект, каждая запись которого хранит название и значение одного параметра. А Ваши приложения соответственно считывают и используют их.

Преимущества:

  • Легко создавать и обновлять (прямо через интерфейс);
  • Можно настраивать доступ к ним с помощью Ролей безопасности.

Недостатки:

  • Данные в записях невозможно перенести вместе с Решением (но, можно, например, с импортом).

Для реализации подобного решения нужно воспользоваться банальными Retrieve и RetrieveMultiple (в зависимости от задачи):

Конфигурационные параметры плагинов

При регистрации шагов плагинов у Вас есть возможность передать в код какие-либо данные через два параметр: Unsecure и Secure Configuration. А в конструкторе класса плагина Вы получить эти данные следующем образом:

public class MyPlugin : IPlugin
{
    private string _secureConfig = null;
    private string _unsecureConfig = null;

    public MyPlugin(string unsecureConfig, string secureConfig)
    {
        _secureConfig = secureConfig;
        _unsecureConfig = unsecureConfig;
    }

    public void Execute(IServiceProvider serviceProvider)
    {
        ...
    }
}

Преимущества:

  • Данные в Unsecure Configuration будут переноситься вместе с Решением, в которое добавлен шаг плагина;
  • К данным в Secure Configuration могут получить доступ только администраторы. Это полезно, когда конфигурация содержит уязвимую информацию, такую как пароли.

Недостатки:

  • Необходимо использовать Plugin Registration Tool для обновления конфигурационных данных;
  • Конфигурация задается в шагах, таким образом, Вы должны обновлять ее для каждого шага, даже если значение для всех шагов одно и то же;
  • К Unsecure Configuration нельзя ограничить доступ с помощью Ролей безопасности;
  • Secure configuration нельзя переносить с Решением, таким образом Вам придётся настраивать их для каждой среды.

З.Ы. Также по этой теме Вам возможно будет интересна эта статья: http://mmcrm.ru/?p=1034


XML Веб-ресурсы

XML Веб-ресурсы это новый способ хранить информацию. И весьма привлекательный. Поскольку не требуется создавать избыточные объекты для хранения одного-двух параметров.

Можете хранить конфигурацию в Веб-ресурсах, например, в виде XML и считывать ее из кода.

Преимущества:

  • Веб-ресурсы можно перемещать вместе с Решениями;
  • Веб-ресурсы сохраняют GUID при переносе их между развертываниями. Поэтому их GUID можно хардкодить в коде (и переносить вместе плагинами, например);
  • Может быть легко изменен через пользовательский интерфейс CRM.

Недостатки:

  • Вы не можете (с помощью стандартных средств) защитить информацию в конкретному Веб-ресурсе, т.к. доступ к Веб-ресурсам выдается только на уровне всей Организации. И большинству пользователей будет требоваться, по крайней мере, доступа для чтения к Веб-ресурсам. Поэтому стоит воздержаться от хранения в Веб-ресурсах секретных данных.

Чтобы получить данный из Веб-ресурса в плагине можно ипользовать два принципиально различных способа:

  1. Обычный запрос из сервиса CRM:
    using System;
    using System.Text;
    using System.Diagnostics;
    using System.Linq;
    using System.ServiceModel;
    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Query;
    using Microsoft.Xrm.Sdk.Messages;
    
    namespace CRM_2011_Plug_in1
    {
        public class MyPlugin : IPlugin
        {
            public void Execute(IServiceProvider serviceProvider)
            {
                IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
                IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
    
                //  Создаем запрос
                QueryByAttribute querybyattribute = new QueryByAttribute("webresource");
                querybyattribute.ColumnSet = new ColumnSet("content");
                querybyattribute.Attributes.AddRange("name");
                querybyattribute.Values.AddRange("new_config.xml");
    
                //  Query passed to service proxy.
                EntityCollection webResourceCollection = service.RetrieveMultiple(querybyattribute);
                if (webResourceCollection.Entities.Count == 0)
                    throw new InvalidPluginExecutionException("Указанного Веб-ресурса не существует.");
    
                Entity webResource = webResourceCollection.Entities[0];
    
                byte[] binary = Convert.FromBase64String(webResource.Attributes["content"].ToString());
                string resourceContent = UnicodeEncoding.UTF8.GetString(binary);
    
                throw new InvalidPluginExecutionException(resourceContent);
            }
        }
    }
    

    З.Ы. Если информация в Вашем Веб-ресурсе храниться в формате XML, то можете воспользоваться следующем кодом для получения данных из конкретного тэга:

  2. // Загружаем XML документ
    XDocument xDoc = XDocument.Parse(resourceContent);
    string orgName= string.Empty;
    XElement orgNameElement = xDoc.XPathSelectElement("//OrgName"); // Получаем данные из тэга OrgName
    if (orgNameElement != null)
    orgName = orgNameElement.Value;
    
    



  1. Вторым способ является HTTP-запрос:
    using System;
    using System.Net;
    using System.Xml;
    using System.Xml.Linq;
    using System.Text;
    using System.Diagnostics;
    using System.Linq;
    using System.ServiceModel;
    using Microsoft.Xrm.Sdk;
    
    namespace CRM_2011_Plug_in1
    {
        public class MyPlugin : IPlugin
        {
            public void Execute(IServiceProvider serviceProvider)
            {
                IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
                IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
    
                string sUrl = "http://crm2011:5555/superfirma/WebResources/new_config.xml";
                WebClient webClient = new WebClient();
                webClient.UseDefaultCredentials = true;
    
                using (XmlTextReader xmlTextReader = new XmlTextReader(webClient.OpenRead(sUrl)))
                {
                    var document = XDocument.Load(xmlTextReader).Root.Value;
                    throw new InvalidPluginExecutionException(document);
                }            
            }
        }
    }
    

    З.Ы. Интересно, используется ли в этом случае кэширование Веб-ресурсов? Если кто знает – отпишите 🙂



JavaScript

Конфигурационный объект

Для возвращения данных из конфигурационного объекта с помощью JS проще всего воспользоваться конечной точкой oData:

XML Веб-ресурсы

C точки зрения клиентского кода XML Веб-ресурсы – идеальный способ хранить информацию о конфигурации системы. Когда XML Веб-ресурс будет получен клиентом (Silverlight или JavaScript), браузер его закэширует.

Рассмотрим как получить содержимое XML Веб-ресурса двумя способами: с помощью нативного JavaScript и с помощью jQuery.

Обычный JavaScript

Допустим у нас есть Веб-ресурс такой XML разметкой и именем new_сonfig.xml:

<attributes>
  <attribute id="DateofBirth">sol_birthdate</attribute>
  <attribute id="Name">sol_name</attribute>
</attributes>

Чтобы выцепить из него данные, нужно воспользоваться таким JS-кодом:

function load () {
    var xmlPath = "../WebResources/new_config.xml";
    var nodePath = "//attributes/attribute";
    var doc = new ActiveXObject("Microsoft.XMLDOM");
    doc.preserveWhiteSpace = true;
    doc.async = false;
    doc.load(xmlPath);
    var nodelist = doc.documentElement.selectNodes(nodePath);
    for (var i = 0; i < nodelist.length; i++) {
        alert(nodelist(i).attributes[0].value);
    }
}


С использованием jQuery

Допустим у нас есть такой XML Веб-ресурс с именем new_сonfig.xml:

<entities>
  <entity name="account">
    <attribute name="accountnumber">
      <description>This is the SAP accountnumber</description>
    </attribute>
  </entity>
</entities>

Создайте JS Веб-ресурс с таким кодом:

function LoadXML() {
    $.ajax({
        type: "GET",
        url: "../WebResources/new_config.xml",
        dataType: "xml",
        success: parseXML
    });
}
function parseXML(data) {
    var entXML = $("entity[name=account]", data)
    $(entXML).children().each(function (i) {
        var attr = this.getAttribute("name");
        var descr = $(this).find('description').text();
        alert(attr + " - " + descr);
    });
}

Подключите к форме последнюю версию jQuery и созданный выше JS Веб-ресурс. На онлоад формы вызовите функцию LoadXML.



JavaScript-объект

Суть способ заключается в создании JS Веб-ресурса (например, с именем new_settings.js) содержащим JS-объект, который в свою очередь содержит несколько переменных (конфигурационных данных). Например, так:

MY_SETTINGS_LOADED = true;
Settings = {
    ComponentSize: 'medium',
    Color: 'green',
    SearchLink: 'http://www.bing.com'
};

Использовать Вы его в целом можно тремя способами:

  • Если Вам нужны эти переменные на какой-либо форме, просто подключите этот Веб-ресурс к форме и можете использовать их в JS-коде;
  • Также можно подгрузить его в любом другом JS-файле (который, в свою очередь, непосредственно задействован в HTML Веб-ресурсе):
    if(typeof(MY_SETTINGS_LOADED) == 'undefined') {
    	var s = document.createElement("script");
    	s.type = "text/javascript";
    	s.src = "../WebResources/new_settings.js";
    	document.getElementsByTagName("head")[0].appendChild(s);
    }
    

    Здесь просто добавляется тэг <script> в заголовок HTML-документа, который ссылается на JS Веб-ресурса;

  • Ну, и наконец Вы можете напрямую подключить JS Веб-ресурс в каком-либо HTML Веб-ресурсе:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>redirecting...</title>
        <script type="text/javascript" src="../WebResources/new_settings.js"></script>
    </head>
    <body>
    <script type="text/javascript">
        window.location = Settings.SearchLink;
    </script>
    </body>
    </html>
    
Комментарии (3)
  • skfd 06.09.2012

    Можно создать сущность с одним большим текстовым полем, куда писать сериализированные json объекты. Преимущества — управление доступом средствами ЦРМ, очень простое использование в джаваскрипте и достаточно простое в Сишарпе.

  • ssd 06.09.2012

    А как реализовать счетчик через XML веб-ресурс ?

  • slivka_83 06.09.2012

    Так же как и через отдельный объект, только возвращать и обовлять нужно контект Веб-ресурса обычными retrieve/update запросами.

*

code