Access Microsoft.Storage/storageAccounts/blobServices metrics from code - azure

I want to retrieve metrics related to Blob metric namespace from Azure Storage Account. I need to read the BlobCount value.
Initially I have tried like this:
var usedCapacityResults = await metricsClient.QueryResourceAsync(resourceId, new[] { "BlobCount1" },
new MetricsQueryOptions
{
MetricNamespace = "Blob",
Aggregations =
{
MetricAggregationType.Average
},
Granularity = TimeSpan.FromMinutes(5),
TimeRange = new QueryTimeRange(TimeSpan.FromMinutes(10))
});
if (usedCapacityResults.GetRawResponse().Status == StatusCodes.Status200OK)
{
var usedCapacityMetric = usedCapacityResults.Value.Metrics.FirstOrDefault(m => m.Name == "BlobCount" && m.Error == null);
var metricValue = usedCapacityMetric?.TimeSeries.FirstOrDefault();
if (metricValue != null && !metricValue.Values.IsNullOrEmpty())
{
var average = metricValue.Values[0].Average;
if (average != null) blobCount = (decimal)average;
}
}
But nothing gets returned.
Then I have tried to get the supported metric namespace, using this call:
GET https://management.azure.com/{resourceUri}/providers/microsoft.insights/metricNamespaces?api-version=2017-12-01-preview
and the only valid metric seems to be Microsoft.Storage/storageAccounts, that does not have the blob count metric.
Any idea how to read from code the BlobCount value?
There will be also the option to retrieve the list of containers and iterate though it to count the blobs, but this is something I want to avoid.

The working solution, with help from MS support:
This is the solution that was provided to me by MS Support team:
private async Task<decimal> GetStorageAccountBlobCount(MetricsQueryClient metricsClient, string resourceId)
{
var blobCount = (decimal)0.0;
try
{
resourceId = $"{resourceId}/blobServices/default";
var blobCountResult = await metricsClient.QueryResourceAsync(resourceId, new[] { "BlobCount" },
new MetricsQueryOptions
{
MetricNamespace = "Microsoft.Storage/storageAccounts/blobServices",
Aggregations =
{
MetricAggregationType.Average
},
Granularity = TimeSpan.FromHours(1),
TimeRange = new QueryTimeRange(TimeSpan.FromMinutes(60))
});
if (blobCountResult.GetRawResponse().Status == StatusCodes.Status200OK)
{
var blobCountMetric = blobCountResult.Value.Metrics.FirstOrDefault(m => m.Name == "BlobCount" && m.Error == null);
var metricValue = blobCountMetric?.TimeSeries.FirstOrDefault();
if (metricValue != null && !metricValue.Values.IsNullOrEmpty())
{
var average = metricValue.Values[0].Average;
if (average != null) blobCount = (decimal)average;
}
}
}
catch (Exception ex)
{
_logger.LogError($"Error on calculate blob count for {resourceId}", ex);
}
return blobCount;
}

Related

Uplaoded Image but with 0 KB size

