How can I read result of web api call from Dynamics 365? - microsoft-dynamics

I try to retrieve a record from Dynamics 365 Sales. I created an app registration in Azure and I can get tokens based on this app.
Also, I can call the HTTP client. But I couldn't figure out how to read the result of the HTTP call.
Microsoft published only WhoAmIRequest sample, but I couldn't find a sample of other entities.
Here is my sample code. I try to read body object.
try
{
string serviceUrl = "https://****.crm4.dynamics.com/";
string clientId = "******";
string clientSecret = "*******";
string tenantId = "*******";
A***.Library.Utility.MSCRM mscrm = new Library.Utility.MSCRM(serviceUrl, clientId, clientSecret, tenantId);
var token = await mscrm.GetTokenAsync();
Console.WriteLine(token);
using (HttpClient client = new HttpClient())
{
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"));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "/api/data/v9.0/accounts");
// Set the access token
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = client.SendAsync(request).Result;
if (response.IsSuccessStatusCode)
{
// Get the response content and parse it.
var responseStr = response.Content.ReadAsStringAsync();
JObject body = JObject.Parse(response.Content.ReadAsStringAsync().Result);
}
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
Here is the result of body object.

You can use either of these syntax to read values. Read more
JObject body = JObject.Parse(response.Content.ReadAsStringAsync().Result);
// Can use either indexer or GetValue method (or a mix of two)
body.GetValue("obs_detailerconfigid");
body["obs_detailerconfigid"];

Related

Connect to Azure Text Analytics from Console App without await

I am trying to call an Azure API (Text Analytics API) from a C# console application with a HttpRequest and I do not want to use any DLLs or await
but using the below snippet I am receiving "Bad Request". Can someone help me where it is going wrong.
public static void ProcessText()
{
string apiKey = "KEY FROM AZURE";
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var requestUri = "https://eastus.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment?" + queryString;
//HttpResponseMessage response;
// Request body
byte[] byteData = Encoding.UTF8.GetBytes("I really love Azure. It is the best cloud platform");
using (var content = new ByteArrayContent(byteData))
{
//content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = client.PostAsync(requestUri, content).Result;
Console.WriteLine(response);
Console.ReadLine();
}
}
string apiKey = "<<Key from Azure>>";
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var requestUri = "https://**eastus**.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment?" + queryString;
//HttpResponseMessage response;
var body = new
{
documents = new[]
{
new
{
ID="1", text="I really love Azure. It is the best cloud platform"
}
}
};
string json = JsonConvert.SerializeObject(body);
byte[] byteData = Encoding.UTF8.GetBytes(json);
dynamic item = null;
using (var con = new ByteArrayContent(byteData))
{
//content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = client.PostAsync(requestUri, con).Result;
if (response.StatusCode == HttpStatusCode.OK)
{
string res = string.Empty;
using (HttpContent content = response.Content)
{
Task<string> result = content.ReadAsStringAsync();
res = result.Result;
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
item = serializer.Deserialize<object>(res);
}
}
Hi All, I could able to get the API output using the above approach

Can not pass a list of strings to a Web API endpoint. Why?

Can not pass a list of strings to a Web API endpoint. Why?
Here is my controller:
[Route("[controller]")]
[ApiController]
public class MyController
{
[HttpPost("foo")]
public string MyMethod(List<string> strs)
{
return "foo";
}
}
Here is how I am trying to call it:
var strs = new List<string> { "bar" };
var json = JsonConvert.SerializeObject(strs);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await httpCliet.PostAsync("/My/foo", content);
Before calling the endpoint I place a breakpoint on the return "foo"; line. Once the breakpoint is hit the strs list inside the MyController.MyMethod is empty. The strs is not null, but it contains no elements. While my intentions and expectations are to see the strs containing one element, i.e. the string "bar".
I am using the ASP.NET Core 2.2 in project where I create and use the HttpClient. And I am using the same ASP.NET Core 2.2 in project where I have the endpoint.
I am not sure what is wrong here. I have checked a few sources. E.g. the following:
C# HTTP post , how to post with List<XX> parameter?
https://carldesouza.com/httpclient-getasync-postasync-sendasync-c/
https://blog.jayway.com/2012/03/13/httpclient-makes-get-and-post-very-simple/
And I can not find what I am missing according to those resources.
UPDATE
The following call works for me as expected:
var json = JsonConvert.SerializeObject(string.Empty);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await server.CreateClient().PostAsync("/My/foo?strs=bar", content);
Maybe someone knows why the parameters in my case are read from the query string only, but not from body?
You can change your url to a full url in client.PostAsync.Here is a demo worked:
Api(localhost:44379):
WeatherForecastController:
[HttpPost("foo")]
public string MyMethod(List<string> strs)
{
return "foo";
}
Call(localhost:44326):
public async Task<IActionResult> CheckAsync() {
HttpClient client = new HttpClient();
var strs = new List<string> { "bar","bar1","bar2" };
var json = JsonConvert.SerializeObject(strs);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://localhost:44379/WeatherForecast/foo", content);
return Ok(response);
}
result:

PowerBi - how to authenticate to app.powerbi.com silently

I have tried the method outlined in the Microsoft docs
which involves creating an app in Active Directory and then having code something very similar to:
var authContextUrl = "https://login.windows.net/common/oauth2/authorize";
var authenticationContext = new AuthenticationContext(authContextUrl);
var redirectUri = "https://dev.powerbi.com/Apps/SignInRedirect";
var pp = new PlatformParameters(PromptBehavior.Auto);
var result = authenticationContext.AcquireTokenAsync(PowerBiApiResource, clientId, new Uri(redirectUri), pp).GetAwaiter().GetResult();
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the PowerBI API token");
}
var token = result.AccessToken;
return token;
I got this code working but it always insisted on prompting for a username and password, which is a problem for a function app.
I have also tried the approach in the silent function specified here
https://community.powerbi.com/t5/Developer/Data-Refresh-by-using-API-Need-Steps/m-p/209371#M6614
static string getAccessTokenSilently()
{
HttpWebRequest request = System.Net.HttpWebRequest.CreateHttp("https://login.windows.net/common/oauth2/token");
//POST web request to create a datasource.
request.KeepAlive = true;
request.Method = "POST";
request.ContentLength = 0;
request.ContentType = "application/x-www-form-urlencoded";
//Add token to the request header
request.Headers.Add("Authorization", String.Format("Bearer {0}", token));
NameValueCollection parsedQueryString = HttpUtility.ParseQueryString(String.Empty);
parsedQueryString.Add("client_id", clientID);
parsedQueryString.Add("grant_type", "password");
parsedQueryString.Add("resource", resourceUri);
parsedQueryString.Add("username", username);
parsedQueryString.Add("password", password);
string postdata = parsedQueryString.ToString();
//POST web request
byte[] dataByteArray = System.Text.Encoding.ASCII.GetBytes(postdata); ;
request.ContentLength = dataByteArray.Length;
//Write JSON byte[] into a Stream
using (Stream writer = request.GetRequestStream())
{
writer.Write(dataByteArray, 0, dataByteArray.Length);
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
dynamic responseJson = JsonConvert.DeserializeObject<dynamic>(responseString);
return responseJson["access_token"];
}
}
This code doesn't work.
Also this has issues, although I haven't tried it:
https://learn.microsoft.com/en-us/power-bi/developer/get-azuread-access-token
There doesn't appear to be anything up to date available that works that explains how to do this. Does anyone know how?
This is the best I've got so far. I have to create the application in AD using https://dev.powerbi.com/apps and then login using a powerbi pro userid and password, using the following code:
public static string GetPowerBiAccessToken(string tenantId, string clientId, string userId, string password)
{
var url = $"https://login.windows.net/{tenantId}/oauth2/token";
var request = (HttpWebRequest)WebRequest.Create(url);
request.KeepAlive = true;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
var dataToPost = new Dictionary<string,string>
{
{"client_id", clientId},
{"grant_type", "password"},
{"resource", PowerBiApiResource},
{"username", userId},
{"password", password},
{"redirect_uri", "https://dev.powerbi.com/Apps/SignInRedirect" }
};
var postData = string.Empty;
foreach (var item in dataToPost)
{
if (!string.IsNullOrEmpty(postData))
postData += "&";
postData += $"{item.Key}={item.Value}";
}
var dataByteArray = System.Text.Encoding.ASCII.GetBytes(postData);
request.ContentLength = dataByteArray.Length;
using (var writer = request.GetRequestStream())
{
writer.Write(dataByteArray, 0, dataByteArray.Length);
}
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
var responseJson = JsonConvert.DeserializeObject<dynamic>(responseString);
return responseJson["access_token"];
}
(P.S. I appreciate the request part of this code could be much better but having spent over 2 days trying to work this out, I'm just glad to have something that is working right now. Also the redirectUrl matches the one in my app, I'm not sure if its essential or not).
In the event of errors, I used Fiddler 4 to tell me exactly what the error was rather than just getting 400 or 401 in the app.

Want to get the details of the user(member) after login successfully in xamarin forms

my question is how to pass username and password from the C# client(xamarin forms) to server's API? if details are correct then the client will get whole product list from webapi(URL).and bind all the details to a listview.I want to get the member details after the success of response code.
the client will send username password from login page to server's API. if server's webapi check whether the details matched with the database, if not, don't let it get product list.
here is the code in loginservices for login(xamarin forms)
public async Task GetData(string username,string password)
{
//string detail = new UserDetails();
UserDetails userDetails = new UserDetails();
// List<UserDetails> detail = new List<UserDetails>();
try
{
var values = new List<KeyValuePair<string, string>>();
values.Add(new KeyValuePair<string, string>("Username", username));
values.Add(new KeyValuePair<string, string>("Password", password));
var content = new FormUrlEncodedContent(values);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("nl-NL"));
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.PostAsync("http://192.168.1.50/Accounts/Authenticate", content);
return response.IsSuccessStatusCode;
};
}
catch (Exception ex)
{
throw ex;
}
}
here is the code for web api---
public async Task ValidateUser([FromBody] Credentials credentials)
{
using (DemoAPPEntities entities = new DemoAPPEntities())
{
var result = await entities.MemberDetails.Where(x => x.UserName == credentials.UserName && x.Password == credentials.Password).SingleOrDefaultAsync();
if (result == null)
{
return NotFound();
}
return Ok(entities.MemberDetails);
}
}

