Azure REST API to .NET SDK object mapping - c#

I've searched for examples but couldn't find out exactly how the Azure SDK for .NET works.
Project is a net5.0 ASP.NET MVC.
There's already a question Mapping between Azure REST API and .NET SDK but it doesn't answer anything. There are good examples here: https://csharp.hotexamples.com/examples/Microsoft.Azure.Subscriptions/SubscriptionClient/-/php-subscriptionclient-class-examples.html but none of them seem to work for me fully (see next lines).
Microsoft.Azure.Management.ResourceManager.Models.Subscription has half of the fields get only, without set.
Recommended Azure.ResourceManager.Resources.Models.Subscription has everything get only.
I cannot create objects with these namespaces.
[AuthorizeForScopes(Scopes = new string[] { "https://management.azure.com/user_impersonation" })]
private async Task<Microsoft.Azure.Management.ResourceManager.Models.Subscription> GetUserSubscriptions()
{
var accessToken = Request.Headers[HeaderNames.Authorization];
Microsoft.Azure.Management.ResourceManager.Models.Subscription sub = new Microsoft.Azure.Management.ResourceManager.Models.Subscription();
using (var httpClient = new HttpClient())
{
string token = await _tokenAcquisition.GetAccessTokenForUserAsync(GraphConstants.ManagementScopes);
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
using (var response = await httpClient.GetAsync("https://management.azure.com/subscriptions?api-version=2020-01-01"))
{
string apiResponse = await response.Content.ReadAsStringAsync();
sub = JsonConvert.DeserializeObject<Microsoft.Azure.Management.ResourceManager.Models.Subscription>(apiResponse);
}
}
return sub;
}
The variable apiResponse correctly retrieves the JSON information, but JsonConvert doesn't convert correctly.
Question:
How can I use Azure SDK (or any other) to map the API responses to objects that I can then manipulate.

Related

Issues publishing image to Facebook Page via Graph API SDK .NET

Attempting this on .NET Core 3.1
After several hours of trying to publish a photo to my public facebook page (as in business page) of which I am the admin and have a long-term token for...
I keep getting the following response to my request using the official Facebook SDK for .NET. However, the image itself is never loaded.
{{"id":"786692942226147","post_id":"113260773923227_786692942226147"}}
The request looks like
var imageMedia = new FacebookMediaObject { FileName = file.FileName, ContentType = file.ContentType };
var stream = file.OpenReadStream();
var bytes = await stream.ReadAsByteArrayAsync();
imageMedia.SetValue(bytes);
var fbClient = new FacebookClient(credential.Token)
{
AppId = _config.GetValue<string>("FacebookClientId"),
AppSecret = _config.GetValue<string>("FacebookSecret")
};
dynamic parameters = new ExpandoObject();
parameters.message = request.Message;
parameters.file = imageMedia;
var result = await fbClient.PostTaskAsync($"{credential.PageId}/photos", parameters, token);
I'm sure it has something to do with the parameters I'm passing in, like parameters.file... but the docs for this thing are VERY unclear... as in "literally does not exist"
Anyone with experience getting this working, please point me in the right direction?
The solution is to change parameters.file to parameters.image...

How are parameters passed through HttpClient in .NET Core