I'm using .NET Core 3.1 but I encountered a weird problem!
the problem is any uploaded image the size of it is 0KB
when I restart the IIS and trying again will upload it without any problem but after that, the problem returns back.
I tried this solution by making my code async but with no luck
I changed my system file to be accessible by my Application pool user but with no luck
Here is my code :
public Document shareWithUsers([FromForm] CreateDocumentDto documentDto)
{
List<CreateUserType1DocumentsDto> listOfCreateUserType1Documents = new List<CreateUserType1DocumentsDto>();
List<CreateHDDocumentsDto> listOfCreateHDDocuments = new List<CreateHDDocumentsDto>();
if (documentDto.listOfUserType1Documents != null)
{
foreach (var item in documentDto.listOfUserType1Documents)
{
listOfCreateUserType1Documents.Add(JsonConvert.DeserializeObject<CreateUserType1DocumentsDto>(item));
}
}
else if (documentDto.listOfHDDocuments != null)
{
foreach (var item in documentDto.listOfHDDocuments)
{
listOfCreateHDDocuments.Add(JsonConvert.DeserializeObject<CreateHDDocumentsDto>(item));
}
}
if (documentDto.sharedText == null)
{
if (documentDto.document != null) //that mean user upload file
{
if (documentDto.document.Length > 0)
{
var UploadedFilesPath = Path.Combine(hosting.WebRootPath/*wwwroot path*/, "UploadedFiles" /*folder name in wwwroot path*/);
var filePath = Path.Combine(UploadedFilesPath, documentDto.document.FileName);
//documentDto.docUrl = filePath;
var documentObject = new Document();
using (var stream = new FileStream(filePath, FileMode.Create))
{
documentDto.document.CopyToAsync(stream);// Use stream
}
if (documentDto.listOfUserType1Documents != null)
{
documentObject.listOfUserType1Documents = ObjectMapper.Map<List<UserType1Documents>>(listOfCreateUserType1Documents);
}
else if (documentDto.listOfHDDocuments != null)
{
documentObject.listOfHDDocuments = ObjectMapper.Map<List<HDDocuments>>(listOfCreateHDDocuments);
}
documentObject.docTtitle = documentDto.docTtitle;
documentObject.docName = documentDto.docName;
documentObject.docUrl = filePath;
return _repository.Insert(documentObject);
}
}
}
else
{ //that mean user upload text
var documentObject = new Document();
if (documentDto.listOfUserType1Documents != null)
{
documentObject.listOfUserType1Documents = ObjectMapper.Map<List<UserType1Documents>>(listOfCreateUserType1Documents);
}
else if (documentDto.listOfHDDocuments != null)
{
documentObject.listOfHDDocuments = ObjectMapper.Map<List<HDDocuments>>(listOfCreateHDDocuments);
}
documentObject.sharedText = documentDto.sharedText;
return _repository.Insert(documentObject);
}
return null;
}
My code works only if I change both of them (CopyTo and Insert ) to Async with await
await CopyToAsync()
await InsertAsync()

How to get Logic App Metrics?

I'm trying to get Logic Apps metrics like BillableExecutions, Latency etc in my console application.
Currently I'm able to list the logic apps runs, triggers, versions using the .Net Client Microsoft.Azure.Management. But it doesn't seem to have the API to access the monitoring API's.
Code excerpt
private static void Main(string[] args)
{
var token = GetTokenCredentials();
var client = new LogicManagementClient(token, new HttpClientHandler())
{
SubscriptionId = new AzureSubscription().SubscriptionId
};
var dataQuery = new ODataQuery<WorkflowFilter>
{
Top = 50
};
using (client)
{
var logicAppsWorkFlows = client.Workflows.ListBySubscription(dataQuery);
foreach (var logicAppsWorkFlow in logicAppsWorkFlows)
{
var runs = GetWorkflowRuns(client, logicAppsWorkFlow.Id.Split('/')[4], logicAppsWorkFlow.Name);
Console.WriteLine(runs.Count);
}
Console.WriteLine(logicAppsWorkFlows.Count());
}
}
Can someone tell me how to access Logic Apps Metrics? Is there a client similar to Microsoft.Azure.Management for access metrics data?
Update 2
I have found a client dll which was in pre release mode which is used to get metrics. Below is my current code
var token = GetTokenCredentials();
var insightsClient = new InsightsClient(token, new HttpClientHandler())
{
SubscriptionId = new AzureSubscription().SubscriptionId
};
var logicManagementClient = new LogicManagementClient(token, new HttpClientHandler())
{
SubscriptionId = new AzureSubscription().SubscriptionId
};
var dataQuery = new ODataQuery<WorkflowFilter>
{
Top = 50
};
using (logicManagementClient)
{
var logicAppsWorkFlows = logicManagementClient.Workflows.ListBySubscription(dataQuery);
foreach (var logicAppsWorkFlow in logicAppsWorkFlows)
{
using (insightsClient)
{
var metricsDataQuery = new ODataQuery<Metric>
{
Filter = "name.value eq 'ActionLatency' and startTime ge '2014-07-16'"
};
IEnumerable<Metric> metricsList = null;
try
{
metricsList = insightsClient.Metrics.List(logicAppsWorkFlow.Id, metricsDataQuery);
}
catch (Exception e)
{
Console.WriteLine(e);
}
if (metricsList == null) continue;
foreach (var metric in metricsList)
{
foreach (var metricValue in metric.Data)
{
Console.WriteLine(metric.Name.Value + " = " + metricValue.Total);
}
}
}
}
}
I'm getting an exception saying the filter string is not valid. Im referring the filter string structure provided here
https://learn.microsoft.com/en-us/rest/api/monitor/filter-syntax
Can someone tell what im doing wrong here?
Thanks
It looks like ge is not allowed for Logic Apps StartTime field for some reason. I had to change the code to below to make it work
using (logicManagementClient)
{
var logicAppsWorkFlows = logicManagementClient.Workflows.ListBySubscription(dataQuery);
foreach (var logicAppsWorkFlow in logicAppsWorkFlows)
{
using (insightsClient)
{
var metricsDataQuery = new ODataQuery<Metric>
{
Filter = "startTime eq " + DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd") + " and name.value eq 'BillableTriggerExecutions' and endTime eq " + DateTime.Now.ToString("yyyy-MM-dd")
};
var query = metricsDataQuery.GetQueryString();
Console.WriteLine(query);
IEnumerable<Metric> metricsList = null;
try
{
//throws exception if there is no metrics data
//TODO: Check whether the logic app ran atleast one time
metricsList = insightsClient.Metrics.List(logicAppsWorkFlow.Id, metricsDataQuery);
}
catch (Exception e)
{
Console.WriteLine(e);
}
if (metricsList == null) continue;
foreach (var metric in metricsList)
{
foreach (var metricValue in metric.Data)
{
Console.WriteLine(metric.Name.Value + " = " + metricValue.Total);
}
}
}
}
}

