2008-11-13

Error: The request failed with http status 400: Bad Request

Ошибка в переданных сервису данных.
Например, при создании systemuser или salesperson в логине вместо DomainName\UserName надо передавать DomainName\\UserName, иначе некоторые совпадения символов косой черты и последующей буквы могут быть распознаны как escape-последовательность.

2008-10-30

Ownerid

Если сущность создавать программно и не заполнять поле ownerid, то MSCRM сам заполнит это поле Guid'ом пользователя, вызвавшего метод Create().

2008-10-16

Скрытие стандартных ссылок в панели навигации сущности.

Узнаем наименование скрываемой ссылки, например с помощью IE DEV Tools.
И в форме сущности на событе OnLoad пишем следующий JavaScript:


if(document.all.navAddresses != undefined) {
document.all.navAddresses.parentNode.style.display = 'none';
}

2008-10-14

Закрытие окна CRM без подтверждения

Если вы хотите закрыть окно CRM без подтверждения, до вызова window.close() вызовите функцию crmForm.detachCloseAlert()

2008-09-19

На событие OnSave формы сущности account


/*Start:Script added by Me*/
var CRM_FORM_TYPE_CREATE=1;
var CRM_FORM_TYPE_QCREATE=5;
var Return;
/******* comment 21.04 *******/
if ((crmForm.FormType==CRM_FORM_TYPE_CREATE)||(crmForm.FormType==CRM_FORM_TYPE_QCREATE))
{
var str="http://servername/Dedup/duplicatelist.aspx?name=" + escape(crmForm.all.name.DataValue)+"&EntityTypeId=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX";
Return = showModalDialog(str,"","resizable=yes;");
if(Return==true)
{ /* продолжить сохранение */
event.returnValue = true;
return true;
}
else
{ /* отменить сохранение */
event.returnValue = false;
crmForm.detachCloseAlert();
//return false;
window.close();
}
}
/******* comment 21.04 *******/
/*End:Script added by Me*/

2008-09-17

Plugin's Starter Execution Method

Have found excellent method at David Fronk blog Starter Execution Method and slightly update it in to separate method.

// based on Starter Execution Method

/// 
/// Return the opportunity id
/// 
/// Plugin context/// opportunityid
public string GetEntityId(IPluginExecutionContext context)
{
 string opportunityid = "";
 DynamicEntity opportunityClose = null;

 switch (context.MessageName)
 {
  case "Create":
   if (context.OutputParameters.Properties.Contains("id"))
   {
    opportunityid = context.OutputParameters.Properties["id"].ToString();
   }
   break;
  case "Update":
   if (context.InputParameters.Properties.Contains(ParameterName.Target) && context.InputParameters.Properties[ParameterName.Target] is DynamicEntity)
   {
    DynamicEntity entity = (DynamicEntity)context.InputParameters.Properties[ParameterName.Target];
    opportunityid = ((Key)entity.Properties["opportunityid"]).Value.ToString();
   }
   break;
  case "SetState":
   if (context.InputParameters.Properties.Contains("EntityMoniker"))
   {
    if (context.InputParameters.Properties.Contains("State"))
    {
     Moniker entityMoniker = (Moniker)context.InputParameters.Properties[ParameterName.EntityMoniker];
     opportunityid = entityMoniker.Id.ToString();
    }
   }
   break;
  case "SetStateDynamicEntity":
   if (context.InputParameters.Properties.Contains("EntityMoniker"))
   {
    if (context.InputParameters.Properties.Contains("State"))
    {
     Moniker entityMoniker = (Moniker)context.InputParameters.Properties[ParameterName.EntityMoniker];
     opportunityid = entityMoniker.Id.ToString();
    }
   }
   break;
  case "Win":
   opportunityClose = (DynamicEntity)context.InputParameters["OpportunityClose"];
   Lookup WonLook = (Lookup)opportunityClose.Properties["opportunityid"];
   opportunityid = WonLook.Value.ToString();
   break;
  case "Lose":
   opportunityClose = (DynamicEntity)context.InputParameters["OpportunityClose"];
   Lookup LoseLook = (Lookup)opportunityClose.Properties["opportunityid"];
   opportunityid = LoseLook.Value.ToString();
   break;
  case "Assign":
   if (context.InputParameters.Properties.Contains("Assignee") && context.InputParameters.Properties["Assignee"] is SecurityPrincipal)
   {
    Moniker assignEntity = (Moniker)context.InputParameters.Properties["Target"];
    opportunityid = assignEntity.Id.ToString();
   }
   break;
  case "Delete":
   if (context.InputParameters.Properties.Contains("Target"))
   {
    Moniker entityMoniker = null;
    entityMoniker = (Moniker)context.InputParameters.Properties[ParameterName.Target];
    opportunityid = entityMoniker.Id.ToString();
   }
   break;
 }
 return opportunityid;
}

2008-09-09

Сущность template, plug-in и Javascript

