Azure Monitor in .NET Core - azure

Using the preview package for Microsoft.Azure.Management.Monitor, I am trying to get metrics from Azure into a .NET Core application, but I am uncertain about what to input as "resourceUri".
var serviceCreds = await ApplicationTokenProvider.LoginSilentAsync(tenantId, clientId, secret);
var monitorClient = new MonitorManagementClient(serviceCreds);
monitorClient.SubscriptionId = subscriptionId;
var resourceUri = "";
var metrics = await monitorClient.Metrics.ListAsync(resourceUri: resourceUri, cancellationToken: CancellationToken.None);
What should I insert in the resourceUri variable, and where do I get this uri from in Azure? A lot of things are great about Azure, but not documentation 🤨

Good question.
The resourceUri is in this format(this example is for web app, and you should replace with your real subscriptionsId, resourceGroupsName etc.):
/subscriptions/4d7e91d4-e930-4bb5-a93d-163aa358e0dc/resourceGroups/Default-Web-westus/providers/microsoft.web/serverFarms/DefaultServerFarm
You can find this information in the source code, here.
And for different resources, the format has a little difference, I add another resourceUri for blob storage:
/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.Storage/storageAccounts/xxx/blobServices/default/providers/Microsoft.Insights/metrics/ContainerCount
If you still have issues, please feel free to let me know.

Related