Mobile App GetIdentityAsync no value

I have this code from Azure Services Mobile App, API custom controller. The result always the same "1:1". I test with all identity providers, google, facebook, twitter, and Microsoft Account, except AD. I think the problem is the call to GetIdentityAsync. Can anyone help me? Thanks
[HttpGet]
public async Task<string> GetIdentityInfo()
{
var user = (MobileAppUser)this.User;
string str = "";
string Provider = "YES", UserId = "NO";
try
{
if (user != null)
{
Provider = "1"; UserId = "1";
var microsoftCredentials = await user.GetIdentityAsync<MicrosoftAccountCredentials>();
if (microsoftCredentials != null && microsoftCredentials.Claims != null)
{
Provider = "MICROSOFT";
UserId = microsoftCredentials.UserId;
}
Provider = "2"; UserId = "2";
var googleCredentials = await user.GetIdentityAsync<GoogleCredentials>();
if (googleCredentials != null && googleCredentials.Claims != null)
{
Provider = "GOOGLE";
UserId = googleCredentials.UserId;
}
Provider = "3"; UserId = "3";
var facebookCredentials = await user.GetIdentityAsync<FacebookCredentials>();
if (facebookCredentials != null && facebookCredentials.Claims != null)
{
Provider = "FACEBOOK";
UserId = facebookCredentials.UserId;
}
Provider = "4"; UserId = "4";
var twitterCredentials = await user.GetIdentityAsync<TwitterCredentials>();
if (twitterCredentials != null && twitterCredentials.Claims != null)
{
Provider = "TWITTER";
UserId = twitterCredentials.UserId;
}
}
else
{
Provider = "NONE"; UserId = "NULL";
}
}
catch (Exception ex)
{
str = "ERROR";
}
finally
{
str = Provider + ":" + UserId;
}
return str;
}
We receive support from Microsoft Support Engineer Adrian Fernandez Garcia, and send an example that worked OK. The unique difference was that EMA_RuntimeUrl must be created manually in mobile app in azure portal in Application Properties, and assigned to Gateway address.
Actually this value is created automatically and don't have to create it manually.
This gave us the error URIFormat NULL value.
All is working OK now.
Thanks to Microsoft for the support.

What is the Best Practice to update multiple fields in a Plugin

