7 Janeiro 2016

Dados em tempo real para um Dashboard em Power BI

Atualmente, a busca por informação quer para um negócio pessoal quer para vida pessoal, quer-se de forma instantânea e se possível sem necessidade de interação por parte dos utilizadores.

O que se pretende abordar será a integração de dados com o Power BI em tempo real.

Através do recentemente lançado Power BI API Rest, é possível atualizar a informação de um Dashboard em tempo real sempre que a nossa fonte de dados sofra alterações. Qualquer linguagem de programação com suporte REST pode fazer integração com esta API.

Apesar das limitações que esta API ainda possui, já é possível usar algumas das mais importantes funcionalidades, entre as quais:

  • Autenticação com Azure Active Directory OAuth2
  • Criação/Eliminação datasets
  • Adicionar / Remover dados

Abaixo é descrito o comportamento de uma aplicação para o Power BI:

Fonte – https://msdn.microsoft.com/en-us/library/dn877544.aspx

Para este exemplo foi criada uma aplicação consola em C#, que envia continuamente os dados de um computador local para o PowerBI. Para a interacção com a API os pedidos JSON são enviados através do protocolo HTTP.

Para podermos aceder à Power Bi Rest API, é necessário autenticarmos a nossa aplicação na Azure AD, previamente criada com as configurações necessárias.

(Fonte: https://powerbi.microsoft.com/en-us/documentation/powerbi-developer-create-an-azure-active-directory-tenant/)

Autenticação com Azure Active Directory (OAuth2)

O método de autenticação usado foi o seguinte:

private TokenSingleton()

{

try

{

//Get access token:

// To call a Power BI REST operation, create an instance of AuthenticationContext and call AcquireToken

// AuthenticationContext is part of the Active Directory Authentication Library NuGet package

// To install the Active Directory Authentication Library NuGet package in Visual Studio,

//  run “Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory” from the nuget Package Manager Console.

//Resource Uri for Power BI API

// OAuth2 authority Uri = https://analysis.windows.net/powerbi/api

string resourceUri = ConfigurationManager.AppSettings[nsCom.Consts.ResourceUri];

// ClientID provided from Azure AD Application

string clientId = ConfigurationManager.AppSettings[nsCom.Consts.ClientID];

// Create an instance of AuthenticationContext to acquire an Azure access token

// OAuth2 authority Uri = https://login.windows.net/common/oauth2/authorize

string authorityUri = ConfigurationManager.AppSettings[nsCom.Consts.AuthorityUri]; ;

AuthenticationContext authContext = new AuthenticationContext(authorityUri);

UserCredential UserCredential = new UserCredential(ConfigurationManager.AppSettings[nsCom.Consts.Username], ConfigurationManager.AppSettings[nsCom.Consts.Password]);

// Call AcquireToken to get an Azure token from Azure Active Directory token issuance endpoint

//  AcquireToken takes a Client Id that Azure AD creates when you register your client app.

//  To learn how to register a client app and get a Client ID, see https://msdn.microsoft.com/en-US/library/dn877542(Azure.100).aspx

token = authContext.AcquireToken(resourceUri, clientId, UserCredential);

}

catch (Exception ex)

{

throw ex;

}

}

token criado é então usado para as futuras chamadas à API.

Criação Dataset

O próximo passo será criar o dataset que irá compor o Dashboard. Os tipos que poderão ser usados para as colunas das tabelas são : int64, bool, DateTime, string e double. Para criação do dataset schema é necessário serializar o objeto em JSON e enviar para o PowerBI:

/// <summary>

/// Creates a dataset based on a DatasetSchema.

/// </summary>

/// <param name=”Schema”>Dataset Schema represents the definition of dataset including dataset name, tables and columns for each table.</param>

/// <returns>Created dataset as .NET object.</returns>

public static dataset GetDataset()

{

try

{

// DatasetName = DataSet

DataSet dataset = new DataSet() { name = ConfigurationManager.AppSettings[nsCom.Consts.DatasetName]};

dataset.tables =new Table[1];

dataset.tables[0] = new Table() { name = “IntGeneratorTable” };

dataset.tables[0].columns = new Column[2];

dataset.tables[0].columns[0] = new Column() { name = “DateTime”, dataType = “DateTime” };

dataset.tables[0].columns[1] = new Column() { name = “Int”, dataType = “Int64” }

// LIB used to serialize objects to JSON

JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();

var str = jsonSerializer.Serialize(dataset);

//Power BI Datasets Url

string powerBIApiUrl = “https://api.powerbi.com/v1.0/myorg/datasets“;

byte[] byteArray = Encoding.UTF8.GetBytes(str);

HttpWebRequest request = System.Net.WebRequest.Create(powerBIApiUrl) as System.Net.HttpWebRequest;

request.KeepAlive = true;

request.Method = “POST”;

request.ContentLength = byteArray.Length;

request.ContentType = “application/json”;

//Add access token to Request header

request.Headers.Add(“Authorization”, String.Format(“Bearer {0}”, nsToken.TokenSingleton.Instance.token.AccessToken));

// Get the request stream.

Stream dataStream = request.GetRequestStream();

// Write the data to the request stream.

dataStream.Write(byteArray, 0, byteArray.Length);

// Close the Stream object.

dataStream.Close();

// Get the response.

//Get HttpWebResponse from GET request

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()))

{

string responseContent = reader.ReadToEnd();

jsonSerializer = new JavaScriptSerializer();

return (dataset)jsonSerializer.Deserialize(responseContent, typeof(dataset));

}

}

}

