如何通过 C# 连接到 Azure D365 Odata
How to connect to Azure D365 Odata via C#
我正在寻找一种简单的方法来连接到 .NET 控制台应用程序(不涉及浏览器)中的 Azure Odata 数据存储(特别是用于财务和运营的 Dynamics365)并检索 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/")).Result;
AuthenticationContext authContext = new AuthenticationContext(ap.Authority, false);
AuthenticationResult authResult;
if (username != string.Empty && 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).Result;
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 F&O。我将它们传递给上面的函数。我还有一个有效的 clientId。我知道所有这些都是有效的,因为我有一个第三方应用程序,通过 usn、pwd、clientId 和授权 URL,我能够连接 F&O 及其 odata 并与之交互。但我正在尝试在我的 .NET 控制台应用程序中尽可能简单地复制这种交互。
我从 this approach 开始,但最终偏离并混合了其他文档的示例和方法,只是为了让它全部编译。
以下是我的细节,尽可能少混淆:
D365 F&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
我有用户名和密码。我不需要 redirectUrl,所以我将其保留为空字符串。我也不需要客户机密。 (如果我有客户机密,所有这一切都会简单得多,因为我找到了更简单的 c# 代码示例来处理它。)
当我调用上面的函数时,我得到这个错误:
Invalid authenticate header format - Parameter name:
authenticateHeader
在这一行抛出异常:
AuthenticationParameters ap = AuthenticationParameters.CreateFromResourceUrlAsync(new Uri(serviceUrl + "/data/")).Result;
我不喜欢我正在使用的方法,这只是我发现的所有实际编译并尝试工作的方法。我将非常感谢一个独立的函数,它具有尽可能少的依赖项来连接到我的 odata 并根据需要下拉 json。
URI 需要如下所示:
private static string serviceUrl = "https://yourorg.crm.dynamics.com";
终于找到答案了:
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%20eq%20%27999";
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.Result;
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).Result;
我正在寻找一种简单的方法来连接到 .NET 控制台应用程序(不涉及浏览器)中的 Azure Odata 数据存储(特别是用于财务和运营的 Dynamics365)并检索 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/")).Result;
AuthenticationContext authContext = new AuthenticationContext(ap.Authority, false);
AuthenticationResult authResult;
if (username != string.Empty && 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).Result;
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 F&O。我将它们传递给上面的函数。我还有一个有效的 clientId。我知道所有这些都是有效的,因为我有一个第三方应用程序,通过 usn、pwd、clientId 和授权 URL,我能够连接 F&O 及其 odata 并与之交互。但我正在尝试在我的 .NET 控制台应用程序中尽可能简单地复制这种交互。
我从 this approach 开始,但最终偏离并混合了其他文档的示例和方法,只是为了让它全部编译。
以下是我的细节,尽可能少混淆:
D365 F&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
我有用户名和密码。我不需要 redirectUrl,所以我将其保留为空字符串。我也不需要客户机密。 (如果我有客户机密,所有这一切都会简单得多,因为我找到了更简单的 c# 代码示例来处理它。)
当我调用上面的函数时,我得到这个错误:
Invalid authenticate header format - Parameter name: authenticateHeader
在这一行抛出异常:
AuthenticationParameters ap = AuthenticationParameters.CreateFromResourceUrlAsync(new Uri(serviceUrl + "/data/")).Result;
我不喜欢我正在使用的方法,这只是我发现的所有实际编译并尝试工作的方法。我将非常感谢一个独立的函数,它具有尽可能少的依赖项来连接到我的 odata 并根据需要下拉 json。
URI 需要如下所示:
private static string serviceUrl = "https://yourorg.crm.dynamics.com";
终于找到答案了:
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%20eq%20%27999";
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.Result;
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).Result;