Рекомендации по подключению к CRM в веб-приложении

Извините, если этот вопрос будет слишком широким, но если это вопрос о нормальном приложении на основе ASP.NET MVC 5 Owin с подключением по умолчанию к серверу MSSQL, у меня не было бы таких трудностей, но мы используем CRM в качестве нашей базы данных.

Хорошо, поскольку я уже упоминал, что работаю над приложением ASP.NET MVC5, и мне трудно найти, что лучше всего создать, оставить открытым и закрыть соединение с Dynamics CRM 365?

Я нашел много сообщений и блогов, но каждый тянет на свою сторону дороги.

Некоторые говорят, что для каждого запроса лучше открывать новое соединение в using заявлении, чтобы его можно было сразу закрыть (звучит хорошо, но это возможно, что запросы будут медленными, потому что при каждом запросе необходимо открывать новое соединение с CRM).
Некоторые говорят, что «лучше сделать singleton объект в области приложения, держать его открытым в течение всего срока службы приложения и повторно использовать его при каждом запросе».

Обычно я бы использовал OrganizationServiceProxy в каком-нибудь простом консольном приложении, но в этом случае я не уверен, следует ли мне использовать OrganizationServiceProxy или CrmServiceClient или что-то еще?

Если бы у кого-то была или была подобная проблема, любой намек был бы отличным.

ОБНОВЛЕНИЕ:

@Nicknow

Я загрузил SDK с SDK 365 и использую этот dll-s.
Microsoft.Xrm.Sdk.dll, Microsoft.Crm.Sdk.Proxy.dll, Microsoft.Xrm.Tooling.Connector.dll и Microsoft.IdentityModel.Clients.ActiveDirectory.dll.

Вы упоминаете

Microsoft.CrmSdk.XrmTooling.CoreAssembly 8.2.0.5.

Если правильно, этот пакет nuget использует официальную сборку, которую я загрузил, или в этот пакет внесены некоторые изменения?

Об этом тесте

контрольный тест

Если я правильно понял, независимо от того, использую ли я оператор using, реализую метод Dispose() или просто использую статический класс в области действия приложения в течение всего времени существования приложения, я всегда получу один и тот же экземпляр (если я использую настройки по умолчанию RequireNewInstance=false)?

Для простоты кода я обычно создаю статический класс (можно также использовать синглтон, но обычно это будет излишним), чтобы вернуть объект CrmServiceClient. Таким образом, мой код не засоряется новыми вызовами CrmServiceClient, если я захочу что-либо изменить в том, как выполняется соединение.

Итак, было бы хорошей практикой создать статический класс в области приложения, который живет в течение всего срока службы приложения? Это означает, что каждый пользователь, который делает запрос, будет использовать один и тот же экземпляр? Разве это не проблема производительности для одного этого соединения?

Все вызовы ваших методов будут выполняться до завершения или вызывать исключение, поэтому, даже если сборщик мусора занимает некоторое время, нет открытого соединения, которое потребляет ресурсы и / или блокирует другие действия.

Это возвращает меня к разделу, где я всегда получаю один и тот же экземпляр CrmServiceClient и часть, в которой xrm.tooling обрабатывает кешированное соединение с другой стороны, но что происходит на этой стороне (веб-приложение). Разве подключение к CRM (т.е. CrmServiceClient) неуправляемым ресурсам, не следует ли Dispose() это явно?

Я нашел несколько примеров с CrmServiceClient, и почти во всех примерах CrmServiceClient приведено в IOrganizationService с использованием CrmServiceClient.OrganizationWebProxyClient или CrmServiceClient.OrganizationServiceProxy.

Почему это так и каковы преимущества этого?

У меня так много вопросов, но это уже можно задать. Есть ли какая-нибудь онлайн-документация, на которую вы могли бы указать мне?


person Genato    schedule 29.09.2017    source источник
comment
Это становится слишком много для вопросов и ответов по Stackoverflow: stackoverflow.com/help/how-to-ask.   -  person Nicknow    schedule 30.09.2017


Ответы (1)


Во-первых, я предполагаю, что вы используете новейшие библиотеки DLL SDK от Nuget: Microsoft.CrmSdk.XrmTooling.CoreAssembly 8.2.0.5.

Я никогда не заключаю соединение в выражение using и не думаю, что когда-либо видел пример, где это делается. Есть примеры из «старых дней», до появления библиотеки инструментов, где вызовы create OrganizationServiceProxy были заключены в оператор using, что заставило многих неопытных разработчиков выпустить код с проблемами производительности соединения.