I have a plugin registered in Post operation that needs to update multiple fields in CRM using data from an XML file. Currently I am using the following code:
if (node["node1"] != null)
{
var sId = sElement.GetElementsByTagName("pId")[0].InnerText;
Guid sGUID = new Guid(sId);
sEntity["Attrib1"] = sGUID;
service.Update(sEntity);
}
if (node["node2"] != null)
{
var sMax = sElement.GetElementsByTagName("pMax")[0].InnerText;
sEntity["Attrib2"] = sMax;
service.Update(sEntity);
}
if (node["node3"] != null)
{
var sMin = sElement.GetElementsByTagName("pMin")[0].InnerText;
sEntity["Attrib3"] = sMin;
service.Update(sEntity);
}
So I am calling the service.Update each time I need to update and in the above case 3 times.
Is there a better way to accomplish what I am trying to do and call the service.Update only one time?
You can just do a single update in the end (eventually you can add a check in case none of the fields changed, to avoid a useless update):
if (node["node1"] != null)
{
var sId = sElement.GetElementsByTagName("pId")[0].InnerText;
Guid sGUID = new Guid(sId);
sEntity["Attrib1"] = sGUID;
}
if (node["node2"] != null)
{
var sMax = sElement.GetElementsByTagName("pMax")[0].InnerText;
sEntity["Attrib2"] = sMax;
}
if (node["node3"] != null)
{
var sMin = sElement.GetElementsByTagName("pMin")[0].InnerText;
sEntity["Attrib3"] = sMin;
}
service.Update(sEntity);

Create UEFI partition using VDS

I'm trying to create UEFI partition using the IVdsCreatePartitionEx::CreatePartitionEx method.
In the CREATE_PARTITION_PARAMETERS struct parameter I passed PARTITION_SYSTEM_GUID (c12a7328-f81f-11d2-ba4b-00a0c93ec93b) as the partitionType and GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER (0x8000000000000000) as the attributes.
But I get an unknown partition with type c12a0000-f81f-11d2-ba4b-00a0c93ec93b.
.
Any ideas what can be wrong here?
Also I tried to create UEFI partition using WMI on Win8.
But I got Error Value 41010 - The specified partition type is not valid.
Here is my code
static void Main(string[] args)
{
try
{
var scope = new ManagementScope(#"\\.\Root\Microsoft\Windows\Storage");
scope.Connect();
const string query = "SELECT * FROM MSFT_Disk WHERE Number = 7";
var objectQuery = new ObjectQuery(query);
var seacher = new ManagementObjectSearcher(scope, objectQuery);
var disks = seacher.Get();
var disk = disks.Cast<ManagementObject>().FirstOrDefault();
if (disk == null)
{
throw new NoNullAllowedException("Disk is null");
}
var parameters = disk.GetMethodParameters("CreatePartition");
FillInvocationParameters(parameters, new Dictionary<string, object> { { "Size", 104857600 }, { "Offset", 5ul * 1024 * 1024 * 1024 }, { "Alignment", 512 }, { "AssignDriveLetter", false }, { "GptType", "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" }, { "IsHidden", false } });
var result = disk.InvokeMethod("CreatePartition", parameters, null);
var returnValue = result["ReturnValue"];
}
catch (Exception exception)
{
Debug.Fail(exception.Message);
}
}
static void FillInvocationParameters(ManagementBaseObject invokeParameters, IDictionary<string, object> parameters)
{
foreach (var pair in parameters)
{
string stringParamValue;
var managementObjectParam = pair.Value as ManagementObject;
var arrayParam = pair.Value as string[];
if (managementObjectParam != null)
{
stringParamValue = managementObjectParam.GetText(TextFormat.CimDtd20);
invokeParameters[pair.Key] = stringParamValue;
}
else if (arrayParam != null)
{
invokeParameters[pair.Key] = arrayParam;
}
else if (pair.Value != null)
{
stringParamValue = pair.Value.ToString();
invokeParameters[pair.Key] = stringParamValue;
}
}
}
I finally solved the problem using VDS: I created volume using IVdsPack::CreateVolume(), received it's partition, formatted it to Fat32 using IVdsAdvancedDisk::FormatPartition() and
changed PartitionType using IVdsAdvancedDisk2::ChangePartitionType()

Resources