Права пользователя на запись
Способ получения прав пользователя на конкретную запись в системе в CRM 2011 (пример на Silverlight с использованием библиотеки SilverCrmSoap).
var userId = new Guid("DF7A9B5D-B0FB-E011-890C-E61F137DE58F");
var entityName = "new_myentity";
var entityId = new Guid("3FA22F05-BA9D-E111-AD62-E61F137DE58F");
bool appendAccess;
bool appendToAccess;
bool assignAccess;
bool createAccess;
bool deleteAccess;
bool readAccess;
bool shareAccess;
bool writeAccess;
var request = new OrganizationRequest { RequestName = "RetrievePrincipalAccess" };
request["Principal"] = new EntityReference { LogicalName = "systemuser", Id = userId };
request["Target"] = new EntityReference { LogicalName = entityName, Id = entityId };
SilverCrmSoap.Helpers.SoapHelper.BeginExecute(request, delegate(IAsyncResult result)
{
var response = ((IOrganizationService)result.AsyncState).EndExecute(result);
var rights = (AccessRights)response["AccessRights"];
appendAccess = rights.HasFlag(AccessRights.AppendAccess);
appendToAccess = rights.HasFlag(AccessRights.AppendToAccess);
assignAccess = rights.HasFlag(AccessRights.AssignAccess);
createAccess = rights.HasFlag(AccessRights.CreateAccess);
deleteAccess = rights.HasFlag(AccessRights.DeleteAccess);
readAccess = rights.HasFlag(AccessRights.ReadAccess);
shareAccess = rights.HasFlag(AccessRights.ShareAccess);
writeAccess = rights.HasFlag(AccessRights.WriteAccess);
});
Получение списка выбранных записей CRM 2011 в Silverlight-приложении, открытом в не модальном окне
Задача
Есть приложение на Silverlight в котором необходимо получить список ID выделенных в таблице записей. При этом приложение открывается в не модальном диалоговом окне (modeless dialog).
Решение
Для начала нужно создать кнопку на Ribbon, которая будет вызывать JS-функцию, а так же передавать в нее список выбранных в таблице записей. Получить список выбранных записей не представляет труда, достаточно использовать CrmParameter. Можно конечно открыть окно Silverlight-приложения напрямую и передать список ID через строку адреса, но она имеет ограничение по длине, которое легко превысить.
Далее необходимо создать JS-функцию, вызываемую кнопкой. Функция будет подготавливать данные и открывать окно Silverlight-приложения. JS-код может выглядеть следующем образом:
function OpenSLApp(ids) {
var data = new Object();
data.ids = ids;
var page = context.prependOrgName('/WebResources/be_/SLApp/Loader.html');
window.showModelessDialog(page, data, "dialogWidth:800px;dialogHeight:600px;center:yes;status:false;");
}
Тут есть одна хитрость: для того чтобы иметь возможность получить передаваемый список в Silverlight его необходимо не напрямую передавать как параметр окна, а передавать как значение свойства некого объекта.
И наконец теперь можно получить список ID в Silverlight:
var ids = new List<Guid>();
dynamic dialogArguments = HtmlPage.Window.GetProperty("dialogArguments");
var guids = dialogArguments.ids;
if (guids != null)
{
for (var i = 0; i < guids.length; ++i)
{
dynamic item = guids[i];
if (!(item is string)) continue;
var objectValue = (string)item;
ids.Add(new Guid(objectValue));
}
}
Выполнение запроса WhoAmI с помощью библиотеки SilverSrmCoap
Выполнение запроса на получение ID текущего пользователя (WhoAmIRequest).
var request = new OrganizationRequest { RequestName = "WhoAmI" };
SilverCrmSoap.Helpers.SoapHelper.BeginExecute(request, delegate(IAsyncResult result)
{
var response = ((IOrganizationService)result.AsyncState).EndExecute(result);
var userId = (Guid)response["UserId"];
});
Создание записи типа email в CRM 2011
Сложность создания записи типа email заключается в том, что поле отправителя и получателя сообщения имеют специальный, не очень понятный тип – массив записей типа activityparty.
Обратите внимание, что не смотря на то, что отправитель может быт только один, поле from все равно должно принимать в качестве параметра массив, но с одним единственным значением.
var apFrom = new Entity[1];
apFrom[0] = new Entity("activityparty");
apFrom[0]["partyid"] = new EntityReference("systemuser", systemUser1Id);
var apTo = new Entity[2];
apTo[0] = new Entity("activityparty");
apTo[0]["partyid"] = new EntityReference("contact", contact1Id);
apTo[1] = new Entity("activityparty");
apTo[1]["partyid"] = new EntityReference("contact", contact2Id);
email["from"] = apFrom;
email["to"] = apTo;
email["subject"] = "Send Email Test";
email["description"] = "This is the test e-mail message.";
using (var service = CreateCrmService())
{
service.Create(email);
}
Связывание команд в Silverlight при использовании паттерна MVVM
Если нужно связать команду с событием Click кнопки, то все достаточно просто:
<Button Command="{Binding NewEventCommand}" />
NewEventCommand — команда, унаследованная от ICommand, из класса контекста.
Если же нужно связать команду к другим событием, то нужно предпринять ряд действий.
Первое что нужно сделать — подключить к проекту библиотеку System.Windows.Interactivity.
Второе — указать на странице использование пространства имен:
<UserControl
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
Дальше можно описывать связывание:
<Button ClickMode="Hover">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding Path=NewEventCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
Обратите внимание на атрибут ClickMode. Если не установить его в Hover событие MouseLeftButtonDown (и ряд других событий) не будет происходит.
В атрибуте EventName необходимо указывать имя события, как оно указано для элемента управления.
Подобным способом можно связывать команды не только для кнопок, но и для других элементов управления (например ListBox, Image и др.).
Доступ к родительскому контексту из элементов, расположенных в GridView в Silverlight
Есть страница типа UserControl, которой передается некий класс в качестве контекста. На странице расположен GridView (Telerik RadGridView в данном случае), в ячейках которого расположены, например, кнопки и эти кнопки должны брать данные (например, иметь доступ к команде) из контекста страницы.
Для решения задачи необходимо создать статический ресурс, связав его с контекстом страницы, после чего этот ресурс указывать в кнопках в качестве источника.
<UserControl.Resources>
<ContentControl x:Key="CurrentDataContext" Content="{Binding}" />
</UserControl.Resources>
<telerik:RadGridView>
<telerik:RadGridView.Columns>
<telerik:GridViewColumn>
<telerik:GridViewColumn.CellTemplate>
<DataTemplate>
<Button ClickMode="Hover">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding Source={StaticResource CurrentDataContext}, Path=Content.NewEventCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
</telerik:GridViewColumn.CellTemplate>
</telerik:GridViewColumn>
</telerik:RadGridView.Columns>
</telerik:RadGridView>
Получение количества записей с помощью FetchXML в CRM 2011
var contactsCount = 0; // количество записей
const string QUERY = @"
<fetch mapping='logical' aggregate='true' version='1.0'>
<entity name='contact'>
<attribute name='contactid' aggregate='count' alias='count' />
</entity>
</fetch>";
var result = service.RetrieveMultiple(new FetchExpression(query));
if (result.Entities.Count > 0)
contactsCount = (int)result.Entities[0].GetAttributeValue<AliasedValue>("count").Value;
Ошибка “Incorrect attribute value type System.Single” при обновлении поля типа float
float value = 123;
var myEntity = new Entity("new_myentity") { Id = myEntityId };
@event["new_myfield"] = value;
service.Update(@event);
Подобный код в CRM 2011 может выдать ошибку “Incorrect attribute value type System.Single”, не смотря на то, что поле new_myfield имеет тип float.
Для решения проблемы достаточно изменить тип переменной value с float на decimal.
Вставка данных в БД SQL из DataSet
string sqlConnectionString = "..."; // Строка подключения к БД SQL
string tableName = "..."; // Имя таблицы в DataSet
DataSet ds; // Заполненный данными DataSet
using (var con = new SqlConnection(sqlConnectionString))
{
con.Open();
using (var insertCmd = con.CreateCommand())
{
insertCmd.CommandText = "INSERT INTO Names (Number, Name) VALUES (@Number, @Name)";
insertCmd.Parameters.Add("Number", SqlDbType.NVarChar, 100, "Номер договора");
insertCmd.Parameters.Add("Name", SqlDbType.NVarChar, 100, "Клиент");
using (var adapter = new SqlDataAdapter())
{
adapter.InsertCommand = insertCmd;
adapter.Update(ds, tableName);
}
}
con.Close();
}
Возможна ситуация, когда и данные есть и ошибок нет, но данные из DataSet в БД не попадают. Такое может быть, например, когда DataSet заполнялся с помощью метода Fill другого DataAdapter или для DataSet был выполнен метод AcceptChanges. В этом случае данные в DataSet помечены как не измененные, и DataAdapter не считает нужным что-то с ними делать.
В случае с заполнением DataSet с помощью метода Fill? для решения проблемы, необходимо добавить перед вызовом метода Fill строку da.AcceptChangesDuringFill = false; (где da – экземпляр DataAdapter).
Выполнение процесса (Workflow) из Silverlight при использовании библиотеки SilverCrmSoap
private void ExecuteWorkflow(Guid entityId, Guid workflowId)
{
var request = new OrganizationRequest
{
RequestName = "ExecuteWorkflow",
Parameters = new ParameterCollection
{
new SilverCrmSoap.CrmSdk.KeyValuePair<string, object> { Key = "EntityId", Value = entityId },
new SilverCrmSoap.CrmSdk.KeyValuePair<string, object> { Key = "WorkflowId", Value = workflowId }
}
};
SilverCrmSoap.Helpers.SoapHelper.BeginExecute(request, delegate(IAsyncResult result)
{
try
{
((IOrganizationService)result.AsyncState).EndExecute(result);
}
catch (Exception ex)
{
HtmlPage.Window.Alert("Ошибка выполнения Workflow!");
}
});
}