PostHeaderIcon Получение метаданных сущности в Silverlight

SilverCrmSoap.Helpers.SoapHelper.BeginExecuteRetrieveEntity("new_agreement", delegate(IAsyncResult result)
{
	try
	{
		var response = ((IOrganizationService)result.AsyncState).EndExecute(result);
		var entityMetadata = ((EntityMetadata)response["EntityMetadata"]);
		...
	}
	catch (Exception ex)
	{
		...
	}
});

Для доступа к данным используется библиотека SilverCrmSoap.

PostHeaderIcon Ошибка 2103 “Недопустимое или неправильно сформированное приложение: проверьте манифест”

Ошибка Silverlight-приложения:

(по-русски)

SCRIPT5022: Unhandled Error in Silverlight Application
Code: 2103
Category: InitializeError
Message: Недопустимое или неправильно сформированное приложение: проверьте манифест

(по-английски)

SCRIPT5022: Unhandled Error in Silverlight Application
Code: 2103
Category: InitializeError
Message: Invalid or malformed application: Check manifest

По-поводу данной ошибки в интернете можно найти только информацию о том, что она возникает по причине не указанного или некорректного Startap Object.

Однако, практика показала, что данная ошибка может быть еще по одной причине – некорректный HTML-файла.

В попытке побороть кэширование Silverlight-приложения, HTML-файл был изменен следующим образом:

...
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
    <param name="source" value="App.xap?ver=1.01"/>
    ...
</object>

Т.е. к имени файла приложения добавлен параметр с номером версии. Проблема оказалась в точке в номере версии. Именно она вызывала ошибку. Кроме того ошибку вызывал любой символ кроме цифры. Стоило убрать точку, как приложение заработало.

Причина такого поведения непонятна.

PostHeaderIcon DatePicker Binding и пустое значение

Есть элемент управления DatePicker с которым связано некое свойство BirthDate типа DateTime.

<sdk:DatePicker SelectedDate="{Binding Path=BirthDate, Mode=TwoWay}" />

Данная связь будет работать только пока значение DatePicker не пустое. В случае очистки значения элемента управления это пустое значение не будет передано свойству и свойство будет содержать свое прежнее значение.

Происходит это потому, что при очистке значения DatePicker его свойство SelectedDate получает значение null, а в нашем примере свойство BirthDate не может иметь нулевое значение.

Решение проблемы очевидно — необходимо объявить свойство BirthDate как Nullable, то есть объявление свойства должно выглядеть таким образом:

public DateTime? BirthDate { get; set; }

PostHeaderIcon Конвертер bool<->Visibility

Конвертер для преобразования значения булева типа к типу параметра Visibility элемента управления.

using System;
using System.Windows;
using System.Windows.Data;

namespace BE.Silverlight.UI.Converters
{
    /// <summary>
    /// Конвертер позволяет преобразованть булево значение к значению свойства Visibility элемента управления.
    /// </summary>
    public class BoolToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return (bool)value == true ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return (Visibility)value == Visibility.Visible;
        }
    }
}

PostHeaderIcon JSON + Веб-сервис + JavaScript

Взаимодействие JavaScript c Веб-сервисом с использованием формата JSON.

Код ASPX-страницы

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>

    <script type="text/javascript">
        $(document).ready(function () {
            $.ajax({
                type: "POST",
                url: "WebService1.asmx/GetEmployees",
                data: "{}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (msg) {
                    var employees = JSON.parse(msg.d);
                    var content = [];
                    content.push('<table>');
                    for (var i = 0; i < employees.length; i++) {
                        content.push('<tr><td>');
                        content.push(employees[i].Name);
                        content.push('</td><td>');
                        content.push(employees[i].ID);
                        content.push('</td><td>');
                        content.push(employees[i].Age);
                        content.push('</td></tr>');
                    }
                    content.push('</table>');
                    $('#Content').append(content.join(''));
                },
                error: function (msg) {
                    alert("Ошибка! " + msg);
                }
            });
        });
    </script>
</asp:Content>

<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <div id="Content"></div>
</asp:Content>

Код Веб-сервиса

using System.Collections.Generic;
using System.Web.Script.Services;
using System.Web.Services;