I am very, very new to the entire idea of REST and calling an API from http in general, but for a project I am working on, it has become necessary.
I am using ASP.NET Core, so I've been trying to find a REST library. When I was using standard .NET, I could use RestSharp, but the community made RestSharp.Core is pretty out of date and has many incompatibilities with newer versions of .NET Standard 1.6+.
To that end, I've explored other options, but my inexperience just makes it frustrating. Inevitably, I'm thinking it is best if I just use the built in HttpClient class. But I'm not sure how to do that for this exact scenario. I'm having a very hard time understanding how to give the parameters to the request, and what I'm specifically looking for in the return value.
My needs are pretty simple;
create a connection to $url
specify that it is a POST operation.
pass an existing JSON object to the server when making the request.
get JSON data back.
My code, using old RestSharp.Core, looks a bit like this - obviously keys and such omitted for privacy.
public async Task<string> OpenApiAsync() {
var token = await Task.Run(async () => {
var httpClient = new RestClient("https://[OMITTED].auth0.com/oauth/token");
var httpRequest = new RestRequest() {
Serializer = new RestSharp.Serializers.JsonSerializer(),
Method = Method.POST
};
httpRequest.AddHeader("content-type", "application/json");
httpRequest.AddJsonBody(new {
client_id = _settings.Value.ClientId,
client_secret = _settings.Value.ClientSecret,
audience = _settings.Value.Audience,
grant_type = _settings.Value.GrantType
});
var httpResponse = await httpClient.Execute(httpRequest);
var deserializer = new RestSharp.Deserializers.JsonDeserializer();
return deserializer.Deserialize<Dictionary<string, string>>(httpResponse);
});
return token["access_token"]);
}
The _settings object is injected with IOptions<Auth0Settings>, which has this shape and general data.
"authentication": {
"Domain": "[auth0-domain]",
"Audience": "https://[OMITTED].auth0.com/api/v2/",
"ClientId": "ABCDEFGHIJKLMNOP....",
"ClientSecret": "A22u5hgbnwifhwihfwi20u559f...",
"CallbackUrl": "http://localhost:5000/signin-auth0",
"GrantType": "client_credentials"
}
Can anyone help me understand how this could be ported to the native HttpClient that is in .NET Standard 1.6+? I specifically need one that is compatible with netstandard1.6 and netcoreapp1.1.
HttpClient is a very good http client and should be used in .NET core moving forward :)
private static async Task<string> OpenApiAsync()
{
var client = new HttpClient();
client.DefaultRequestHeaders.Add("content-type", "application/json");
var body = JsonConvert.SerializeObject(YOUR_BODY);
var result = await client.PostAsync("https://[OMITTED].auth0.com/oauth/token", new StringContent(body , Encoding.UTF8));
var deserialized = JsonConvert.DeserializeObject<Dictionary<string, string>>(await result.Content.ReadAsStringAsync());
return deserialized["access_token"];
}

Mobile Service Client throws exception when response is not found

I am trying to port an application from an azure mobile service to an azure web app. (the mobile service was working). I have added microsoft account authentication to the web-app, and the web app api has a MobileAppController attribute. I have a Universal windows app front end that calls the api. The app first checks if a player is in the database, if not I get a not found response. If I call the method using the following code with the MobileServiceClient I get an exception.
private async Task<HttpResponseMessage> GetAZMAsyncP(string apiext, IDictionary<string,string> param )
{
string myuri = String.Format("{0}{1}", urlbase, apiext);
//client is the MobileServiceClient that is correctly logged in
//I do not get response which is 404 not found, I get an exception "The request could not be completed, Not Found"
var response = await client.InvokeApiAsync(myuri, System.Net.Http.HttpMethod.Get, param);
return response;
}
If I call the api from an httpclient and add my own headers, which the mobile client is supposed to do for me, then I get the response as requested. Here is the code:
private async static Task<HttpResponseMessage> GetAZAsync(string apiext)
{
string completeUrl = String.Format("{0}{1}", urlbase, apiext);
// Call out to AZ
using (var http = new HttpClient())
{
// http.BaseAddress = new Uri(completeUrl);
HttpRequestMessage rq = new HttpRequestMessage()
{
RequestUri = new Uri(completeUrl),
Method = HttpMethod.Get
};
addauthheader(rq);
var response = await http.SendAsync(rq);
return response;
}
}
private static void addauthheader(HttpRequestMessage rq)
{
MobileServiceUser user = App.client.CurrentUser;
rq.Headers.Add("X-ZUMO-FEATURES", "AT,QS");
rq.Headers.Add("X-ZUMO-INSTALLATION-ID",
"ff90f37e-0c03-4c52-a343-af711752e383");
rq.Headers.Add("X-ZUMO-AUTH", user.MobileServiceAuthenticationToken);
rq.Headers.Add("Accept", "application/json");
rq.Headers.Add("User-Agent", "ZUMO/2.1");
rq.Headers.Add("User-Agent",
"(lang = Managed; os = Windows Store; os_version = --; arch = X86; version = 2.1.40707.0)");
rq.Headers.Add("X-ZUMO-VERSION",
"ZUMO/2.1(lang = Managed; os = Windows Store; os_version = --; arch = X86; version = 2.1.40707.0)");
rq.Headers.Add("ZUMO-API-VERSION", "2.0.0");
}
You can try this out as it is live (and buggy).
https://gamenote2.azurewebsites.net/api/Players?displayname=Paul Goldschmidt&teamid=arizona-diamondbacks
Should give you a 404,
https://gamenote2.azurewebsites.net/api/Players?displayname=Chase Utley&teamid=los-angeles-dodgers
should give you a chase utley object. (YOu will be asked to log into a Microsoft Account).
So my questions: 1. Can I fix the mobileclient call to get a response instead of an execption
2. Is there any good reason for me to be spending so much time on this.
If you examine the exception, you will note that the status code is in there - it's just in a property that is not serialized. Just surround your InvokeApiAsync() call with a try/catch and test for the StatusCode. It should be a lot easier than writing your own HTTP Client code for the same purpose.
Specifically, MobileServiceInvalidOperationException contains the HttpResponse of the failed request, so you can check exception.Response.StatusCode value.