Начну с того, что сущность template не изменяемая, но настраиваемая. Однако, это не преимущество. Я не понимаю по каким причинам сущность template была скрыта от нас, но ни форма ни события на ней нам недоступны.
Более того, plug-in на шаг PreCreate для этой сущности дает поразительный результат - при выбрасывании InvalidPluginExecutionException стирает тело и тему самого template.
А задача простая - не дать или хотя бы уведомить пользователя о том, что шаблон с таким именем уже существует. Ну чтобы пользователь потом не выбирал из десятка шаблонов с одинаковым title.
Как же решить? Plug-in не функционален, скрипт вставить некуда. Решил внедриться в оригинальную страничку. Называется она emailtemplateeditor.aspx. Там есть функция Save в нее и написал свой код.
Но проблема обнаружилась и тут. Оказывается CRM не дает обратиться к значению поля templateid (нужно, чтобы title не сравнивать с самим собой), т.е. crmForm.all.templateid.DataValue не работает.
Что ж решил действовать старым проверенным способом через crmForm.FormType, чтобы узнать создаем новый шаблон(FormType=1) или редактируем старый(FormType=2). И тут Microsoft окончательно убедил меня в том, что его сотрудники видимо произошли не от углеродной формы жизни - FormType=0 (Undefined form type). Т.е. согласно SDK сущность создана для системных нужд "For internal use only".

Спасло свойство crmForm.ObjectId, которое и содержало значение поля templateid.
В результате скрипт был закончен и стал иметь такой вид:


var url = "http://mcrm4/wsTemplateCreateCheckDup/CheckTemplateTitleDup.asmx/IsDup";
var templateid="null";
if (crmForm.ObjectId != null)
{
templateid=crmForm.ObjectId;
templateid=templateid.slice(1, templateid.indexOf('}'));
}
var paramstr = "TemplateTitle="+crmForm.all.title.DataValue+"&"+"TemplateId="+templateid;
try{
var oXmlHTTP = new ActiveXObject("Msxml2.XMLHTTP");
oXmlHTTP.open("POST", url,false);
oXmlHTTP.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
oXmlHTTP.send(paramstr);
if(oXmlHTTP.status == 200)
{
var retstr=oXmlHTTP.responseText;
var retidx=retstr.indexOf(">found");
if(retidx>0)
{
alert("Имя шаблона '"+crmForm.all.title.value+"' уже есть в списке.\n Пожалуйста, задайте другое имя.");
SubjectEditor.focus();
event.returnValue=false;
return false;
}
}
else
{
alert("Ошибка "+ oXmlHTTP.status+" при проверке на повторное использование имени шаблона.");
}
}
catch(e){alert(e);}

2008-08-18

Plug-in signing

При разработке plug-in'а, нужно обязательно задавать сильное имя(strong name) и не забывать при релизе переподписывать(re-sign) библиотеку, если был выставлен атрибут Delay Sign Only.

sn - R <assembly> <keyfile>

"Not have enough privilege to complete Create operation for an Sdk entity" при регистрации плагина в CRM 4.0

Эта ошибка возникает даже если пользователь обладает ролью System Administrator. Причина её возникновения, в том, что пользователь не является членом группы Deployment Administrators group в утилите CRM Deployment Manager.

Вы написали plug-in и пытаетесь его зарегистрировать. Не важно, делаете ли вы это с помощью Plug-in Registration Tool из SDK или с помощью собственного инсталлера, однако, даже если вы Системный Администратор, то возможно вам все-равно не удастся зарегистрировать plug-in, и вы получите следующую ошибку:

"Not have enough privilege to complete Create operation for an Sdk entity"

Оказывается System Administrator больше не царь и бог, и эта роль не обладает привилегиями развертывания(deploy). Есть отдельная роль Deployment Administrator. Изначально ее имеет тот, кто устанавливал CRM на локальную машину.
Чтобы регистрировать плагины, понадобится добавить пользователя из-под которого происходит регистрация в Deployment Manager.

  1. Откройте CRM 4.0 Deployment Manager (Start -> All Programs -> Microsoft Dynamics CRM -> Deployment Manager)

  2. Добавьте пользователя из Active Directory в Deployment Administrator'ы


После этого попробуйте еще раз зарегистрировать свой plug-in.

2008-08-05

TargetUpdate Sample Code.

Этого Sample Code я не нашел в SDK, однако нашел вопросы на форумах, оставленные без ответов и решенные с помощью CrmService.Update. Потому я решил написать такой пример.
Думаю кому-то будет интересно как же на самом деле может быть решена задача обновления через TargetUpdate.
private void EmailDeliveryChange(email emailResult, int new_delivery)
{
service = new CrmService.CrmService();
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
service.Url = CrmServiceUrl;

TargetUpdateEmail tue = new TargetUpdateEmail();
// create new email entity for update
email emailUpdate = new email();

// Set the ID of entity which we want to update
emailUpdate.activityid = new Key();
emailUpdate.activityid.Value = new Guid(emailResult.activityid.Value.ToString()); // parameter

// set new value of attribute
emailUpdate.new_delivery = new Picklist();    
emailUpdate.new_delivery.Value = new_delivery;  // parameter

tue.Email = emailUpdate;    
UpdateRequest upreq = new UpdateRequest();

upreq.Target = tue;
UpdateResponse upres = (UpdateResponse)service.Execute(upreq);
}

