Как подключиться к Azure D365 Odata через C#

#c# #azure #oauth-2.0 #odata #microsoft-dynamics

Вопрос:

Я ищу простой способ подключения к хранилищу данных Azure Odata (в частности, Dynamics365 для финансов и операций) в консольном приложении .NET (без браузера) и получения odata json. Я искал по всем документам MS и, наконец, нашел это:

 public OAuthMessageHandler(string serviceUrl, string clientId, string redirectUrl, string username, string password, HttpMessageHandler innerHandler): base(innerHandler) {
  AuthenticationParameters ap = AuthenticationParameters.CreateFromResourceUrlAsync(new Uri(serviceUrl   "/data/")).Resu<
  AuthenticationContext authContext = new AuthenticationContext(ap.Authority, false);
  AuthenticationResult authResu<
  if (username != string.Empty amp;amp; password != string.Empty) {

    UserCredential cred = new UserCredential(username, password);
    authResult = authContext.AcquireToken(serviceUrl, clientId, cred);
  } else {
    authResult = authContext.AcquireToken(serviceUrl, clientId, new Uri(redirectUrl), PromptBehavior.Auto);
  }

  authHeader = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
}
 

try/catch ниже находится внутри статического метода моего консольного приложения main и вызывает функцию выше:

 try {
  messageHandler = new OAuthMessageHandler(serviceUrl, clientId, string.Empty, userName, password, new HttpClientHandler());

  using(HttpClient client = new HttpClient(messageHandler)) {
    client.BaseAddress = new Uri(serviceUrl);
    client.Timeout = new TimeSpan(0, 2, 0); //2 minutes
    client.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
    client.DefaultRequestHeaders.Add("OData-Version", "4.0");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    var response = client.GetAsync("api/data/v9.0/WhoAmI", HttpCompletionOption.ResponseHeadersRead).Resu<

    if (response.IsSuccessStatusCode) {
      //Get the response content and parse it.  
      JObject body = JObject.Parse(response.Content.ReadAsStringAsync().Result);
      Guid userId = (Guid) body["UserId"];
      Console.WriteLine("Your system user ID is: {0}", userId);
    } else {
      throw new Exception(response.ReasonPhrase);
    }
  }
} catch (Exception ex) {
  DisplayException(ex);
}
 

ВАЖНО: Я могу успешно подключиться к D365 Famp;O в браузере с помощью имени пользователя и пароля, которые у меня есть. И я передаю их в функцию выше. У меня также есть действительный идентификатор клиента. Я знаю, что все это действительно, потому что у меня есть стороннее приложение, которое с помощью usn, pwd, идентификатора клиента и URL-адреса авторизации я могу подключаться и взаимодействовать с Famp;O и его odata. Но я пытаюсь как можно проще воспроизвести это взаимодействие в своем консольном приложении .NET.

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

Вот мои особенности, как можно меньше запутанные:

 D365 Famp;O URL: https://mycustomer2492efd6bdevaos.cloudax.dynamics.com/
Odata URL: https://mycustomer2492efd6bdevaos.cloudax.dynamics.com/data/InventItemPrices
Client Id: c0bzae2e-5233-4465-a2f2-ceb87aa52c3f (I changed some chars)
Authorization URL: https://login.windows.net/mycustomer.com
 

И у меня есть имя пользователя и пароль. Мне не нужен перенаправитель, поэтому я оставил его как пустую строку. Мне также не нужен секрет клиента. (Если бы у меня был секрет клиента, все это было бы намного проще, потому что я нашел более простые примеры кода c# для работы с этим.)

Когда я вызываю функцию выше, я получаю эту ошибку:

Недопустимый формат заголовка аутентификации — Имя параметра: authenticateHeader

Исключение создается в этой строке:

 AuthenticationParameters ap = AuthenticationParameters.CreateFromResourceUrlAsync(new Uri(serviceUrl   "/data/")).Resu<
 

Я не женат на подходе, который я использую, это просто все, что я нашел, что на самом деле компилируется и пытается работать. Я был бы очень признателен за автономную функцию с как можно меньшим количеством зависимостей для подключения к моей odata и удаления json по мере необходимости.

Комментарии:

1. Есть ли причина, по которой вам нужно использовать конечную точку OData поверх SDK?

2. blockingHD: Вовсе нет. Предпочел бы не использовать SDK. Было бы здорово использовать необработанный c# без каких-либо зависимостей, кроме стандартной .NET.

3. URI должен выглядеть следующим образом: «частная статическая строка serviceUrl = yourorg.crm.dynamics.com

4. jdweng: нет, это не crm. Это Famp;O.

Ответ №1:

Наконец-то я нашел ответ:

 string d365RootURL = "https://someenvironmentos.cloudax.dynamics.com";
string authorizationURL = "https://login.windows.net/something.com";
var usn = "serviceAcctUsn";
var pwd = "serviceAcctPwd";
var clientID = "c0bcae....6aa52c3f";
string d365OdataURL = d365RootURL   "/data/";
string odataQuery = "SomeEntity?ItemNumber eq '999";

UserCredential creds = new UserPasswordCredential(usn, pwd);
var authContext = new AuthenticationContext(authorizationURL, false);
var authTask = authContext.AcquireTokenAsync(d365RootURL, clientID, creds);

try {
  authTask.Wait();
} catch (Exception ex) {

}

AuthenticationResult authenticationResult = authTask.Resu<

var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authenticationResult.AccessToken);
httpClient.BaseAddress = new Uri(d365OdataURL);

var response = httpClient.GetAsync(odataQuery).Resu<
 

Ответ №2:

URI должен выглядеть следующим образом :

 private static string serviceUrl = "https://yourorg.crm.dynamics.com";
 

Комментарии:

1. Нет, это не CRM. Это D365 Финансы и операции, как упоминалось в оригинальном посте.