Xamarin Forms HttpClient GetAsync

I have an ASP.NET WebApi hosted in Azure. There is no HTTP Header based or Azure API authentication on it and fiddler sessions prove that the API is fully functional and spits out data as requested and expected.
In my Xamarin forms (PCL, iOS & Android only) PCL project, I have the following code in a service class:
public async Task<IEnumerable<Link>> GetCategories()
{
IEnumerable<Link> categoryLinks = null;
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Using https to satisfy iOS ATS requirements
var response = await client.GetAsync(new Uri("https://myproject.azurewebsites.net/api/contents"));
//response.EnsureSuccessStatusCode(); //I was playing around with this to see if it makes any difference
if (response.IsSuccessStatusCode)
{
var content = response.Content.ReadAsStringAsync().Result;
categoryLinks = JsonConvert.DeserializeObject<IEnumerable<Link>>(content);
}
}
return categoryLinks;
}
I have debugged the code and noticed that the control does not go past:
var response = await client.GetAsync(new Uri("https://myproject.azurewebsites.net/api/contents"));
and as a result categoryLinks remains null.
Has anyone come across this before?
A few things to note:
Although I doubt if there is any issue here but I have a MainViewModel class that looks as follows:
public class MainViewModel
{
private readonly INavigation navigation;
private readonly IContentService contentService;
public IEnumerable<CategoryItem> Categories { get; set; }
public MainViewModel(IContentService contentservice, INavigation nav)
{
this.navigation = nav;
this.contentService = contentservice;
SetCategoriesAsync();
}
private async Task SetCategoriesAsync()
{
var response = await this.contentService.GetCategories();
this.Categories = (from c in response
select new CategoryItem()
{
//code removed but you get the idea
}).AsEnumerable();
}
}
My MainPage.xaml.cs has the following lines in the constructor. I don't think there is any issue here either.
this.MainViewModel = new MainViewModel(contentService, navService);
this.CategoriesList.ItemsSource = this.MainViewModel.Categories;
As per this link, I have already added references via nuget to the following libraries in the order of appearance: Microsoft.BCL, Microsoft.BCL.Build, Microsoft.Net.Http
I'm not using ModernHttpClient as yet. I plan to do so once I have HttpClient working as I believe it improves performance.
Any assistance on this will be greatly appreciated.
I have had this exact problem, and it is being caused by a deadlock, How are you calling this method? usually I go:
Device.BeginInvokeInMainThread(async () =>
{
var categoriesList = await GetCategories();
});
Or if it is inside your View Model, you can use Task.Run();
Avoid using .Result, and timers within your UI even events handlers may cause deadlocks like this one.
Hope this helps.

Search for user in Azure Active directory group using graph api

