> ## Content Index
> Fetch the complete content index at: https://www.azurebrasil.cloud/llms.txt
> Use this file to discover other available public pages before exploring further.

# Como utilizar o Azure Cost Management REST API
- URL: https://www.azurebrasil.cloud/blog/azure-cost-management/
- Published: 2023-05-24T14:37:01.000Z
- Updated: 2023-05-24T14:37:01.000Z
- Author: Talles Valiatti

Muitas vezes temos a necessidade de integrar as APIs da Azure em nossas aplicações e fluxos de trabalho. A Azure nos oferece uma [série de APIs especializadas](https://learn.microsoft.com/en-us/rest/api/azure/?ref=azurebrasil.cloud)!

Hoje vamos fazer algumas chamadas a API de *cost management*, com objetivo de obter os gastos diários de qualquer [*subscription* pertencente a sua *tenant*](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/organize-subscriptions?ref=azurebrasil.cloud)*.* Inicialmente vamos registrar uma nova [*application* em nosso Azure AD.](https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app?ref=azurebrasil.cloud)

![](https://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2023/05/Screen-Shot-2023-05-12-at-14.40-1.png)

Nossa aplicação ira interagir com o Azure por conta própria, não necessitando que nenhum usuário esteja autenticado. Por isso, será preciso [gerar um ](https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal?ref=azurebrasil.cloud#option-3-create-a-new-application-secret)[certificado ou segredo para essa aplicação](https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal?ref=azurebrasil.cloud#option-3-create-a-new-application-secret). 

![](https://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2023/05/Group-1011.png)

Copie o valor do segredo. Além disso, devemos também salvar outros valores referentes a nossa *tenant Id*, *subscription Id e client Id.*

![](https://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2023/05/Group-1013.png)

Para que nossa aplicação possa ler os valores dos gastos diários*,* devemos conceder a permissão de *Reader* da nossa *subscription* para nossa aplicação. Vamos utilizar o [Azure RBAC](https://learn.microsoft.com/en-us/azure/role-based-access-control/overview?ref=azurebrasil.cloud)!

Dentro da *subscription,* devemos ir menu *"Access control (IAM)"* e clicar em *"Add role assignment".* 

![](https://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2023/05/Screen-Shot-2023-05-12-at-15.10.png)

Basta selecionarmos a permissão de *Reader* e a nossa aplicação como alvo da atribuição.

![](https://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2023/05/Group-1012.png)

Com isso pronto, já podemos criar nosso aplicação. Vamos criar um novo diretório, [uma ](https://learn.microsoft.com/en-us/visualstudio/ide/solutions-and-projects-in-visual-studio?view=vs-2022&ref=azurebrasil.cloud)*[solution](https://learn.microsoft.com/en-us/visualstudio/ide/solutions-and-projects-in-visual-studio?view=vs-2022&ref=azurebrasil.cloud)*[ do .NET](https://learn.microsoft.com/en-us/visualstudio/ide/solutions-and-projects-in-visual-studio?view=vs-2022&ref=azurebrasil.cloud) e um [projeto web básico](https://learn.microsoft.com/en-us/aspnet/core/tutorials/min-web-api?view=aspnetcore-7.0&tabs=visual-studio&ref=azurebrasil.cloud).

```
mkdir AzureCostManagement
```

```
dotnet new sln
```

```
dotnet new web -o AzureCostManagement.Api
```

Devemos [adicionar o projeto a *solution*](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-sln?ref=azurebrasil.cloud#add)recém criada*.*

```
dotnet sln add AzureCostManagement.Api/AzureCostManagement.Api.csproj
```

Podemos adicionar algumas configurações ao *appsettings.json* do nosso projeto.

```
 "Application": {
    "AzureAdLoginUrlResource" : "https://login.microsoftonline.com",
    "AzureAdLoginUrlPath" : "/{0}/oauth2/v2.0/token",
    "AzureCostManagementUrlResource": "https://management.azure.com",
    "AzureCostManagementUrlPath": "/subscriptions/{0}/providers/Microsoft.CostManagement/forecast?api-version=2022-10-01",
    "ClientId" : "<your-client-id>",
    "ClientSecret" : "<your-client-secret>",
    "TenantId" : "<your-tenant-id>"
  }
```

Teremos dois serviços implementados em nosso projeto:

- *IEnterpriseIdentityService*: responsável por autenticar a aplicação, e consequentemente obter o *[access token](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens?ref=azurebrasil.cloud)*;
- *ICostManagementService:* serviço responsável em fazer a chamada à API[https://management.azure.com](https://management.azure.com/?ref=azurebrasil.cloud).

Vamos as interfaces e implementações:

### IEnterpriseIdentityService

```
using AzureCostManagement.Api.Models;
namespace AzureCostManagement.Api
{
    public interface IEnterpriseIdentityService
    {
        Task<AccessToken> GetAccessToken(string scope);
    }
}
```

```
using System.Text.Json;
using AzureCostManagement.Api.Models;

namespace AzureCostManagement.Api
{
    public class AzureAdService : IEnterpriseIdentityService
    {
        private readonly IConfiguration _configuration;
        private readonly HttpClient _httpClient;
        
        public AzureAdService(
        IConfiguration configuration, 
        IHttpClientFactory httpclientFactory)
        {
            _configuration = configuration;
            _httpClient = httpclientFactory.CreateClient();
        }
        public async Task<AccessToken> GetAccessToken(string scope)
        {
            var url = _configuration.GetSection("Application:AzureAdLoginUrlResource").Value!;
            
            var path = _configuration.GetSection("Application:AzureAdLoginUrlPath").Value!;

            var dict = new Dictionary<string, string>
            {
                { "grant_type", "client_credentials" },
                { "client_id", _configuration.GetSection("Application:ClientId").Value! },
                { "client_secret", _configuration.GetSection("Application:ClientSecret").Value! },
                { "scope", $"{scope}/.default" }
            };
   
            var fullUrl = string.Format(
                $"{url}{path}",
                _configuration.GetSection("Application:TenantId").Value!);

            var requestBody = new FormUrlEncodedContent(dict);
            
            var response = await _httpClient.PostAsync(fullUrl, requestBody);

            response.EnsureSuccessStatusCode();

            var result = await response.Content.ReadAsStringAsync();

            return JsonSerializer.Deserialize<AccessToken>(result)!;
        }
    }
}
```

```
using System.Text.Json.Serialization;

namespace AzureCostManagement.Api.Models
{
    public record AccessToken
    {
         [JsonPropertyName("token_type")]
        public string TokenType { get; set; } = default!;

        [JsonPropertyName("expires_in")]
        public long ExpiresIn { get; set; }

        [JsonPropertyName("access_token")]
        public string Token { get; set; } = default!;
    }
}
```

### ICostManagementService

```
namespace AzureCostManagement.Api.Models
{
    public interface ICostManagementService
    {
        Task<CostManagementResult> GetUsageCostsAync(Guid subscriptionId, DateTime endDate, DateTime startDate);
    }
}
```

```
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace AzureCostManagement.Api.Models
{
    public record CostManagementResult
    {
        [JsonPropertyName("id")]
        public string Id { get; init; } = default!;

        [JsonPropertyName("name")]
        public string Name { get; init; } = default!;

        [JsonPropertyName("type")]
        public string Type { get; init; } = default!;

        [JsonPropertyName("properties")]
        public CostManagementProperties Properties { get; init; } = default!;
    }

    public record CostManagementProperties
    {
        [JsonPropertyName("nextLink")]
        public string? NextLink { get; init; }

        [JsonPropertyName("columns")]
        public IEnumerable<CostManagementColumn> Columns { get; init; } = default!;

        [JsonPropertyName("rows")]
        public IEnumerable<IEnumerable<dynamic>> Rows { get; init; } = default!;

        public IEnumerable<CostManagementRow> RowsFormated
        {
            get
            {
                var dateFormat = "yyyyMMdd";

                return Rows.Select(x => new CostManagementRow
                {
                    // Amount
                    Amount = ((JsonElement)x.ToArray<object>()[0]).GetDouble(),

                    // Date
                    Date = DateTime.ParseExact(
                        ((JsonElement)x.ToArray<object>()[1]).GetInt64().ToString(),
                        dateFormat,
                        CultureInfo.InvariantCulture),

                    // CostStatus
                    CostStatus = ((JsonElement)x.ToArray<object>()[2]).GetString()!,

                    // Currency
                    Currency = ((JsonElement)x.ToArray<object>()[3]).GetString()!,
                });
            }
        }        
    }

    public record CostManagementRow
    {
        public double Amount { get; init; }

        public DateTime Date { get; init; }

        public string CostStatus { get; init; } = default!;

        public string Currency { get; init; } = default!;
    }

    public record CostManagementColumn
    {
        [JsonPropertyName("name")]
        public string Name { get; set; } = null!;

        [JsonPropertyName("type")]
        public string Type { get; set; } = null!;
    }
}
```

```
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using AzureCostManagement.Api.Models;

namespace AzureCostManagement.Api
{
    public class AzureCostManagementService : ICostManagementService
    {
        private readonly IEnterpriseIdentityService _enterpriseIdentityService;
        private readonly IConfiguration _configuration;
        private readonly HttpClient _httpClient;
        
        public AzureCostManagementService(
            IEnterpriseIdentityService enterpriseIdentityService, 
            IConfiguration configuration,
            IHttpClientFactory httpClientFactory)
        {
            _enterpriseIdentityService = enterpriseIdentityService;
            _configuration = configuration;
            _httpClient = httpClientFactory.CreateClient();
        }
        
        public async Task<CostManagementResult> GetUsageCostsAync(Guid subscriptionId, DateTime endDate, DateTime startDate)
        {
            var url = _configuration.GetSection("Application:AzureCostManagementUrlResource").Value!;
            var path = _configuration.GetSection("Application:AzureCostManagementUrlpath").Value!;

            var acessToken = await _enterpriseIdentityService.GetAccessToken(url);

            var request = new CostManagementRequestBuilder()
                .WithStartDate(startDate)
                .WithEndDate(endDate)
                .Build();

            var json = JsonSerializer.Serialize(request);

            var data = new StringContent(json, Encoding.UTF8, "application/json");

            var fullUrl = string.Format(
                $"{url}{path}",
                subscriptionId);

            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", acessToken.Token);

            var response = await _httpClient.PostAsync(fullUrl, data);

            response.EnsureSuccessStatusCode();

            var result = await response.Content.ReadAsStringAsync();

            return JsonSerializer.Deserialize<CostManagementResult>(result)!;
        }
    }
}
```

Observe que injetamos via [DI](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-7.0&ref=azurebrasil.cloud) o serviço *IEnterpriseIdentityService* dentro da implementação *AzureCostManagementService.*

Com os serviços prontos, podemos implementar a classe principal da nossa aplicação!

### Program.cs

Como estamos utilizando uma miniaml API, todas as configurações e métodos HTTP irão estar no mesmo arquivo. Iremos injetar via *depedency injection* o serviço de *cost management* no método *GET* e retornar aos usuários os valores de gastos da *subscription* formatados*.*

```
using AzureCostManagement.Api;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddScoped<ICostManagementService, AzureCostManagementService>();
builder.Services.AddScoped<IEnterpriseIdentityService, AzureAdService>();
builder.Services.AddHttpClient();

var app = builder.Build();

app.MapGet("/cost-management", async (
    [FromQuery] Guid subscritionId,
    ICostManagementService costManagementService) => 
{
    var today = DateTime.Today;

    var firstDayOfCurrentMonth = new DateTime(today.Year, today.Month, 1);
    var lastDayOfCurrentMonth = firstDayOfCurrentMonth.AddMonths(1).AddDays(-1);

    var data = await costManagementService.GetUsageCostsAync(
        subscritionId, 
        lastDayOfCurrentMonth, 
        firstDayOfCurrentMonth);

    return Results.Ok(new 
    {
        Values = data.Properties.RowsFormated
    });
 });

app.Run();

```

Podemos executar nosso projeto e fazer a chamada HTTP, passando como *query string* o valor da *subscriptionId.*

```
dotnet run
```

![](https://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2023/05/Group-1010.png)

Temos o resultado:

![](https://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2023/05/Screen-Shot-2023-05-17-at-09.22.png)

  
Isso é tudo pessoal! Você já pode baixar o projeto por esse [](https://github.com/TallesValiatti/AzureSqlReadOnlyReplica?ref=azurebrasil.cloud)[link](https://github.com/TallesValiatti/AzureCostManagementRestApi?ref=azurebrasil.cloud), e não esquece de me seguir no [LinkedIn](https://www.linkedin.com/in/tallesvaliatti/?ref=azurebrasil.cloud)!

Até a próxima, abraços!