catch (Exception ex)

{

throw ex;

}

}

O token criado é então usado para as futuras chamadas à API.

Criação Dataset

O próximo passo será criar o dataset que irá compor o Dashboard. Os tipos que poderão ser usados para as colunas das tabelas são : int64, bool, DateTime, string e double. Para criação do dataset schema é necessário serializar o objeto em JSON e enviar para o PowerBI:

/// <summary>

/// Creates a dataset based on a DatasetSchema.

/// </summary>

/// <param name=”Schema”>Dataset Schema represents the definition of dataset including dataset name, tables and columns for each table.</param>

/// <returns>Created dataset as .NET object.</returns>

public static dataset GetDataset()

{

try

{

// DatasetName = DataSet

DataSet dataset = new DataSet() { name = ConfigurationManager.AppSettings[nsCom.Consts.DatasetName]};

dataset.tables =new Table[1];

dataset.tables[0] = new Table() { name = “IntGeneratorTable” };

dataset.tables[0].columns = new Column[2];

dataset.tables[0].columns[0] = new Column() { name = “DateTime”, dataType = “DateTime” };

dataset.tables[0].columns[1] = new Column() { name = “Int”, dataType = “Int64” }

// LIB used to serialize objects to JSON

JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();

var str = jsonSerializer.Serialize(dataset);

//Power BI Datasets Url

string powerBIApiUrl = “https://api.powerbi.com/v1.0/myorg/datasets“;

byte[] byteArray = Encoding.UTF8.GetBytes(str);

HttpWebRequest request = System.Net.WebRequest.Create(powerBIApiUrl) as System.Net.HttpWebRequest;

request.KeepAlive = true;

request.Method = “POST”;

request.ContentLength = byteArray.Length;

request.ContentType = “application/json”;

//Add access token to Request header

request.Headers.Add(“Authorization”, String.Format(“Bearer {0}”, nsToken.TokenSingleton.Instance.token.AccessToken));

// Get the request stream.

Stream dataStream = request.GetRequestStream();

// Write the data to the request stream.

dataStream.Write(byteArray, 0, byteArray.Length);

// Close the Stream object.

dataStream.Close();

// Get the response.

//Get HttpWebResponse from GET request

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()))

{

string responseContent = reader.ReadToEnd();

jsonSerializer = new JavaScriptSerializer();

return (dataset)jsonSerializer.Deserialize(responseContent, typeof(dataset));

}

}

}

catch (Exception ex)

{

throw ex;

}

}

Este método criou uma tabela com uma coluna de inteiros e uma de data que irá permitir o armazenamento de dados. No response do pedido HTTP é permitido obter o ID do dataset que nos irá permitir , mais tarde, aceder ao dataset (para as operações de edição / eliminação de dados).

Para além da criação de um dataset também nos é permitido eliminar e obter um dataset previamente criado.

Adicionar dados

Finalmente, com o dataset criado, é agora possivel adicionar dados. Foi criado um caso de teste, que envia os dados do CPU continuamente para o Power BI. Mais uma vez é criado um objecto em C#, e posteriormente é serializado um objecto JSON, e enviado no HTTP Request.

public static void SendData(dataset_dataset)

{

string powerBIApiUrl = String.Format(“https://api.powerbi.com/v1.0/myorg/datasets/{0}/tables/{1}/rows”, _dataset.Id, “IntGeneratorTable”);

while (1 == 1)

{

// Data Generated

PerformanceCounter cpuCounter = new PerformanceCounter();

cpuCounter.CategoryName = “Processor”;

cpuCounter.CounterName = “% Processor Time”;

cpuCounter.InstanceName = “_Total”;

// will always start at 0

dynamic firstValue = cpuCounter.NextValue();

System.Threading.Thread.Sleep(1000);

// now matches task manager reading

dynamic secondValue = cpuCounter.NextValue();

// My object

TableRows rows = new TableRows();

rows.rows = new ArrayList();

rows.rows.Add(new IntGeneratorTable() { DateTime = DateTime.Now, Int = Convert.ToInt32(secondValue) });

JavaScriptSerializer JavaScriptSerializer = new JavaScriptSerializer();

var json = JavaScriptSerializer.Serialize(rows).ToString();

byte[] byteArray = Encoding.UTF8.GetBytes(json);

HttpWebRequest request = System.Net.WebRequest.Create(powerBIApiUrl) as System.Net.HttpWebRequest;

request.KeepAlive = true;

request.Method = “POST”;

request.ContentLength = byteArray.Length;

request.ContentType = “application/json”;

request.Headers.Add(“Authorization”, String.Format(“Bearer {0}”, nsToken.TokenSingleton.Instance.token.AccessToken));

// Get the request stream.

Stream dataStream = request.GetRequestStream();

// Write the data to the request stream.

dataStream.Write(byteArray, 0, byteArray.Length);

// Close the Stream object.

dataStream.Close();

// Get the response.

//Get HttpWebResponse from GET request

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()))

{

string responseContent = reader.ReadToEnd();

}

}

}

}

Assim, se o envio de dados for bem sucedido é possivel verificar o dashboard, a ser atualizado automaticamente:

 

Fontes

 

.

.

.

.

      David Almas
Software Engineering