2008-07-23

Dynamics CRM 4.0 Solution Center

Команда Microsoft Dynamics CRM 4.0 создали на сайте поддрежки Microsoft страницу Dynamics CRM 4.0 Solution Center, где публикуются решения, на часто возникающие проблемы и вопросы.

2008-07-22

Кастомизируемость

Очень меня печалит, что переводили CRM 4.0 видимо с помощью программы переводчика, а не лингвиста-переводчика. Особенно это заметно, когда в сущности template атрибут title переведен как "Должность".
Это не было бы критично, если бы разработчики CRM позволили менять названия атрибутов стандартными средствами.

2008-07-21

Microsoft Dynamics CRM 4.0 SDK

Если кто-то еще не знает где взять(скачать) Microsoft Dynamics CRM SDK, то это можно сделать вот тут:

Microsoft Dynamics CRM 4.0 Software Development Kit

P.S. Версия SDK 4.0.5

CRM 4.0 E-mail access type bulk setting tool

Джим Ванг написан замечательную утилиту для правки email'ов.
Эта утилита, в помощь администраторам CRM, позволяет менять настройки доступа для всех писем попадающих в фильтр по определенному пользователю, т.е. массово. Сама Dynamics CRM не предоставляет такой возможности.


Скачачать ее можно здесь: http://code.msdn.microsoft.com/crm/Release/ProjectReleases.aspx

2008-07-14

ISV.config.xml и русские символы

Если при импорте ISV.config.xml у вас не отображаются русские символы, то посмотрите, есть ли у вас в начале файла строка

<?xml version="1.0" encoding="utf-8"?>;

ISV.config.xml

В MS CMR 4.0 поменялся формат ISV.config.xml
Все Title и ToolTips теперь должны быть вынесены в отдельные тэги.
Например, вместо

<button
title="Dial..."
tooltip="Dials one of the phone numbers on this record"
icon="/_imgs/ico_16_137.gif" url="/C4Web/C4Dial.aspx" passparams="1"
winparams="directories=0,height=150,width=300,location=no,menubar=no,resizable=no,scrollbars=no,status=no,titlebar=no,toolbar=no" winmode="0" client="Web, Outlook" availableoffline="false">


следует писать


<Button Icon="/_imgs/ico_16_137.gif" Url="/C4Web/C4Dial.aspx" PassParams="1" WinParams="directories=0,height=150,width=300,location=no,menubar=no,resizable=no,scrollbars=no,status=no,titlebar=no,toolbar=no" WinMode="0" Client="Web, Outlook" AvailableOffline="false">
<Titles>
<Title LCID="1001" Text="Dial..." />
</Titles>
<ToolTips>
<ToolTip LCID="1001" Text="Dials one of the phone numbers on this record" />
</ToolTips>
</Button›

2008-07-11

Microsoft.Crm.WebServices.Crm2007.MultipleOrganizationSoapHeaderAuthenticationProvider

Проблема:
В MS CRM 4.0 столкнулся с проблемой размещения своего сайта в виртуальном каталоге сайта MS CRM.

Ошибка выдавалась следующая:

Microsoft.Crm.WebServices.Crm2007.MultipleOrganizationSoapHeaderAuthenticationProvider, Microsoft.Crm.WebServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' doesn't exist.
Parameter name: Microsoft.Crm.WebServices.Crm2007.MultipleOrganizationSoapHeaderAuthenticationProvider, Microsoft.Crm.WebServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35



Решение:
Было найдено на форуме Dynamics
Решение совершенно бредовое, но только так и удалось запустить свой сайт. Необходимо зарегистрировать в GAC библиотеку Microsoft.Crm.WebServices.dll(лежит в %CRM Web%/bin)

gacutil /i Microsoft.Crm.WebServices.dll

Если вы не нашли gacutil.exe, то можно в Explorer'е просто перетащить нужную DLL в папку WINDOWS\assembly.

2008-07-10

Ожидания

Под Microsoft CRM я начал писать недавно. До этого много сил отдал Navision, так и не достигнув нирваны, но добившись каких-то успехов.

MS CRM привлек сразу несколькими возможностями: писать под web с использованием нормального объектно-ориентированного языка C# и в нормальной рабоче среде Visual Studio. Это радовало. Особенно после Navision.
Но как оказалось все было не так радужно, как представлялось. MS CRM да и .Net Framework преподносит сюрпризы, которые могут по началу шокировать. Но задачи становятся настолько интересными, на сколько это вообще возможно!

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