I would like to have some kind of people picker functionality with auto complete features in my asp.net mvc 5 app to search for a user in a specific Azure AD group. It's a demo "todo app" that allows to assign a todo to a user that is member of a the group.
I tried with both the Graph API directly and the Azure Graph Client library but I don't seem to find a way to achieve what I want. The graph api allows to get the members of a group but adding filter "startswith" fails as when adding the filter the api returns only directory object which don't include for example DisplayName property... the client library doesn't help much either except for the batch functionality which offers a way but with a lot of overhead... I then would have to get a filtered resultset of user regardless of group membership (using User List stuff in the api), all members of the group and then fish out using Linq the correct result set.... would work fine for dev/testing but in production with a couple of hundred users this would be insane...
Any ideas or suggestions would be much appreciated. Thanks!
EDIT
Below my code that is called from client side Javascript to search for user;
AccessGroupId is the Azure AD group used to authorize users. Only
members of this group can access the web app which I handle in custom
OWin Middleware
The method is intented to be used to find a user in that group
Code works fine as below only there is no filtering applied which is the intentaion with the input parameter pre (which comes from a textbox in the ui). I get all the members of the access group.
public async Task<JsonResult> FindUser(string pre)
{
string AccessGroupId = ConfigurationManager.AppSettings["AccessGroupId"];
AuthenticationContext authCtx = new AuthenticationContext(String.Format(CultureInfo.InvariantCulture, "{0}/{1}", SecurityConfiguration.LoginUrl, SecurityConfiguration.Tenant));
ClientCredential credential = new ClientCredential(SecurityConfiguration.ClientId, SecurityConfiguration.AppKey);
AuthenticationResult assertionCredential = await authCtx.AcquireTokenAsync(SecurityConfiguration.GraphUrl, credential);
var accessToken = assertionCredential.AccessToken;
var graphUrl = string.Format("https://graph.windows.net/mytenant.onmicrosoft.com/groups/{0}/members?api-version=2013-11-08, AccessGroupId );
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, graphUrl);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await client.SendAsync(request);
String responseString = await response.Content.ReadAsStringAsync();
JObject jsonReponse = JObject.Parse(responseString);
var l = from r in jsonReponse["value"].Children()
select new
{
UserObjectId = r["objectId"].ToString(),
UserPrincipalName = r["userPrincipalName"].ToString(),
DisplayName = r["displayName"].ToString()
};
//users = Newtonsoft.Json.JsonConvert.DeserializeObject<List<User>>(responseString);
return Json(l, JsonRequestBehavior.AllowGet);
}
When I add a filter to the same api call instead of returning the members (users, groups and/or contacts), it returns directory objects (that doesn't have displayName) which are not really usefull in the above code, unless I would query the api again (in batch) to retrieve the users displayname but that looks like a lot of overhead to me.
var graphUrl = string.Format("https://graph.windows.net/mytenant.onmicrosoft.com/groups/{0}/members?api-version=2013-11-08&$filter=startswith(displayName,'{1}')", AccessGroupId, pre);
I'd highlight two possible approaches:
Execute requests to Graph API using a custom JS library.
You'd need still need to care for accesstokens and have a look at ADAL.js
A sample app (not finalized as of this writing) available at:
AzureADSamples WebApp-GroupClaims-DotNet
Have a look at AadPickerLibrary.js
Try using ActiveDirectoryClient
It would look something like:
public async Task<JsonResult> FindUser(string pre) {
ActiveDirectoryClient client = AADHelper.GetActiveDirectoryClient();
IPagedCollection<IUser> pagedCollection = await client.Users.Where(u => u.UserPrincipalName.StartsWith(pre, StringComparison.CurrentCultureIgnoreCase)).ExecuteAsync();
if (pagedCollection != null)
{
do
{
List<IUser> usersList = pagedCollection.CurrentPage.ToList();
foreach (IUser user in usersList)
{
userList.Add((User)user);
}
pagedCollection = await pagedCollection.GetNextPageAsync();
} while (pagedCollection != null);
}
return Json(userList, JsonRequestBehavior.AllowGet);
}
More detailed sample is available at:
AzureADSamples WebApp-GraphAPI-DotNet

Categories

Resources