14.12.2007, 11:15 | #1 |
Заноза в заднице
|
Разбор кода примеров SDK, а также разных прочих
Решил начать тему, в которой все желающие могут выкладывать свой опыт разбора примеров из различных источников (в первую очередь - из SDK) и обсудить применимсоть тех или иных приемов на практике, распространенные ошибки и связанные с этим вопросы.
|
|
14.12.2007, 12:15 | #2 |
Заноза в заднице
|
Поиск дубликатов
Ну-с, сам и начну...
Первый пример, котроый хотел бы представить на всеобщий обзор - пример из SDK по поиску дубликатов записей организации при вводе новой. Дабы всё не пересказывать - прикрепил архивчик duplicatedetection.rar с файлами этого примера. Файлов немного, к тому же пристутствует Readme-файл, инструкции которого следует выполнить пошагово. Однако, читая readme можно отметить первый момент, который не очень понятен (по крайней мере мне): ну сгенерили мы библиотеку Microsoft.Crm.Sdk.Wsdl.dll, ну а дальше-то что. Там есть данные о том, что где-то надобно его выложить, но буквально два слова. Не буду разбирать подробности моих умозаключений, но не будет ил столь любезен кто-нибудь сказать точно, куда надо её поместить для успеха, либо же, кто-то может поведать некие правила или принципы, по которым можно установить, куда же всё-таки надо эту библиотеку положить? Про библиотеку можно забыть, создав новый проект, подключив его к сайту CRM в IIS и добавив в веб-ссылки этого проекта ссылку на службу crmservice, которая располагается обычно по ссылке: http:// < имя сервера crm > /mscrmservices/2006/crmservice.asmx Дальше, пример страницы checkforduplicateaccount.aspx надо добавить в проект и попробовать сбилдить. У меня сбилдилось всё обалденно, но когда я попытался запустить это хозяйство для проверки (на всякий случай: для корректной работы указанного примера необходимо к ссылке запуска странички, справа добавлять параметр, например: "?name=%D0%90%D1%80%D0%B5%D0%BD"), получил невнятную ошибку в классе Reference.cs. Собственно, упомянутый файл класса - это не что иное, как класс созданный при добавлении ссылки на службу crmservice. Буквально, ошибка заключается в том, что при выполнении строки кода страницы aspx: RetrieveMultipleResponse retrieved = (RetrieveMultipleResponse)service.Execute(retrieve); в коде класса происходит обращение к строкам: public Response Execute([System.Xml.Serialization.XmlElementAttribute(Namespace="http://schemas.microsoft.com/crm/2006/WebServices")] Request Request) { object[] results = this.Invoke("Execute", newobject[] { Request}); а ссылка, упомянутая в этих строках не работает, то есть буквально, при её выполнении, броузер выдает ошибку 404 Not Found. Ессно, добавив код в событие формы OnSave() из приложенного js-файла, я ничего не добился, поскольку ошибка не давала исполнять страничку aspx. Код странички был переписан, таким образом, чтобы избавиться от конструкции кода service.Execute, в результате чего рабочая странчка aspx стала такой, как в прикрепленном файле CheckForDuplicateAccount.rar. И напоследок совет: в примере, событие OnSave() формы организации снабжено условием, при выполнении которого проверка на дубликаты выполняется только при создании нового элемента. Таким образом проверку можно обойти, создав элемент с уникальным именем, сохранив его и потом открыть для изменения. Я у себя это условие убрал и проверка на дубликаты выполняется всегда. Всем успехов в работе! Последний раз редактировалось Likefire; 14.12.2007 в 12:17. |
|
24.12.2007, 15:53 | #3 |
Участник
|
Аудит данных
А вот такой есть пример (DataAudit.rar) в книжке Working With CRM Снайдера и Стеггера. Предназначен для сохранения лога изменений записей контактов. Я слегка поправил пример для сохранения лога изменений обращений. Но столкнулся с тремя моментами.
1) в качестве значений picklist`ов сохраняются коды, а не значения; 2) не сохраняется информация о назначении обращения другому сотруднику и изменении статуса обращения; 3) не сохраняется информация об изменении состояния обращения. Первая проблема решилась изменением кода при обработке типа PicklistProperty в функции GetValueFromProperty на следующий: Код: else if (propType == typeof(PicklistProperty)) { MetadataService servicemeta = new MetadataService(); servicemeta.Credentials = System.Net.CredentialCache.DefaultCredentials; servicemeta.Url = "http://crm-server:5555/MSCRMServices/2006/metadataservice.asmx"; AttributeMetadata attMetaData = servicemeta.RetrieveAttributeMetadata("incident", InputProperty.Name); PicklistAttributeMetadata picklist = (PicklistAttributeMetadata)attMetaData; int propIdValue = ((PicklistProperty)InputProperty).Value.Value; foreach(Option o in picklist.Options) { if (o.OptionValue == propIdValue) { propValue = o.Description; } } } В итоге получился вот такой (AltecDataAudit.rar) код. Но вот третья проблема у меня решаться нехочет, хотя казалось бы она должна быть попроще второй... Может кто-нить из присутствующих здесь гуру прокомментировать мои потуги в написании колаутов и подсказать в какую сторону надо копать? |
|
|
За это сообщение автора поблагодарили: Likefire (1). |
18.03.2008, 15:18 | #4 |
Заноза в заднице
|
Автонумерация в MS CRM 3.0
...По просьбе уважаемого коллеги ShurikEv представляю разобранный код из книги Снайдера и Стеггера.
Книга относит данную возможность в раздел "SDK серверной части". Цитата: "...Данный пример кода демонстрирует принцип использования поля SQL ServerIdentity, реализуюий схему нумерации сущности Lead(Интерес) * (см. пояснения ниже под звездочкой) с использованием предварительного вызова (callout)." Уже о многом говорит... * - в книге нумерация применяется в отношении сущности Lead, но в данном примере я выложу код для сущностей Account и Contact, так как у меня была практическая задача по нумерации именно этих сущностей при создании. Перед началом кодинга, мной был создан новый атрибут сущности Account, а затем такой же и для Contact - cust_crmid, типа integer (в книге всё немного иначе). Далее следуем инструкциям книги (цитата): Создание проекта конструкции вызова 1. Создайте новый проект C# Class Library с именем ..., (который у меня получил название ExtentCRM.Callout.) 2. Обязательно проверьте наличие ссылки System.Web.Services и в случае, если она отстуствует - добавьте. 3. Добавьте веб-ссылку на веб-службу CrmService под именем: CrmSdk (чувствительно к регистру). 4. Добавьте ссылку на Microsoft.Crm.Platform.Callout.Base.dll (ищите на установочном диске). 5. Добавьте новый файл class с именем ... (книжные имена не называю, чтобы не сбивать с толку, но коль уж цитирую книгу - то вынужден упоминать так, как написано там.) (Однако же, в пункте 5 идет речь о создании одного класса, в котором всё связано только с сущностью Lead. В моем случае речь идет о двух сущностях - это два разных класса, плюс, общий для обоих класс с функцией вычисления, смысл которой будет ясен позднее. Итого имеем три класса: AccountCallout.cs, ContactCallout.cs, NextClientNumber.cs. Код каждого из классов в соответствующем файле-вложении к данному посту)." 6. После компиляции конструкции необходимо обновить файл Callout.config.xml. Код файла должен включить следующие строки: Код: <?xml version="1.0" encoding="utf-8" ?> <callout.config version="2.0"> <callout entity="contact" event="PreCreate"> <subscription assembly="ExtentCRM.Callout.dll" class="ExtentCRM.Callout.ContactCallout"></subscription> </callout> <callout entity="account" event="PreCreate"> <subscription assembly="ExtentCRM.Callout.dll" class="ExtentCRM.Callout.AccountCallout"></subscription> </callout> </callout.config> Естественно, новый проект, как указано в пункте 1 книги создавать необязательно, если в вашем распоряжении уже имеется проект Class Library, который выполняет некие операции предварительного вызова (callout).
__________________
Лень мудрого человека - это необходимое средство нейтрализации кипучей активности руководящих им дураков! |
|
19.03.2008, 15:29 | #5 |
Moderator
|
Что-то не понравился мне этот код. Неправильно перебирать все организации или контакты чтобы определить который был последним! Это как минимум нерационально! Если уж надо 100% на CRM реализовать, то сделайте какую-нибудь несчастную сущность "счетчики системы" и храните данные в ней! При сохранении вычитывайте ее инстанцию и наматывайте счетчик на ней! В разы быстрее будет работать, чем перебор сотен контактов и вытаскивания их в память (пусть даже 1 поля) только с целью пересчитать! При попытке массового импорта эта реализация взорвет моск сервера!
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional |
|
20.03.2008, 14:52 | #6 |
Заноза в заднице
|
Цитата:
Сообщение от Enot Poloskun
Что-то не понравился мне этот код. ... Если уж надо 100% на CRM реализовать, то сделайте какую-нибудь несчастную сущность "счетчики системы" и храните данные в ней! При сохранении вычитывайте ее инстанцию и наматывайте счетчик на ней! ... При попытке массового импорта эта реализация взорвет моск сервера!
__________________
Лень мудрого человека - это необходимое средство нейтрализации кипучей активности руководящих им дураков! Последний раз редактировалось Likefire; 20.03.2008 в 14:54. |
|
20.03.2008, 21:10 | #7 |
Moderator
|
Вы знаете, пример из книги тоже не обеспечивает защиту от конкуренции потоков. Скорее напротив своей медлительностью будет ее провоцировать. Если мы для каждого объекта где есть уникальный номер создаем свой атрибут на сущности счетчика, то, вероятно, мы никогда не получим 2 одинаковых. Если объекты лезут сохраняться по очереди (а не параллельными потоками), то им все равно придется "встать в очередь".
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional |
|
25.03.2008, 22:34 | #8 |
Moderator
|
Добавлено по просьбе LikeFire. Мой опыт неравной борьбы со службой отчетов:
Как вывести в отчете нормальную шапку? В студии, в свойствах отчета: меню Report -> Report Properties. Есть такая вкладка Code. Сюда можно поместить свой код, причем не на скрипотвых языках, а на полноценном Visual Basic .NET (если конечно считать этот язык полноценным). Вот таким кодом, например, можно выковыривать свои параметры из строки фильтра: Код: Const defaultVal As String = "Не указано" Const backspace As Char = Chr(10) Const newline As Char = Chr(13) Const space As Char = Chr(32) Function getParameter(ByVal filterText As String, ByVal className As String, ByVal attributeName As String, ByVal expression As String) As String Dim result As String = defaultVal Dim pos As Integer = filterText.IndexOf(className, StringComparison.OrdinalIgnoreCase) If (pos <> -1) Then pos = filterText.IndexOf(attributeName, pos + className.Length, StringComparison.OrdinalIgnoreCase) If (pos <> -1) Then pos = filterText.IndexOf(expression, pos + attributeName.Length, StringComparison.OrdinalIgnoreCase) If (pos <> -1) Then Dim startPos As Integer = pos + expression.Length pos = filterText.IndexOf(Chr(10), pos + expression.Length) result = filterText.Substring(startPos, pos - startPos).Trim(New Char() {backspace, newline, space}) End If End If End If Return result End Function Далее вызываем его из полей отчета: Code.GetParameter(Parameters!CRM_FilterText.Value, "Заказ", "Дата создания", "в указанную дату или ранее") Достаточно удобное и простое решение. Есть тем не менее и более правильный способ: есть возможность создать и использовать в любом отчете целую библиотеку с любыми удобными для вас функциями и константами! Кроме того, так вам будет доступна вся мощь .NET и снимается ограничение на кодирование только на Basic. Я пошел именно этой дорогой. Короече, если кому-то интересно подробнее об этом можно узнать тут: http://msdn2.microsoft.com/ru-ru/library/ms155798.aspx http://msdn2.microsoft.com/en-us/library/ms153561.aspx http://msdn2.microsoft.com/en-us/library/ms155034.aspx http://www.microsoft.com/Rus/Msdn/pu...RSCstCode.mspx Последний раз редактировалось Артем Enot Грунин; 25.03.2008 в 22:37. |
|
03.04.2008, 17:42 | #9 |
Moderator
|
Коллеги, кажется, duplicatedetection победил и меня... Суть: сделал нормальный проект веб приложения, который лежит в некоторой директории на сервере. В IIS настроено 2 одинаковые virtual directory которые на нее указывают. Первая на сайте по умолчанию, вторая на сайте CRM. Запускаем через сайт по умолчанию - работает. Через CRM валится с невозможностью загрузить библиотеки: Microsoft.Crm.MetadataService.dll и Microsoft.Crm.Tools.ImportExportPublish.dll которые описаны в web.config сайта CRM, а не моего сайта!!! Вылечил простым копированием в директорию своего сайта... Как, как сделать это по-человечьему? Почему такое вообще происходит?
Кстати, проблему проверки уникальности при изменении записи решил, как мне кажется, чуть более элегантно: скрипт запускается при условии что crmForm.all.name.IsDirty а не в зависимости от вида формы. Иными словами в первый раз оно обязательно пачкается, а во все последующие не сработает на старое значение.
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
04.04.2008, 10:30 | #10 |
Заноза в заднице
|
2 Enot Poloskun:
Есть такая беда, называется GAC. Помнится, я когда-то на форуме здесь же поднимал тему выскакивания ошибки, которая мне не понятна. Короче, я потратил день на чтение разной литературы по основам веб-программинга, после чего в моём органайзере появилась следующая запись: Часто возникает ошибка при попытке запуска веб-приложений, использующих веб-референс. Ошибка такого плана: Exception Details: System.ArgumentException: 'Microsoft.Crm.WebServices.Crm2007.MultipleOrganizationSoapHeaderAuthenticationProvider, Microsoft.Crm.WebServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' doesn't exist. Возникает такая ошибка потому, что в GAC (Global Assembly Cache) не зарегистрирована используемая в качестве референс, библиотека. Решение проблемы имеется такое: Заходим в ControlPanel сервера (windows - на ангельском) Обычно нужные библиотеки прописываются в тексте ошибки и найти их не составляет труда, но если же возникают трудности - лучше добавить в GAC все библиотеки, которые содержатся в папках "GAC" и "bin" соответствующих системных папок на сервере (C:\Inetpub\wwwroot\bin и C:\Program Files\Microsoft CRM\Server\GAC).-> Administrative Tools -> Microsoft .NET Framework Configuration -> Assembly Cache Справа выбираем 'Add an Assembly to the Assembly Cache' и Browse'им путь до dll... Она прописывается в GAC, но физически лежит в той директории, откуда ее взяли. В C:\Windows\Assembly\Gac... только ссылка.
__________________
Лень мудрого человека - это необходимое средство нейтрализации кипучей активности руководящих им дураков! |
|
04.04.2008, 12:36 | #11 |
Moderator
|
Коллега, этот способ решения проблемы мне известен, однако, в силу суеверности, в GAC с чужими библиотеками лазить мне не хочется - раз разработчики там их не фиксировали, значит на то были причины и черт его знает какие.
Пост о том, что мне не ясен тот процесс который происходит при загрузке моей страницы. Могу лишь предположить, что вышеупомянутое связано с тем, что моя сборка ссылается на web reference, который, в свою очередь расположен на корневом сайте CRM. В результате, видимо, он запускается из под моей директории, что и нарушает область видимости библиотек не зарегистрированных в GAC. А теперь вопрос: куда смотрели те кто писал SDK?
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional |
|
04.04.2008, 16:12 | #12 |
Заноза в заднице
|
Не знаю. Но возможно, что они полагали, что те, кто будут писать расширения для CRM знакомы с основами веб-программирования и смогут добавить библиотеку в глобальный кэш. Может так? Я тож сильно возмущался, но опять же - у меня зацепок было вообще мало: сообщение об ошибке из созданного мной приложения. Раскрутив эту тему я пришел к выводу, что без добавления нужных библотек в GAC дела не будет. Добавил - и всё стало хорошо. Полагаю, что нужно как-то решать эти вопросы со службой поддержки.
__________________
Лень мудрого человека - это необходимое средство нейтрализации кипучей активности руководящих им дураков! |
|
05.04.2008, 12:21 | #13 |
Moderator
|
Службой поддержки Microsoft? Не, сынок, это фантастика!
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional |
|
22.05.2008, 16:26 | #14 |
Участник
|
По поводу duplicatedetection через JavaScript (обращение к Web-сервису).
В свое время тоже реализовал этот пример для CRM 3.0. Но радость была не долгой - подобное решение не работает в случае, если у клиента стоит Outlook client для Off-line работы. Это решение не работает вообще независимо от того в онлайне или оффлайне клиент (для 4-ки ситуация изменилась, но там это и не нужно duplicatedetection - есть встроенное). Пришлось реализовывать duplicatedetection через Callouts (есть пример в SDK). Работает всегда четко и точно с одной правда засадой - если находится дубликат, после того, как пользователь нажимает Ok на сообщении об ошибке - все введенные данные стираются (!). |
|
22.05.2008, 17:18 | #15 |
Moderator
|
А как вы хотели? Там используется внешняя страница, которая, само-собой не копируется. Кроме того, в локальном режиме может быть доступна не вся база, так что решение в любом случае будет незаконченным.
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional |
|
|
|