К счастью, большая часть этого была исправлена ​​с помощью библиотеки Xrm.Tooling.

Создайте объект подключения, используя CrmServiceClient:

CrmServiceClient crmSvc = new CrmServiceClient(@"...connection string goes here...");

Теперь, если я создаю объект OrganizationServiceContext (или эквивалент с ранней привязкой), я оборачиваю его в using, чтобы он был определенно удален, когда я завершу свою единицу работы.

using (var ctx = new OrganizationServiceContext(crmSvc))
{
    var accounts = from a in ctx.CreateQuery("account")
                    select a["name"];

    Console.WriteLine(accounts.ToList().Count());
}

Библиотека Xrm.Tooling обрабатывает все остальное за вас, включая канал подключения и аутентификацию. Если вы не укажете создание нового канала каждый раз (добавив «RequireNewInstance = true» в строку подключения или установив useUniqueInstance на true при вызове new CrmServiceClient), библиотека будет повторно использовать существующий аутентифицированный канал.

Я использовал следующий код для быстрой проверки:

void Main()
{

    var sw = new Stopwatch();
    sw.Start();

    var crmSvc = GetCrmClient();

    Console.WriteLine($"Time to get Client # 1: {sw.ElapsedMilliseconds}");

    crmSvc.Execute(new WhoAmIRequest());

    Console.WriteLine($"Time to WhoAmI # 1: {sw.ElapsedMilliseconds}"); 

    var crmSvc2 = GetCrmClient();

    Console.WriteLine($"Time to get Client # 2: {sw.ElapsedMilliseconds}");

    crmSvc2.Execute(new WhoAmIRequest());

    Console.WriteLine($"Time to WhoAmI # 2: {sw.ElapsedMilliseconds}");    

}

public CrmServiceClient GetCrmClient()
{
    return new CrmServiceClient("...connection string goes here...");
}

Когда я запускаю это с RequireNewInstance=true, я получаю следующий вывод консоли:

  • Время получить клиента №1: 2216
  • Время до WhoAmI # 1: 2394
  • Время получить клиента №2: 4603
  • Время до WhoAmI # 2: 4780

Очевидно, что создание каждого соединения занимало примерно одинаковое количество времени.

Теперь, если я изменю его на RequireNewInstance=false (что по умолчанию), я получу следующее:

  • Время получить клиента №1: 3761
  • Время до WhoAmI # 1: 3960
  • Время получить клиента №2: 3961
  • Время для WhoAmI # 2: 4145

Вау, это большая разница. Что здесь происходит? При втором вызове библиотека Xrm.Tooling использует существующий канал службы и аутентификацию (которые она кэширует).

Вы можете сделать еще один шаг и заключить свои new CrmServiceClient вызовы в using, и вы получите такое же поведение, потому что удаление экземпляра возврата не уничтожает кеш.

Таким образом, это вернет время, подобное приведенному выше:

using (var crmSvc = GetCrmClient())
{
    Console.WriteLine($"Time to get Client # 1: {sw.ElapsedMilliseconds}");

    crmSvc.Execute(new WhoAmIRequest());

    Console.WriteLine($"Time to WhoAmI # 1: {sw.ElapsedMilliseconds}");
}

using (var crmSvc2 = GetCrmClient())
{
    Console.WriteLine($"Time to get Client # 2: {sw.ElapsedMilliseconds}");

    crmSvc2.Execute(new WhoAmIRequest());

    Console.WriteLine($"Time to WhoAmI # 2: {sw.ElapsedMilliseconds}");
}

Для простоты кода я обычно создаю статический класс (можно также использовать синглтон, но обычно это будет излишним), чтобы вернуть объект CrmServiceClient. Таким образом, мой код не будет завален new CrmServiceClient вызовами, если я захочу что-нибудь изменить в том, как устанавливается соединение.

Чтобы фундаментально ответить на вопрос о using, нам не нужно его использовать, потому что нечего выпускать. Все вызовы ваших методов будут выполняться до завершения или вызывать исключение, поэтому, даже если сборщик мусора занимает некоторое время, нет открытого соединения, которое потребляет ресурсы и / или блокирует другие действия.

person Nicknow    schedule 30.09.2017
comment
Здравствуйте, я обновил свой вопрос новыми вопросами. :) (комментария не хватит) - person Genato; 30.09.2017
comment
Пожалуйста, разместите новый вопрос для каждого конкретного вопроса, который у вас есть, с примерами кода. В противном случае это создает беспорядок и не укладывается в желаемое использование Stackoverflow. - person Nicknow; 30.09.2017