namespace WebApplication1
{
    [WebService(Namespace = "http://buseng.ru/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    [ScriptService]
    public class WebService1 : WebService
    {
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public string GetEmployees()
        {
            var employee1 = new Employee { Name = "Pini", ID = "111", Age = "30" };
            var employee2 = new Employee { Name = "Yaniv", ID = "Cohen", Age = "31" };
            var employee3 = new Employee { Name = "Yoni", ID = "Biton", Age = "20" };
            var employees = new List { employee1, employee2, employee3 };
            var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            var jsonStr = serializer.Serialize(employees);
            return jsonStr;
        }
    }

    public class Employee
    {
        public string Name { get; set; }
        public string Age { get; set; }
        public string ID { get; set; }
    }
}

В результате выполнения JS-кода, при загрузке страницы будет произведен запрос к сервису и оттуда получены данные о сотрудниках в формате JSON. Эти данные потом будут отображены в виде таблицы:

Pini 111 30
Yaniv Cohen 31
Yoni Biton 20

Источники

PostHeaderIcon Ошибка “Не удалось завершить эту операцию. Повторите попытку. 0×80004005″ в SharePoint и правила построения запросов с “Or”

Запрос для выбора записей (задач), назначенных на некоторый круг пользователей и не являющихся завершенными:

<Query>
    <Where>
        <And>
            <Or>
                <Includes>
                    <FieldRef Name='AssignedTo' />
                    <Value Type='Lookup'>user01</Value>
                </Includes>
                <Includes>
                    <FieldRef Name='AssignedTo' />
                    <Value Type='Lookup'>user02</Value>
                </Includes>
                <Includes>
                    <FieldRef Name='AssignedTo' />
                    <Value Type='Lookup'>user03</Value>
                </Includes>
            </Or>
            <Neq>
                <FieldRef Name='_x0421__x043e__x0441__x0442__x04' />
                <Value Type='Text'>Завершена</Value>
            </Neq>
        </And>
    </Where>
</Query>

Данный запрос возвратит ошибку “Не удалось завершить эту операцию. Повторите попытку. 0×80004005“.

Запрос выглядит довольно правдоподобным и так сразу и не скажешь в чем причина ошибки. Однако, причина довольно банальна – запрос не верен, так как оператор Or может принимать только два условия для сравнения (а в запросе их три). Кому из разработчиков CAML пришла в голову идея сделать именно так (ведь это откровенный бред!) не известно, но факт остается фактом – корректный запрос в данному случае должен выглядеть так:

<Query>
    <Where>
        <And>
            <Or>
                <Includes>
                    <FieldRef Name='AssignedTo' />
                    <Value Type='Lookup'>user01</Value>
                </Includes>
                <Or>
                    <Includes>
                        <FieldRef Name='AssignedTo' />
                        <Value Type='Lookup'>user02</Value>
                    </Includes>
                    <Includes>
                        <FieldRef Name='AssignedTo' />
                        <Value Type='Lookup'>user03</Value>
                    </Includes>
                </Or>
            </Or>
            <Neq>
                <FieldRef Name='_x0421__x043e__x0441__x0442__x04' />
                <Value Type='Text'>Завершена</Value>
            </Neq>
        </And>
    </Where>
</Query>

Дабы избежать подобных ошибок и упростить себе работу по построению запросов на просторах интернета найден программа U2U CAML Query Builder for SharePoint 2003 and SharePoint 2007 (Windows Version).

Для программного создания подобных условий пришлось написать такой вот метод:

// [C#]
private static string CreateOrLookupConditions(string comparisonOperator, string fieldName, string[] wssValues)
{
    if (wssValues == null || wssValues.Length < 1)
        return string.Empty;
    var tpl = "<" + comparisonOperator + "><FieldRef Name='" + fieldName + "' /><Value Type='Lookup'>{0}</Value></" + comparisonOperator + ">";
    var conditionString = string.Format(tpl, wssValues[0]);
    if (wssValues.Length == 1)
        return conditionString;
    for (var i = 1; i < wssValues.Length; i++)
        conditionString = "<Or>" + conditionString + string.Format(tpl, wssValues[i]) + "</Or>";
    return conditionString;
}

// Использование
var users = new string[] { "user01", "user02", "user03" };
var conditions = CreateOrLookupConditions("Includes", "AssignedTo", users);

PostHeaderIcon Подключение к удаленному SQL-серверу из SQL-запроса

-- Отключение от удаленного сервера
EXEC sp_droplinkedsrvlogin 'MyRemoteServer', NULL
GO

-- Подключение удаленного сервера
IF NOT EXISTS(SELECT name FROM sys.servers WHERE name = 'MyRemoteServer')
	EXEC sp_addlinkedserver 'MyRemoteServer', N'SQL Server'
GO

-- Авторизация на удаленном сервере
EXEC sp_addlinkedsrvlogin
   @rmtsrvname = 'MyRemoteServer',
   @useself = 'false',
   @rmtuser = 'MyRemoteServerUserName',
   @rmtpassword = 'MyRemoteServerUserPassword'
GO

-- Выполнение запроса к удаленной базе
SELECT  * FROM MyRemoteServer.master.dbo.MyTable

PostHeaderIcon Функция для определения GUID

Функция для определения, является ли текстовая строка GUID.

function IsGuid(str) {
	if (str=="") return false;
	var pattern = /^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$/;
	if (pattern.test(str)) return true;
		else return false;
}

PostHeaderIcon WebRequest через прокси

По умолчанию при выполнении запроса через WebRequest используются настройки прокси, прописанные в Internet Explorer. Но если прокси-сервер использует AD-авторизацию, то необходимо указать в запросе использование разрешений пользователя по умолчанию. Т.е. код инициализации запроса должен выглядеть следующим образом:

var request = (HttpWebRequest)WebRequest.Create(url);
request.Proxy.Credentials = CredentialCache.DefaultCredentials;

Если не указать для прокси разрешения, которые следует использовать, то возникнет ошибка “Удаленный сервер возвратил ошибку: (407) Требуется проверка подлинности посредника” (“The remote server returned an error: (407) Proxy Authentication Required”).

PostHeaderIcon Отмена общего доступа

Приведенный код отменяет общий доступ для всех пользователей и групп у указанной записи организации.

var entityName = "account";
var entityId = new Guid("{00FAF5A6-07A5-DE11-8EC4-0003FF2BA268}");
var crmServerUrl = "http://.../";
var organizationName = "...";

using (var service = GetCrmService(crmServerUrl, organizationName))
{
    var target = new TargetOwnedDynamic
    {
        EntityName = entityName,
        EntityId = entityId
    };
    var principalRequest = new RetrieveSharedPrincipalsAndAccessRequest
    {
        Target = target
    };
    var response = (RetrieveSharedPrincipalsAndAccessResponse)service.Execute(principalRequest);
    foreach (var principalAccesses in response.PrincipalAccesses)
    {
         var request = new RevokeAccessRequest
         {
             Target = target,
             Revokee = principalAccesses.Principal
         };
        service.Execute(request);
    }
}

Метод GetCrmService создает и настраивает экземпляр CrmService.