Azure Storage - krzysiek861/AvanadeWorkshop GitHub Wiki

Checkout branch

This step is obligatory!

git checkout feature/azure-storage

If you experience any issues with checking this branch out first stash all the changes you have from previous modules, checkout the branch and then apply the changes back.

Azure Table Storage Basics

Add Azure.Data.Tables NuGet to WebApp project.

Open Models/Table Storage Models folder in WebApp and add following classes:

 public class TeamEntity : ITableEntity
 {
    public TeamEntity()
    {

    }

    public TeamEntity(string partition, string id)
    {
        PartitionKey = partition;
        RowKey = id;
    }

    public string Group { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }
    public string Flag { get; set; }
    public int Games { get; set; }
    public int Points { get; set; }
    public string PartitionKey { get; set; }
    public string RowKey { get; set; }
    public DateTimeOffset? Timestamp { get; set; }
    public ETag ETag { get; set; }
}

public class PlayerEntity : ITableEntity
{
    public PlayerEntity()
    {

    }

    public PlayerEntity(string teamId, string id)
    {
        PartitionKey = teamId;
        RowKey = id;
    }

    public string TeamId { get { return PartitionKey; } }
    public int? Number { get; set; }
    public string Position { get; set; }
    public string FullName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public string Club { get; set; }
    public int Goals { get; set; }
    public string Thumbnail { get; set; }
    public string PartitionKey { get; set; }
    public string RowKey { get; set; }
    public DateTimeOffset? Timestamp { get; set; }
    public ETag ETag { get; set; }
}

Open DevController and modify MapPlayer and MapTeam methods replacing dynamic as a return value with PlayerEntity and TeamEntity

private PlayerEntity MapPlayer(Player player)
{
    return new PlayerEntity(player.TeamId, Guid.NewGuid().ToString())
    {
        Club = player.Club,
        DateOfBirth = player.DateOfBirth,
        Number = player.Number,
        Position = player.Position,
        FullName = player.FullName
    };
}

private TeamEntity MapTeam(Team team)
{
    return new TeamEntity(2022.ToString(), team.Name.Replace(" ", ""))
    {
        Flag = team.Flag,
        Name = team.Name,
        Group = team.Group.ToString()
    };
}

Open TeamsRepository, implement StoreTeams and StorePlayers methods:

public async Task StoreTeams(IEnumerable<TeamEntity> teams)
{
	var tableClient = GetServiceClient();
	var table = tableClient.GetTableClient("teams");
	await table.CreateIfNotExistsAsync();

	var transactionActions = new List<TableTransactionAction>();

	foreach (var team in teams)
	{
		transactionActions.Add(new TableTransactionAction(TableTransactionActionType.UpdateReplace, team));
	}

	await table.SubmitTransactionAsync(transactionActions);
}

public async Task StorePlayers(IEnumerable<PlayerEntity> players)
{
	var tableClient = GetServiceClient();
	var table = tableClient.GetTableClient("players");

	await table.CreateIfNotExistsAsync();            

	foreach (var group in players.GroupBy(p => p.PartitionKey))
	{
		var transactionActions = new List<TableTransactionAction>();
		foreach (var player in group)
		{
			transactionActions.Add(new TableTransactionAction(TableTransactionActionType.Add, player));
		}
		await table.SubmitTransactionAsync(transactionActions);
	}            
}

Deploy your Web app to Azure. Enter /Dev url and click Fill Azure Table Storage. Note: opening /Home controller at this stage will result in errors as some of the methods are not implemented yet.

Important! Do not click the link more than once otherwise it will result in duplicates.

Azure Storage Explorer

Download Azure Storage Explorer (link) and log in using your Azure account credentials.

Expan tables and browse the data. Try to find:

  • all the teams from group H
  • all the players with number 10
  • all the players under 20

Azure Table Storage Basics (2)

Make sure to restore all Nuget Packages

Open TeamsRepository.cs and implement two missing methods:

public IEnumerable<TeamEntity> FetchTeams()
{
	var tableClient = GetServiceClient();
	var table = tableClient.GetTableClient("teams");
	return table.Query<TeamEntity>().OrderBy(f => f.Group);
}

public IEnumerable<PlayerEntity> FetchPlayers(string teamId)
{
	var tableClient = GetServiceClient();
	var table = tableClient.GetTableClient("players");

	var result = table.Query<PlayerEntity>(p => p.PartitionKey == teamId).OrderBy(f => f.Number);
	return result;
}

Deploy your Web App.

Run the application and observe the data flow.

Azure Blob Storage

Open PlayersService.cs and analyze GetPlayerImages method. Try to implement all empty methods used there.

Open BinaryFilesRepository and add following method:

private BlobServiceClient GetBlobserviceClient()
{
	var serviceClient = new BlobServiceClient(GlobalSecrets.StorageAccountConnectionString);
	return serviceClient;
}

Implement SaveBlob method:

public string SaveBlob(string containerName, string fileName, byte[] bytes)
{
	var serviceClient = GetBlobserviceClient();
	var container = $"{containerName}-{fileName}".ToLower();
	var blobContainerClient = serviceClient.GetBlobContainerClient(container);
	blobContainerClient.CreateIfNotExists();
	blobContainerClient.SetAccessPolicy(Azure.Storage.Blobs.Models.PublicAccessType.Blob);
	var blobClient = blobContainerClient.GetBlobClient(Guid.NewGuid().ToString() + ".png");
	using (var stream = new MemoryStream(bytes, writable: false))
	{
		blobClient.Upload(stream);
		return blobClient.Uri.AbsoluteUri;
	}          
}

Try to run the application and open few player profiles. Open Storage Explorer. Locate your blobs. Click on Properties tab. Copy the URL and try to open it in the browser.

Implement missing repository methods:

public bool AnyFileExists(string containerName, string fileName)
{
	var serviceClient = GetBlobserviceClient();
	var container = $"{containerName}-{fileName}".ToLower();
	var blobContainerClient = serviceClient.GetBlobContainerClient(container);
	return blobContainerClient.Exists();
}

public List<string> GetBlobUrls(string containerName, string fileName)
{
	var serviceClient = GetBlobserviceClient();
	var container = $"{containerName}-{fileName}".ToLower();
	var blobContainerClient = serviceClient.GetBlobContainerClient(container);
	return blobContainerClient.GetBlobs()
		.Select(b => blobContainerClient.GetBlobClient(b.Name).Uri.ToString())
		.ToList();
}

Open Azure Portal and browse Storage account metrics.

⚠️ **GitHub.com Fallback** ⚠️