Using Httpclient for send SOAP request In Asp.net Core

Im using Asp.net Core, for calling an asmx service which has 4 methods and i want to call one of them by the name: Verify method, i do this steps:
1-Create realted SOAP:
private XmlDocument CreateSoapEnvelope(PayVM payModel)
{
XmlDocument soapEnvelop = new XmlDocument();
string requiredXML = string.Format(#"<SOAP-ENV:Envelope xmlns:SOAP-ENV=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsi=""http://www.w3.org/1999/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/1999/XMLSchema""><SOAP-ENV:Body><verifyTransaction xmlns=""http://tempuri.org/""> <String_1 xsi:type=""xsd:string"">{0}</String_1><String_2 xsi:type=""xsd:string"">{1}</String_2></verifyTransaction></SOAP-ENV:Body></SOAP-ENV:Envelope>", payModel.ReNO, payModel.MID);
soapEnvelop.LoadXml(requiredXML);
return soapEnvelop;
}
2-create the HttpClient and send my request:
XmlDocument soapRequest = CreateSoapEnvelope(iPGVerifyResultModel);
using (var client = new HttpClient())
{
var request = new HttpRequestMessage()
{
RequestUri = new Uri("relatedUri/ServiceName.asmx"),
Method = HttpMethod.Post
};
request.Content = new StringContent(soapRequest.ToString(), Encoding.UTF8, "text/xml");
request.Headers.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml"));
request.Content.Headers.ContentType = new MediaTypeHeaderValue("text/xml");
request.Headers.Add("SOAPAction", "Verify"); //I want to call this method
HttpResponseMessage response = client.SendAsync(request).Result;
if (!response.IsSuccessStatusCode)
{
throw new Exception();
}
Task<Stream> streamTask = response.Content.ReadAsStreamAsync();
Stream stream = streamTask.Result;
var sr = new StreamReader(stream);
var soapResponse = XDocument.Load(sr);
//do some other stuff...
}
but i didn't result, i try uses service by same parameters with Soap UI and the service work properly, but in my way i got StatusCode: 400 what is the problem?