Azure data lake query acceleration error - One or more errors occurred. (XML specified is not syntactically valid

I am trying to filter data from azure storage account using ADLS query. Using Azure Data Lake Storage Gen2. Not able to filter data and get the result in. Been stuck on this issue, even Microsoft support is not able to crack this issue. Any help is greatly appreciated.
Tutorial Link: https://www.c-sharpcorner.com/article/azure-data-lake-storage-gen2-query-acceleration/
Solution - .Net Core 3.1 Console App
Error: One or more errors occurred. (XML specified is not syntactically valid.)
Status: 400 (XML specified is not syntactically valid.)
private static async Task MainAsync()
{
var connectionString = "DefaultEndpointsProtocol=https;AccountName=gfsdlstestgen2;AccountKey=0AOkFckONVYkTh9Kpr/VRozBrhWYrLoH7y0mW5wrw==;EndpointSuffix=core.windows.net";
var blobServiceClient = new BlobServiceClient(connectionString);
var containerClient = blobServiceClient.GetBlobContainerClient("test");
await foreach (var blobItem in containerClient.GetBlobsAsync(BlobTraits.Metadata, BlobStates.None, "ds_measuringpoint.json"))
{
var blobClient = containerClient.GetBlockBlobClient(blobItem.Name);
var options = new BlobQueryOptions
{
InputTextConfiguration = new BlobQueryJsonTextOptions(),
OutputTextConfiguration = new BlobQueryJsonTextOptions()
};
var result = await blobClient.QueryAsync(#"SELECT * FROM BlobStorage WHERE measuringpointid = 547", options);
var jsonString = await new StreamReader(result.Value.Content).ReadToEndAsync();
Console.WriteLine(jsonString);
Console.ReadLine();
}
After looking every where and testing almost all variations of ADLS query for .net Microsoft support mentioned
Azure.Storage.Blobs version 12.10 is broken version. We had to downgrade to 12.8.0
Downgrading this package to 12.8.0 worked.

Performance degradation after upgrading to Microsoft.Azure.Cosmos.Table to access Azure table storage

We upgraded to the next version of SDK to access our Azure Table storage.
We observed performance degradation of our application after that. We even created test applications with identical usage pattern to isolate it, and still see this performance hit.
We are using .NET Framework code, reading data from Azure table.
Old client: Microsoft.WindowsAzure.Storage - 9.3.2
New client: Microsoft.Azure.Cosmos.Table - 1.0.6
Here is one of the sample tests we tried to run:
public async Task ComparisionTest1()
{
var partitionKey = CompanyId.ToString();
{
// Microsoft.Azure.Cosmos.Table
var storageAccount = Microsoft.Azure.Cosmos.Table.CloudStorageAccount.Parse(ConnectionString);
var tableClient = Microsoft.Azure.Cosmos.Table.CloudStorageAccountExtensions.CreateCloudTableClient(storageAccount);
var tableRef = tableClient.GetTableReference("UserStatuses");
var query = new Microsoft.Azure.Cosmos.Table.TableQuery<Microsoft.Azure.Cosmos.Table.TableEntity>()
.Where(Microsoft.Azure.Cosmos.Table.TableQuery.GenerateFilterCondition("PartitionKey", "eq", partitionKey));
var result = new List<Microsoft.Azure.Cosmos.Table.TableEntity>(20000);
var stopwatch = Stopwatch.StartNew();
var tableQuerySegment = await tableRef.ExecuteQuerySegmentedAsync(query, null);
result.AddRange(tableQuerySegment.Results);
while (tableQuerySegment.ContinuationToken != null)
{
tableQuerySegment = await tableRef.ExecuteQuerySegmentedAsync(query, tableQuerySegment.ContinuationToken);
result.AddRange(tableQuerySegment.Results);
}
stopwatch.Stop();
Trace.WriteLine($"Cosmos table client. Elapsed: {stopwatch.Elapsed}");
}
{
// Microsoft.WindowsAzure.Storage
var storageAccount = Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse(ConnectionString);
var tableClient = storageAccount.CreateCloudTableClient();
var tableRef = tableClient.GetTableReference("UserStatuses");
var query = new Microsoft.WindowsAzure.Storage.Table.TableQuery<Microsoft.WindowsAzure.Storage.Table.TableEntity>()
.Where(Microsoft.WindowsAzure.Storage.Table.TableQuery.GenerateFilterCondition("PartitionKey", "eq", partitionKey));
var result = new List<Microsoft.WindowsAzure.Storage.Table.TableEntity>(20000);
var stopwatch = Stopwatch.StartNew();
var tableQuerySegment = await tableRef.ExecuteQuerySegmentedAsync(query, null);
result.AddRange(tableQuerySegment.Results);
while (tableQuerySegment.ContinuationToken != null)
{
tableQuerySegment = await tableRef.ExecuteQuerySegmentedAsync(query, tableQuerySegment.ContinuationToken);
result.AddRange(tableQuerySegment.Results);
}
stopwatch.Stop();
Trace.WriteLine($"Old table client. Elapsed: {stopwatch.Elapsed}");
}
}
Anyone observed it, any thoughts about it?
The performance issue will be resolved in Table SDK 1.0.7 as verified with large entity.
On 1.0.6 the workaround is to disable Table sdk trace by adding diagnostics section in app.config if it's a .NET framework app. It will still be slower than Storage sdk, but much better than without the workaround depending on the usage.
I think your data are stored in the legacy Storage Table. Just in case, if this is CosmosDB Table backed, you may get better performance if you set TableClientConfiguration.UseRestExecutorForCosmosEndpoint to True.
If it's the legacy Storage Table store, CosmosDB Table sdk 1.0.6 is about 15% slower than Storage Table sdk 9.3.3. In addition, it has an extra second overhead upon the first CRUD operation. Higher query duration has been resolved in 1.0.7, which is on-par with Storage SDK. The initialization second is still required why using CosmosDB Table sdk 1.0.7, which should be acceptable.
We are planning to release 1.0.7 during the week of 4/13.

Sending IM with Skype for Business Online from Console App

I am trying to set up a C# console app that can send notifications/reminders to users via Skype for Business online from a generic AD account. I was excited to see the other day that according to this page, UCWA is now supported in Skype for Business online: https://msdn.microsoft.com/en-us/library/office/mt650889.aspx.
I've been trying to follow this tutorial to get this set up: https://msdn.microsoft.com/en-us/library/office/mt590891(v=office.16).aspx. So far I haven't really had much luck... I have my application set up in Azure AD but I get stuck at the "Requesting an access token using implicit grant flow" step of that article (not 100% certain I'm taking the correct actions before that either)... so far I have this:
string clientId = "xxxxxxxx"
string resourceUri = "https://webdir.online.lync.com";
string authorityUri = "https://login.windows.net/common/oauth2/authorize";
AuthenticationContext authContext = new AuthenticationContext(authorityUri);
UserCredential cred = new UserCredential("username", "password");
string token = authContext.AcquireToken(resourceUri, clientId, cred).AccessToken;
var poolReq = CreateRequest("https://webdir.online.lync.com/autodiscover/autodiscoverservice.svc/root", "GET",token);
var poolResp = GetResponse(poolReq);
dynamic tmp = JsonConvert.DeserializeObject(poolResp);
string resourcePool = tmp._links.user.href;
Console.WriteLine(resourcePool);
var accessTokenReq = CreateRequest("https://login.windows.net/common/oauth2/authorize"
+ "?response_type=id_token"
+ "&client_id=" + clientId
+ "&redirect_uri=https://login.live.com/oauth20_desktop.srf"
+ "&state=" + Guid.NewGuid().ToString()
+ "&resource=" + new Uri(resourcePool).Host.ToString()
, "GET",token);
var accessTokenResp = GetResponse(accessTokenReq);
my GetResponse and CreateRequest methods:
public static string GetResponse(HttpWebRequest request)
{
string response = string.Empty;
using (HttpWebResponse httpResponse = request.GetResponse() as System.Net.HttpWebResponse)
{
//Get StreamReader that holds the response stream
using (StreamReader reader = new System.IO.StreamReader(httpResponse.GetResponseStream()))
{
response = reader.ReadToEnd();
}
}
return response;
}
public static HttpWebRequest CreateRequest(string uri, string method, string accessToken)
{
HttpWebRequest request = System.Net.WebRequest.Create(uri) as System.Net.HttpWebRequest;
request.KeepAlive = true;
request.Method = method;
request.ContentLength = 0;
request.ContentType = "application/json";
request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken));
return request;
}
accessTokenResp is an office online logon page, not the access token I need to move forward... so I'm stuck. I've tried quite a few variations of the above code.
I've been scouring the net for more examples but can't really find any, especially since UCWA support for Office 365 is so new. Does anyone have an example of how to do what I am trying to do or can point me to one? Everything I've found so far hasn't really even been close to what I'm trying. I can't use the Skype for Business client SDK unfortunately either as it doesn't meet all of my requirements.
I came to a working solution using ADAL (v3), with the help of steps outlined at
Authentication using Azure AD
Here the steps, which involve requesting multiple authentication tokens to AAD using ADAL
Register your application, as Native Application, in Azure AD.
Perform autodiscovery to find user's UCWA root resource URI.
This can be done by performing a GET request on
GET https://webdir.online.lync.com/Autodiscover/AutodiscoverService.svc/root?originalDomain=yourdomain.onmicrosoft.com
Request an access token for the UCWA root resource returned in the autodiscovery response, using ADAL
For instance, your root resource will be at
https://webdir0e.online.lync.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=yourdomain.onmicrosoft.com
you'll have to obtain a token from AAD for resource https://webdir0e.online.lync.com/
Perform a GET on the root resource with the bearer token obtained from ADAL
GET https://webdir0e.online.lync.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=yourdomain.onmicrosoft.com
This will return, within the user resource, the URI for applications resource, where to create your UCWA application. This in my case is:
https://webpoolam30e08.infra.lync.com/ucwa/oauth/v1/applications
Residing then in another domain, thus different audience / resource, not included in the auth token previously obatained
Acquire a new token from AAD for the host resource where the home pool and applications resource are (https://webpoolam30e08.infra.lync.com in my case)
Create a new UCWA application by doing a POST on the applications URI, using the token obtained from ADAL
Voilá, your UCWA application is created. What I notice at the moment, is that just few resources are available, excluding me / presence. So users' presence can be retrieved, but self presence status can't be changed.
I've been able however to retrieve my personal note, and the following resources are available to me:
people
communication
meetings
Show me some code:
Function to perform the flow obtaining and switching auth tokens
public static async Task<UcwaApp> Create365UcwaApp(UcwaAppSettings appSettings, Func<string, Task<OAuthToken>> acquireTokenFunc)
{
var result = new UcwaApp();
result.Settings = appSettings;
var rootResource = await result.Discover365RootResourceAsync(appSettings.DomainName);
var userUri = new Uri(rootResource.Resource.GetLinkUri("user"), UriKind.Absolute);
//Acquire a token for the domain where user resource is
var token = await acquireTokenFunc(userUri.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped));
//Set Authorization Header with new token
result.AuthToken = token;
var usersResult = await result.GetUserResource(userUri.ToString());
//
result.ApplicationsUrl = usersResult.Resource.GetLinkUri("applications");
var appsHostUri = new Uri(result.ApplicationsUrl, UriKind.Absolute).GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped);
//Acquire a token for the domain where applications resource is
token = await acquireTokenFunc(appsHostUri);
//Set Authorization Header with new token
result.AuthToken = token;
//
var appResult = await result.CreateApplicationAsync(result.ApplicationsUrl, appSettings.ApplicationId, appSettings.UserAgent, appSettings.Culture);
return result;
}
Usage code ato retrieve OAuth tokens using ADAL
var ucSettings = new UcwaAppSettings
{
UserAgent = "Test Console",
Culture = "en-us",
DomainName = "yourdomain.onmicrosoft.com",
ApplicationId = "your app client id"
};
var acquireTokenFunc = new Func<string, Task<OAuthToken>>(async (resourceUri) =>
{
var authContext = new AuthenticationContext("https://login.windows.net/" + ucSettings.DomainName);
var ar = await authContext.AcquireTokenAsync(resourceUri,
ucSettings.ApplicationId,
new UserCredential("myusername", "mypassword"));
return new OAuthToken(ar.AccessTokenType, ar.AccessToken, ar.ExpiresOn.Ticks);
});
var app = await UcwaApp.Create365UcwaApp(ucSettings, acquireTokenFunc);
It should be of course possible to avoid hard-coding username and password using ADAL, but this was easier for PoC and especially in case of Console Application as you asked
I've just blogged about this using a start-to-finish example, hopefully it will help you. I only go as far as signing in, but you can use it with another post I've done on sending IMs using Skype Web SDK here (see day 13 and 14) and combine the two, it should work fine.
-tom
Similar to Massimo's solution, I've created a Skype for Business Online C# based console app that demonstrates how to sign and use UCWA to create/list/delete meetings and change user presence. I haven't gotten around to extending it to send IM's, but you're certainly welcome to clone my repository and extend it to your needs. Just drop in your Azure AD tenant name and native app ID into the code.
I think they just turned this on today - I was doing something unrelated with the Skype Web SDK samples and had to create a new Azure AD app, and noticed that there are two new preview features for receiving conversation updates and changing user information.
Now everything in the Github samples works for Skype For Business Online.

Change Azure website app settings from code

Is it possible to change the app settings for a website from the app itself?
This is not meant to be an everyday operation, but a self-service reconfiguration option. A non-developer can change a specific setting, which should cause a restart, just like I can do manually on the website configuration page (app setting section)
You can also use the Azure Fluent Api.
using Microsoft.Azure.Management.Fluent;
using Microsoft.Azure.Management.ResourceManager.Fluent;
using Microsoft.Azure.Management.ResourceManager.Fluent.Authentication;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core;
...
public void UpdateSetting(string key, string value)
{
string tenantId = "a5fd91ad-....-....-....-............";
string clientSecret = "8a9mSPas....................................=";
string clientId = "3030efa6-....-....-....-............";
string subscriptionId = "a4a5aff6-....-....-....-............";
var azureCredentials = new AzureCredentials(new
ServicePrincipalLoginInformation
{
ClientId = clientId,
ClientSecret = clientSecret
}, tenantId, AzureEnvironment.AzureGlobalCloud);
var _azure = Azure
.Configure()
.WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
.Authenticate(azureCredentials)
.WithSubscription(subscriptionId);
var appResourceId = "/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.Web/sites/xxx"; //Get From WebApp -> Properties -> Resource ID
var webapp = _azure.WebApps.GetById(appResourceId);
//Set App Setting Key and Value
webapp.Update()
.WithAppSetting(key, value)
.Apply();
}
It wasn't that hard once I found the right lib to do it, Microsoft Azure Web Sites Management Library.
var credentials = GetCredentials(/*using certificate*/);
using (var client = new WebSiteManagementClient(credentials))
{
var currentConfig = await client.WebSites.GetConfigurationAsync(webSpaceName,
webSiteName);
var newConfig = new WebSiteUpdateConfigurationParameters
{
ConnectionStrings = null,
DefaultDocuments = null,
HandlerMappings = null,
Metadata = null,
AppSettings = currentConfig.AppSettings
};
newConfig.AppSettings[mySetting] = newValue;
await client.WebSites.UpdateConfigurationAsync(webSpaceName, webSiteName,
newConfig);
}
Have you read into the Service Management REST API? The documentation mentions that it allows you to perform most the actions that are available via the Management Portal programmatically.
In addition to Diego answer, to use the Azure Management Librairies within a WebApp (WebSites and/or WebJobs), you need to configure SSL which is a little bit tricky:
Using Azure Management Libraries from Azure Web Jobs

Extend functionality of Azure Mobile Services using ASP.NET Identity

I have a .Net Mobile Services back end (i.e. not the JavaScript one) which out of the box supports authentication with the common Identity Providers (facebook, twitter, etc) through the windows azure portal. However I would like users to be able to create their own username/password accounts as they can do with the ASP.NET Web Api implementation of ASP.NET Identity (using AccountController).
The question is if this is possible and if so what is the best way of achieving it?
My first thought was to just copy the appropriate classes (AccountController, Startup.Auth, ApplicationOAuthProvider, etc) from a template ASP.NET MVC Web Api project and add a reference to Microsoft.AspNet.Identity.EntityFramework and System.Web.MVC but I don't know what impact this would have. If it worked would I have just taken control of the Authentication logic with the portal "Identity" no longer having any effect?
The other option is to simply start with a Web Api project and add the Mobile Services functionality to that instead (Although I couldn't see how to create a Web Api project without MVC but that is a different question).
Thanks for any help.
UPDATE 11 April 2014
In the end we decided to manage our own username and passwords and generate a JWT token so that the client could use the standard IMobileServiceClient. To do this we used two resources. The first was from the joy of code:
http://www.thejoyofcode.com/Exploring_custom_identity_in_Mobile_Services_Day_12_.aspx
and the second was from content master:
http://www.contentmaster.com/azure/creating-a-jwt-token-to-access-windows-azure-mobile-services/
Although we made some small changes to the code as per this Mobile Services team blog post:
[Don't have enough reputation points to add a third link so just google "changes-in-the-azure-mobile-services-jwt-token"]
So here is the code if useful. (it might be better to write an implementation using JwtSecurityTokenHandler but this works for us)
public static string GetSecurityToken(TimeSpan periodBeforeExpires, string aud, string userId, string masterKey)
{
var now = DateTime.UtcNow;
var utc0 = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
var payload = new
{
exp = (int)now.Add(periodBeforeExpires).Subtract(utc0).TotalSeconds,
iss = "urn:microsoft:windows-azure:zumo",
ver = 2,
aud = "urn:microsoft:windows-azure:zumo",
uid = userId
};
var keyBytes = Encoding.UTF8.GetBytes(masterKey + "JWTSig");
var segments = new List<string>();
//kid changed to a string
var header = new { alg = "HS256", typ = "JWT", kid = "0" };
byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header, Formatting.None));
byte[] payloadBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload, Formatting.None));
segments.Add(Base64UrlEncode(headerBytes));
segments.Add(Base64UrlEncode(payloadBytes));
var stringToSign = string.Join(".", segments.ToArray());
var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);
SHA256Managed hash = new SHA256Managed();
byte[] signingBytes = hash.ComputeHash(keyBytes);
var sha = new HMACSHA256(signingBytes);
byte[] signature = sha.ComputeHash(bytesToSign);
segments.Add(Base64UrlEncode(signature));
return string.Join(".", segments.ToArray());
}
// from JWT spec
private static string Base64UrlEncode(byte[] input)
{
var output = Convert.ToBase64String(input);
output = output.Split('=')[0]; // Remove any trailing '='s
output = output.Replace('+', '-'); // 62nd char of encoding
output = output.Replace('/', '_'); // 63rd char of encoding
return output;
}
This is possible but not quite as simple as we would like (we have a bug on improving it). In general it boils down to that you can inject things into the OWIN pipeline including auth providers.
If you are familiar with the OWIN pipeline and ASP.NET Identity Framework then here's roughly what you do:
1) Crate your own OWIN App Builder which sets up the OWIN pipeline for the .NET backend.
2) Register your App Builder with the Dependency Injection engine which will get called as part of the initialization.
Here is a gist of what it looks like (using the latest NuGets from nuget.org):
https://gist.github.com/HenrikFrystykNielsen/9835526
It won't automatically get hooked into the "login" controller we have a work item to enable this but I think it should work if you are careful.
Btw, you can find some good information from Filip W's blog: http://www.strathweb.com/2014/02/running-owin-pipeline-new-net-azure-mobile-services/
Hope this helps!
Henrik

Resources