CRUD Operations with Azure Blob Storage in an Azure Function – Update & Deletion

In the preceeding parts of this series, we have delved into how to Create and Retrieve blobs using Azure Web Functions. In this part, we will look into how delete the blobs from Azure Blob Storage.

Wait a minute !! Did that we mean we skip Update ? Not really, we will have a word about it before we start with Deletion.

Update Blobs

The reason I thought Update Blobs doesn’t require its own blog post was it is quite different from what we learned for Creation (for starters, without delving too much into details). In fact, there is no difference at all.

Consider the Block Blobs – most likely, these are single files whose updation implies replacing them with a updated version. This could be an image file or an media file. This is no different from creating a new file.

You could overwrite an existing blob using the same code which learned in the previous post.

using (var stream = data.OpenReadStream())
{
    var blob = blobContainer.GetBlockBlobReference(key);
    await blob.UploadFromStreamAsync(stream);
}

With Append Blob, as the name suggests, the action is more of an “append to end of blob” scenario. This is whatthe Append blob is designed for. You could do exactly that using your learnings in the previous blog.

Deletion

Now that we have briefly spoken about the Updatation process, let us move ahead with the Deletion.

How do one delete a blob ? Well the answer is pretty simple, and is almost the same for Block and Append Blobs.

[FunctionName("DeleteFileBlockBlob")]
public static async Task<IActionResult> DeleteFileBlockBlob(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
    [Blob("todos")] CloudBlobContainer blobContainer,
    ILogger log
    )
{
    string key = req.Query["key"];

    var blob = blobContainer.GetBlockBlobReference(key);
    var result = await blob.DeleteIfExistsAsync();

    return new OkObjectResult($"Item Deletion {(result ? "Success" : "Failed")}");
}

As you notice in the code above, all it takes is to get a reference to the blob using the now familiar CloudBlobContainer.GetBlockBlobReference and use the CloudBlockBlob.DeleteIfExistsAsync to delete it.

With the Append Blob, obviously, one needs to get reference to the Append Blob, instead of Block Blob, but the code feels no different. Take a look at the example below.

[FunctionName("DeleteFileAppendBlob")]
public static async Task<IActionResult> DeleteFileAppendBlob(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
[Blob("sample")] CloudBlobContainer blobContainer,
ILogger log
)
{
    string key = req.Query["key"];

    var blob = blobContainer.GetAppendBlobReference(key);
    var result = await blob.DeleteIfExistsAsync();

    return new OkObjectResult($"Item Deletion {(result ? "Success" : "Failed")}");
}

That’s hardly any different.

So we have so far, looked into basics of CRUD operations into Azure Table Storage and Azure Blob Storage. We will continue our exploration of Azure Storage options and also take time to delve deeper in the configurations/security options in the upcoming blobs.

Until then, keep coding !!! As always, all code discussed here are available in my Github. For complete series on Azure Storage, refer here

Fody and “OnPropertyChanged” – The Unusual behavior

As a WPF Developer, Fody has been an extremely vital component in my aresenal. It takes a lot of burden off me by injecting some of the boiler plate codes. Despite that, there is one unusually behavior of Fody, which I have difficulty in digesting.

For demonstration, let us create an example View for ourselves. For the sake of example here, am relying on Caliburn Micro for my MVVM.

<StackPanel>
    <TextBlock Text="{Binding RandomNumber}" FontSize="16" HorizontalAlignment="Center"/>
    <Button Content="Randomize" x:Name="Randomize"/>
</StackPanel>

The ViewModel, at the moment, looks like the following.

public class ShellViewModel:Screen
{
    private Random _random;

    public ShellViewModel()
    {
        _random = new Random();
    }
    public long RandomNumber { get; set; }

    public void Randomize()
    {
        RandomNumber = _random.Next();
    }
}

This works perfectly fine. If you examine the code via ILSpy, you could notice that Fody has injected the code correctly as one would expect.

public class ShellViewModel : Screen
{
	private Random _random;

	public long RandomNumber
	{
		[CompilerGenerated]
		get
		{
			return <RandomNumber>k__BackingField;
		}
		[CompilerGenerated]
		set
		{
			if (<RandomNumber>k__BackingField != value)
			{
				<RandomNumber>k__BackingField = value;
				OnPropertyChanged(<>PropertyChangedEventArgs.RandomNumber);
			}
		}
	}


	public ShellViewModel()
	{
		_random = new Random();
	}

	public void Randomize()
	{
		RandomNumber = _random.Next();
	}
}

The OnPropertyChanged call here points to the PropertyChangedBase.OnPropertyChanged method of Caliburn Micro (PropertyChangedBase implements INotifyPropertyChanged in Caliburn Micro)

protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
	this.PropertyChanged?.Invoke(this, e);
}

Let us add some more code to our ViewModel and see how Fody behaves. Assume that we need to do some special handling when the Property Changed event is triggered in our ViewModel. So we will go ahead and subscribe in our constructor.

public ShellViewModel()
{
    _random = new Random();
    PropertyChanged += HandlePropertyChanged;
}

private void HandlePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
    // Do something here
}

Fody, quite expectedly, handles the change gracefully.

public class ShellViewModel : Screen
{
	private Random _random;

	public long RandomNumber
	{
		[CompilerGenerated]
		get
		{
			return <RandomNumber>k__BackingField;
		}
		[CompilerGenerated]
		set
		{
			if (<RandomNumber>k__BackingField != value)
			{
				<RandomNumber>k__BackingField = value;
				OnPropertyChanged(<>PropertyChangedEventArgs.RandomNumber);
			}
		}
	}

	public ShellViewModel()
	{
		_random = new Random();
		PropertyChanged += HandlePropertyChanged;
	}

	private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
	{
	}

	public void Randomize()
	{
		RandomNumber = _random.Next();
	}
}

So far, so good. This is exactly like one would expect. The injected code still calls the INotifyPropertyChanged implementation(in our base class).

set
{
    if (<RandomNumber>k__BackingField != value)
    {
        <RandomNumber>k__BackingField = value;
        OnPropertyChanged(<>PropertyChangedEventArgs.RandomNumber);
    }
}


But this is also where things start to behave strangely (one could counter argue this, but i still feel the following behavior is strange). Let us rename our PropertyChanged event handler as HandlePropertyChanged.

public ShellViewModel()
{
    _random = new Random();
    PropertyChanged += OnPropertyChanged;
}

private void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
    // Do something here
}

Let us examine the code generated by Fody now.

public long RandomNumber
{
    [CompilerGenerated]
    get
    {
        return <RandomNumber>k__BackingField;
    }
    [CompilerGenerated]
    set
    {
        if (<RandomNumber>k__BackingField != value)
        {
            <RandomNumber>k__BackingField = value;
            OnPropertyChanged(this, <>PropertyChangedEventArgs.RandomNumber);
        }
    }
}

public ShellViewModel()
{
    _random = new Random();
    PropertyChanged += OnPropertyChanged;
}

private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
}

The code injected by Fody has changed now and instead of calling the implementation of INotifyPropertyChanged, it is invoking the Event Handler of PropertyChanged.

set
{
    if (<RandomNumber>k__BackingField != value)
    {
        <RandomNumber>k__BackingField = value;
        OnPropertyChanged(this, <>PropertyChangedEventArgs.RandomNumber);
    }
}

In a way, if one was to think about it, it is a good behavior. Fody, on sensing that we have subscribing to PropertyChanged handler, ensure we are calling the handler instead. But, then the behavior should have been same when the Handler name was HandlePropertyChanged.

The strange part, which am not comfortable with this, is that this call to Handler occurs only when the Handler is named OnPropertyChanged. In every other case the injected code points to the implementation of INotifyPropertyChanged. I would like to call this a bug – You could expect the behavior to be consistent.

One of the troubles with this behavior (other than the obvious inconsistency) is that is extremely hard to trace this issue (remember – Fody injects the code) unless one is aware of this strange naming convention followed by Fody. I hope Fody does something to correct, if not make the make the behavior more consistent.

CRUD Operations with Azure Blob Storage in an Azure Function – Read

In the previous post, we examined how we could add an item to the Azure blob.

In this part, we will use an Azure function to download the file store in Azure Blob Storage.

Block Blob

Let us begin with Block Blobs.

[FunctionName("DownloadBlockBlob")]
public static async Task<IActionResult> DownloadBlockBlob(
    [HttpTrigger(AuthorizationLevel.Anonymous,"get",Route =null)] HttpRequest req,
    [Blob("todos")] CloudBlobContainer blobContainer,
    ILogger log)
{
    var key = req.Query["key"];

    var stream = new MemoryStream();
    var blob = await blobContainer.GetBlobReferenceFromServerAsync(key);
    await blob.DownloadToStreamAsync(stream);
    stream.Position = 0;
    return new FileStreamResult(stream, "application/octet-stream") { FileDownloadName = key };
}

This turns out to be pretty straightforward, isn’t it. The CloudBlobContainer.GetBlobReferenceFromServerAsync gets the reference to the blob we are interested in using the blob name, in this case, passed on as a query parameter. We could then use the CloudBlob.DownloadToStreamAsync method to download the contents of the blob to a stream, which could be later pass back using the FileStreamResult.

One obvious question would be why use a azure function in the above case, when there is no authentication. One could directly use a Http Get Request. Partially, that is true, however, do not forget this is only an example and most often than note, authentication would not be anonymous and there could be other things that you would like your azure function to during the download, like a log or updating/fetching another document.

Of course, you could simplify things using input bindings. For example, the above code could be rewritten using binding as the following.

[FunctionName("DownloadBlockBlobUsingBinding")]
public static async Task<IActionResult> DownloadBlockBlobUsingBinding(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "DownloadBlockBlobUsingBinding/{fileName}")] HttpRequest req,
[Blob("todos/{fileName}",FileAccess.Read)] Stream blob,
string fileName,
ILogger log)
{
    var memoryStream = new MemoryStream();
    await blob.CopyToAsync(memoryStream);
    memoryStream.Position = 0;
    return new FileStreamResult(memoryStream, "application/octet-stream") { FileDownloadName = fileName };
}

Append Blob

To download a file from an Append Blob is no different from what we have seen with Block Blob.

[FunctionName("DownloadAppendBlob")]
public static async Task<IActionResult> DownloadAppendBlob(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
[Blob("sample")] CloudBlobContainer blobContainer,
ILogger log)
{

    var key = req.Query["key"];

    var stream = new MemoryStream();
    var blob = blobContainer.GetAppendBlobReference(key);
    await blob.DownloadToStreamAsync(stream);
    stream.Position = 0;
    return new FileStreamResult(stream, "text/plain") { FileDownloadName = key };
}


The only point of importance while learning would be to remember that Append Blobs are not supported by the Storage emulator. For rest of the code look quite similar to the Block blob, sole difference being we use a different method to get reference to the blob – CloudContainer.GetAppendBlobReference.

As mentioned in the earlier post, we will address the Page blob separately. But for now, go ahead and play around with the Block Blob and Append Blob. You could access the source code explained in this code in my Github

CRUD Operations with Azure Blob Storage in an Azure Function – Create, Part 1

With Azure Blob storage, Microsoft provides an easy to use cloud based storage solution for storing massive amount of data, particularly unstructured data. These are ideal for storing media files which could be served directly to browser, maintaining log files among others.

There are three components of Blob storage one needs to be aware of.

  • Storage Account – The unique namespace for your azure data.
  • Container – Containers are similar to Directory in a file system, and is used to organize your blobs into sub sections.
  • Blobs – Reflects the data to be stored.

The blobs themselves are of 3 types.

  • Block Blobs : Ideal for storing image and other media files for streaming.
  • Append Blobs : Ideal for logging (append to end)
  • Page Blobs : Ideal for frequent read/write operations

That was a short introduction on the Blob Storages, let us now look at some code to create a new item in the blob storage.

We will stick to Azure Functions, and keep the code as simple as possible. As mentioned in the series opener, the more advanced topics including security would be discussed in a seperate posts.

Create Item in Block Blob

We will begin with the block blob first. In the very first example, we will add a text file to the blob, contents of which are passed via the request. I guess that would be the simplest way to begin the journey.

[FunctionName("AddItemBlockBlob")]
public static async Task<IActionResult> AddItemBlockBlob(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
    [Blob("todos")] CloudBlobContainer blobContainer,
    ILogger log)
{
    log.LogInformation("Request Recieved");

    await blobContainer.CreateIfNotExistsAsync();

    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
    var data = JsonConvert.DeserializeObject<TodoDto>(requestBody);

    data.Id = Guid.NewGuid().ToString();

    var serializedData = JsonConvert.SerializeObject(data);

    var blob = blobContainer.GetBlockBlobReference($"{data.Id}.json");
    await blob.UploadTextAsync(serializedData);
    return new OkObjectResult($"Item added to blob with Id = {data.Id}");
}

public class TodoDto
{
    public string Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public bool IsCompletd { get; set; }
}


CloudBlobContainer references the container in which our blob resides. If the container does not exists, we could create it using the CloudBlobContainer.CreateIfNotExistsAsync method.

Since we want to store our data in a Block Blob, we use CloudBlockBlob.GetBlockBlobReference method to get reference to the blob and use the CloudBlockBlob.UploadTextAsync method to upload the text data to the blob, referred by the blob name. In our first example, it is a Guid(followed by a string .json – but this is only for bringing more clarity to content of blob, you could choose a different name as well).

That was pretty clean, thanks to the rich set of APIs defined by Microsoft. There is however a behavior one needs to be aware of. If we were to upload text again to the same blob (refered by same blob name), the content would be replaced.

Upload a file to Block Blob

As the second example, let us attempt to upload an image file to the blob.

[FunctionName("UploadFileBlockBlob")]
public static async Task<IActionResult> UploadFileBlockBlob(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
    [Blob("todos")] CloudBlobContainer blobContainer,
    ILogger log
    )
{
    string key = req.Query["key"];
    var data = req.Form.Files["file"];
    using (var stream = data.OpenReadStream())
    {
        var blob = blobContainer.GetBlockBlobReference(key);
        await blob.UploadFromStreamAsync(stream);
    }
    return new OkObjectResult($"Item added to blob with Id = {key}");
}

In this example, we are retrieving the contents of the file from the HttpRequest and using the CloudBlockBlob.UploadFromStreamAsync method to upload the file to the blob.

Of course, Bindings are applicable here as well, and you could reduce fair bit of code with help of output binding.

[FunctionName("UploadFileBlockBlobBinding")]
public static async Task<IActionResult> UploadFileBlockBlobBinding(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "UploadFileBlockBlobBinding/{filename}")] HttpRequest req,
    [Blob("todos/{filename}",FileAccess.Write)] Stream fileStream,
    string filename,
    ILogger log)
{
    log.LogInformation("Request Recieved");
    var data = req.Form.Files["file"];
    var inputDataStream = data.OpenReadStream();
    await inputDataStream.CopyToAsync(fileStream);
    return new OkObjectResult($"Item added to blob with Id = {filename}");
}

The parameter fileStream would refer to the blob specified by the todos/{filename} where the filename is passed via the Http request.

The inputDatastream, read from the HttpRequest is being copied over to the fileStream using the CopyToAsync method, ensuring the blob has been updated with the stream of data from the request.

Create a Append Blob

Let us now attempt to create another type of blob – Append Blob. Unfortunately, the Azure Storage Emulator does not support the Append Blob, so do make sure you have your connections string in place before trying the following code.

[FunctionName("AddToAppendBlob")]
public static async Task<IActionResult> AddToAppendBlob(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
    [Blob("sample")] CloudBlobContainer blobContainer,
    ILogger log)
{
    log.LogInformation("Request Recieved");

    await blobContainer.CreateIfNotExistsAsync();
    var requestBody = await new StreamReader(req.Body).ReadToEndAsync();
    var data = JsonConvert.DeserializeObject<LogMessage>(requestBody);

    var blob = blobContainer.GetAppendBlobReference("applog.txt");
    if (!blob.Exists())
    {
        blob.CreateOrReplace();
    }
    await blob.AppendTextAsync($"User:{data.User}, Message:{data.Message}");

    return new OkObjectResult($"Item added to blob");
}

We retrieve a reference to the Append Blob using the CloudBlobContainer.GetAppendBlobReference method. We then use the CloudAppendBlob.AppendTextAsync to append the data to the end of the existing blob.

The Page Blobs has a bit more story to tell, which is why we will reserve it for another post. But as you have already seen, Microsoft’s rich API makes it easy to create blobs, as it was the case with Azure Table Storage.

View Model First Approach using Caliburn Micro

While it is possible to use both View Model First and View First approach while using Caliburn Micro, I personally feel one should stick to one single appraoch thoughout your application. Mixing the two approaches would impact the readability of code adversely.

View Model First Approach

In this post we will look at the ViewModel first approach, which is the default approach used by Caliburn Micro. Simply stated, it uses ViewModel to recognize the associated View.

Let us assume we have a ShellViewModel class, which contains an instance of UserProfileViewModel, defined as in example code below.

public class ShellViewModel:Conductor<object>
{
    public UserProfileViewModel UserProfile { get; set; }

    public ShellViewModel()
    {
        UserProfile = IoC.Get<UserProfileViewModel>();
        UserProfile.Name = "Anu Viswan";
        UserProfile.Age = 37;
    }
}

The Xaml part, particularly the View detection is quite simpler here, thanks to the Caliburn Micro’s conventions.

<ContentControl  x:Name="UserProfile"/>

The caliburn micro would detect the required View using the ViewLocator.LocateForModelType method. Following is how it looks like.

public static Func<Type, DependencyObject, object, UIElement> LocateForModelType = (modelType, displayLocation, context) =>{
    var viewTypeName = modelType.FullName.Replace("Model", string.Empty);
    if(context != null)
    {
        viewTypeName = viewTypeName.Remove(viewTypeName.Length - 4, 4);
        viewTypeName = viewTypeName + "." + context;
    }

    var viewType = (from assmebly in AssemblySource.Instance
                    from type in assmebly.GetExportedTypes()
                    where type.FullName == viewTypeName
                    select type).FirstOrDefault();

    return viewType == null
        ? new TextBlock { Text = string.Format("{0} not found.", viewTypeName) }
        : GetOrCreateViewType(viewType);
};

As you can observe, the method removes Model from the full name of the viewmodel to recognize the associate view. The parameter context brings us to an interesting scenario, which we will discuss a bit later. But for now, it becomes clear that how the naming conventions of Caliburn Micro works under the hood.

Custom naming conventions is easily possible with Caliburn Micro. But I guess that is another topic, which need’s a post of its own.

Binding to Collection of ViewModel

For now, let us look into another scenario. Let us assume, we have a collection of ViewModels which needs to be displayed in an ItemsControl.

public class ShellViewModel:Conductor<object>
{
    public IEnumerable<UserProfileViewModel> UserProfileCollection { get; set; }
    public ShellViewModel()
    {
        UserProfileCollection = Enumerable.Range(1, 10).Select(x => new UserProfileViewModel { Name = $"Sample Name {x}", Age = 37 + x });
    }
}

Binding the collection to ItemsControl and displaying each of the Items in a ContentControl would require a minor change. The usage of View.Model attached property, which is defined as

public static DependencyProperty ModelProperty =
            DependencyPropertyHelper.RegisterAttached(
                "Model",
                typeof(object),
                typeof(View),
                null,
                OnModelChanged
                );


public static void SetModel(DependencyObject d, object value) {
    d.SetValue(ModelProperty, value);
}

public static object GetModel(DependencyObject d) {
    return d.GetValue(ModelProperty);
}

static void OnModelChanged(DependencyObject targetLocation, DependencyPropertyChangedEventArgs args)
{
    if (args.OldValue == args.NewValue) {
        return;
    }

    if (args.NewValue != null) {
        var context = GetContext(targetLocation);

        var view = ViewLocator.LocateForModel(args.NewValue, targetLocation, context);
        ViewModelBinder.Bind(args.NewValue, view, context);
        if (!SetContentProperty(targetLocation, view)) {

            Log.Warn("SetContentProperty failed for ViewLocator.LocateForModel, falling back to LocateForModelType");

            view = ViewLocator.LocateForModelType(args.NewValue.GetType(), targetLocation, context);

            SetContentProperty(targetLocation, view);
        }
    }
    else {
        SetContentProperty(targetLocation, args.NewValue);
    }
}

As you can observe, the View.Model attached property, under the hood uses the ViewLocator.LocateForModel method itself, which we had previously seen.

We have now seen how View.Model is defined, so let us go ahead and write our xaml to finish off the example.

<ItemsControl x:Name="UserProfileCollection">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Border Grid.Row="1" BorderThickness="1" BorderBrush="LightGray">
                <ContentControl cal:View.Model="{Binding}"/>
            </Border>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

The Context Parameter – Multiple Views for single View Model

We had skipped the Context Parameter for the ViewLocator.LocateForModel method earlier. Let us now examine the role of the parameter in detail.

var viewTypeName = modelType.FullName.Replace("Model", string.Empty);
if(context != null)
{
    viewTypeName = viewTypeName.Remove(viewTypeName.Length - 4, 4);
    viewTypeName = viewTypeName + "." + context;
}

From the above code (from the ViewLocator.LocateForModel), it is obvious that if the context parameter is non-null value, then it would replace the View string with a . followed by the context string. With that in mind, let us build our alternative views using the following folder structure.

Let us now pass the context parameter in our example above using the attached property.

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Border Grid.Row="1" BorderThickness="1" BorderBrush="LightGray">
            <ContentControl cal:View.Model="{Binding}" cal:View.Context="StudentProfile"/>
        </Border>
    </DataTemplate>
</ItemsControl.ItemTemplate>

The UserProfileView would be now replaced with StudentProfile view which we have created in the previous step.

Conclusion 

In this post, we examined how to name resolution happens behind the scene for Caliburn Micro in a View Model First approach. We will examine View First approach in a later post, but if you understand the difference between the approach, and the working of one, it becomes easier to expect the other should behave.

CRUD Operations with Azure Table Storage in an Azure Function – D

In the previous part of this series we briefly described how to Create, Retreive and Update records in an Azure Table Storage using Azure Web Functions. In this part, we will look into final part of quadrant – the Delete operations.

As you would have guessed after going through previous posts in this series, we would be using the CloudTable for deletion of record.

[FunctionName("DeleteRecord")]
public static async Task<IActionResult> DeleteEntity(
    [HttpTrigger(AuthorizationLevel.Anonymous,"POST", Route = "DeleteRecord/{partitionKey}/{rowKey}")] HttpRequest request,
    [Table("todos", "{partitionKey}", "{rowKey}")] TodoTableEntity tableEntity,
    [Table("todos")] CloudTable todoTable,
    ILogger log)
{
    log.LogInformation("Request to delete the record");

    var deleteOperation = TableOperation.Delete(tableEntity);
    var result = await todoTable.ExecuteAsync(deleteOperation);
    return new OkObjectResult(result);
}

In this above example, we are using Bindings to retrieve the record to be deleted. The PartitionKey and RowKey is retrieved from the query string, quite similiar to the method we learned in the Retrieve record post.

A word of caution here. It is tempting to retrieve the record using RowKey alone, but one needs to be aware of the consequences. If one was to attempt retrival/deletion based on RowKey alone, the whole table has to be scanned for the record. Furthermore, it is theoratical to have the same RowKey over different patition (though this could be averted by application logic), which would retrieve multiple entites instead of one.

Deletion Table Binding

Of course, you could achieve the above without Table Binding.

[FunctionName("DeleteWithoutBinding")]
        public static async Task<IActionResult> DeleteWithoutBinding(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest request,
        [Table("todos")] CloudTable todoTable,
         ILogger log)
{
    log.LogInformation("Request to delete Record without binding");

    string partitionKey = request.Query["pkey"];
    string rowKey = request.Query["rkey"];

    var tableQuery = new TableQuery<TodoTableEntity>();

    var filterRowKeyAndPartitionKey = TableQuery.CombineFilters(
        TableQuery.GenerateFilterCondition(nameof(TodoTableEntity.RowKey), QueryComparisons.Equal, rowKey),
        TableOperators.And,
        TableQuery.GenerateFilterCondition(nameof(TodoTableEntity.PartitionKey), QueryComparisons.Equal, partitionKey));

    tableQuery.FilterString = TableQuery.CombineFilters(
        TableQuery.GenerateFilterCondition(nameof(TableEntity.PartitionKey), QueryComparisons.NotEqual, "Key"),
        TableOperators.And,
        filterRowKeyAndPartitionKey);

    var itemToDelete = todoTable.ExecuteQuery(tableQuery).First();

    var deleteOperation = TableOperation.Delete(itemToDelete);
    var deleteResponse = await todoTable.ExecuteAsync(deleteOperation);
    return new OkObjectResult(deleteResponse);
}

But honestly, I feel that is quite a lot of boilerplate code which could be avoided using bindings. I strongly suggest you use binding unless you have very strong reasons of doing otherwise.

Well, so far we have seen CRUD operations using the Azure Table Storage. In the next part of this series, we will explore another medium of storage provided by Azure. Until then, enjoy coding.

Computed Vs Methods Vs Watch

Computed Properties allows you to define auto calculated properties based on other properties. For example, you could have properties firstName and lastName, from which you could create a new property, fullName, which gets updated each time either firstName or lastName changes. For example,

 data() {
    return {
      firstName: "",
      lastName: "",
    };
  },
  computed: {
    FullName: function() {
      return this.firstName.concat(this.lastName);
    },
  }

The FullName property would be recomputed each time firstName or lastName changes. You could now use the FullName property just as if you it was a normal property.

<div>FirstName :{{ firstName }}</div>
<div>LastName :{{ lastName }}</div>
<div>FullName:{{ FullName }}</div>

Computed Property Vs Method

You would why a computed property and why not a method ? For example, you could achieve the above with following.

GetFullName() {
      return this.firstName + " " + this.lastName;
    },

This could be consumed from your code as following

<div>FirstName :{{ firstName }}</div>
<div>LastName :{{ lastName }}</div>
<div>FullName:{{ GetFullName() }}</div>

So what is the difference ? Well the difference lies in the fact that the Computed Properties are cached internally, which the methods are recalculated each time, even if the corresponding property doesn’t change.

For demonstration, let us add another property to our component, age.

export default {
  name: "Home",
  data() {
    return {
      firstName: "",
      lastName: "",
      age: 0,
    };
  },
}

The properties are bound to input boxes as the following.

<div class="row">
  <div class="col-12 border py-3 bg-light">
    Inputs :
    <input v-model="firstName" placeholder="First Name" class="mx-2" />
    <input v-model="lastName" placeholder="Last Name" class="mx-2" />
    <input v-model="age" placeholder="Age" class="mx-2" />
  </div>
</div>

We will also define couple of computed properties and methods which would consumed in our code else where.

  computed: {
    ComputedFullName: function() {
      console.log("Calling Computed Full Method");
      return this.firstName + " " + this.lastName;
    },
    ComputedAge: function() {
      console.log("Calling Computed Age Method");
      return this.age + "Yrs";
    },
  },
  methods: {
    GetFullName() {
      console.log("Calling FullName Method");
     return this.firstName + " " + this.lastName;
    },
    GetAge() {
      console.log("Call Age Method");
      return this.age + "Yrs";
    },
  },

As you could observe, we have declared two computed properties, namely, ComputedFullName and ComputedAge. We also have a corresponding pair of methods namely GetFullName and GetAge.

We will use these properties and methods to display the values as following based on the input elements defined earlier.

<div class="row g-2">
  <div class="col-4 border">
    <div><b>Computed</b></div>
    <div>FirstName :{{ firstName }}</div>
    <div>LastName :{{ lastName }}</div>
    <div>FullName:{{ ComputedFullName }}</div>
    <div>Age:{{ ComputedAge }}</div>
  </div>
  <div class="col-4 border">
    <div><b>Methods</b></div>
    <div>FirstName :{{ firstName }}</div>
    <div>LastName :{{ lastName }}</div>
    <div>FullName:{{ GetFullName() }}</div>
    <div>Age:{{ GetAge() }}</div>
  </div>
</div>

Let us now build and run our application and observe how it behaves.

Type a single character in the First Name input element and observe the console window.

Calling Computed Full Method
Calling FullName Method
Call Age Method

Since the firstName changes, the ComputedFullName property is called. So is the GetFullName method. These are pretty much desired and expected.

However, you could also observe that despite no changes to the age input element (and hence age property), the GetAge() method has been invoked. That is not the case with ComputedAge property. This is because, the Calculated property would be reevaulated only if the reactive dependency changes. If the reactive depencency does not change, the cached value is retrieved by the computed property, which reevaluting the property again.

On other hand, the method would be reevaluted each time it is invoked, irrespective of any changes to the dependend properties.

Computed Vs Watched Properties

If you want to your vue application to react to a change in a certain property, you have the option to use Watch properties.

But wait, does that sound similar to computed property. Yes and No – the watched properties observe a particular property in component and react (invokes a call back) to the change. This could be used to recalculate fields, which has same effect as the computed method. Since the watch is executed only when a property changes, it does share the issue of being reevaluated unnecessarly, as with methods.

For example, let us write the watch for age property.

  data() {
    return {
      firstName: "",
      lastName: "",
      age: 0,
      ageString: "",
    };
  },
    watch: {
    age: function(value) {
      console.log("Watch Age : " + value);
      this.ageString = value + "Yrs";
    },
  },

The application would react to any changes to age property. In our call back in the given example, we are recalculating a property named ageString for each change in age. You might wonder how is it different from computed property and when you would hesistate to use the watch property.

In fact, I should stop calling it watch property. Watch is a call back, a reaction to a change. This as such doesn’t expose any property. You need to do that yourself. Computed Property in contrast is a property by definition and reacts to changes to the reactive dependencies. In the cases, it might be a good idea to use computed property. The reason is obvious if you were to complete the example by providing a watch to calculate the full name.

data() {
    return {
      firstName: "",
      lastName: "",
      age: 0,
      fullName: "",
      ageString: "",
    };
  },
  watch: {
    firstName: function(value) {
      console.log("Watch FirstName : " + value);
      this.fullName = value + " " + this.lastName;
    },
    lastName: function(value) {
      console.log("Watch LastName : " + value);
      this.fullName = this.firstName + " " + value;
    },
    age: function(value) {
      console.log("Watch Age : " + value);
      this.ageString = value + "Yrs";
    },
  },

As you can observe, since a single watch would be observing a single property, you would need to define two watches to react to changes to both first name and last name. This would, as seen in the example above, result in duplicate code. This could be easily avoided by using `calculated properties.

As you would have observed, you could basically achieve the results with any of the above options. But the hidden implications are evident once your application grows and for the same reason, it is important to understand the subtle differences to ensure you use the right feature for your requirement.

Complete source code of the post could be accessed in my Github

Azure Storage with Azure Functions

In this series of Articles, we will explore various Azure Storage options using Azure Functions. We will stick to the basic usage, leaving out the more advanced topics involved with the storage to later blog posts.

CRUD using Azure Table Storage

CRUD using Azure Blob Storage

CRUD Operations with Azure Table Storage in an Azure Function – U

In the earlier posts, we enlightened ourselves with creation and retrieval of records from Azure Table Storage using Azure Web Functions. In this segment, we will attempt to update a record.

Let us once again look at our table before proceeding further.

In the first approach, we will attempt to update the record based on the RowKey and PartitionKey provided by the request. Let us go ahead and write our method now.

[FunctionName("Update")]
public static async Task<IActionResult> Update(
    [HttpTrigger(AuthorizationLevel.Anonymous,"post",Route = null)] HttpRequest request,
    [Table("todos")]CloudTable todoTable,
    ILogger log)
{
    log.LogInformation("Request to update Record");

    string requestBody = await new StreamReader(request.Body).ReadToEndAsync();
    var data = JsonConvert.DeserializeObject<TodoDto>(requestBody);

    var rowKeyToUpdate= request.Query[nameof(TableEntity.RowKey)];
    var partitionKeyToUpdate= request.Query[nameof(TableEntity.PartitionKey)];

    var tableEntity = new TodoTableEntity
    {
        RowKey = rowKeyToUpdate,
        PartitionKey = partitionKeyToUpdate,
        Title = data.Title,
        Description = data.Description,
        IsCompleted = data.IsCompletd,
        ETag = "*"
    };

    var updateOperation = TableOperation.Replace(tableEntity);
    var result = await todoTable.ExecuteAsync(updateOperation);
    return new OkObjectResult(result);
}

I will skip the Bindings here since we have learned about the same in the previous posts. We will first create an instance of record which will have the new value.

var tableEntity = new TodoTableEntity
{
    RowKey = rowKeyToUpdate,
    PartitionKey = partitionKeyToUpdate,
    Title = data.Title,
    Description = data.Description,
    IsCompleted = data.IsCompletd,
    ETag = "*"
};

Notice that we have used the PartitionKey and Rowkey retrieved from our query (we will address how to fetch it from database, if not given in query later). The other important point to notice here is the presence of the ETag. The Update Table Operation will not be allowed to process without the ETag.

As the next step, we will use the TableOperation to update or replace our record. This turns out to be pretty easy, thanks to the rich collection of methods introduced by Microsoft.

var updateOperation = TableOperation.Replace(tableEntity);
var result = await todoTable.ExecuteAsync(updateOperation);

Now you are ready to hit F5 and test your web function. For example, let us consider the following input.

// Request
http://localhost:7071/api/Update?PartitionKey=L&RowKey=1001

//Body
{
    title:'Learn Azure Func',
    description:'Learn Azure Func with Table Storage',
    isCompleted:'True'
}

We want to flip the IsCompleted Flag to True here. Final result would be.

We could, optimize the code a bit with help of the Bindings we have learned in the previous post. For example, the above code could be rewritten as,

[FunctionName("UpdateUsingBinding")]
public static async Task<IActionResult> UpdateUsingBinding(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "UpdateUsingBinding/{partitionKey}/{rowKey}")] HttpRequest request,
[Table("todos", "{partitionKey}", "{rowKey}")] TodoTableEntity tableEntity,
[Table("todos")] CloudTable todoTable,
    ILogger log)
{
    log.LogInformation("Request to update Record");

    string requestBody = await new StreamReader(request.Body).ReadToEndAsync();
    var data = JsonConvert.DeserializeObject<TodoDto>(requestBody);

    tableEntity.Title = data.Title;
    tableEntity.Description = data.Description;
    tableEntity.IsCompleted = data.IsCompletd;

    var updateOperation = TableOperation.Replace(tableEntity);
    var result = await todoTable.ExecuteAsync(updateOperation);
    return new OkObjectResult(result);
}

As you could notice, we have made using of the Table Bindings to retrieve the record here, which is then updated with new values passed on from the Http Request.

In the last approach for the post, we will address the case when PartitionKey and RowKey is not known to the HttpRequest and we need to fetch it using the Title. Well, as you might have guessed it, it would involve retrieval we learned in the previous posts.

[FunctionName("UpdateWithRetrival")]
public static async Task<IActionResult> UpdateWithRetrival(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest request,
[Table("todos")] CloudTable todoTable,
    ILogger log)
{
    log.LogInformation("Request to update Record");

    string requestBody = await new StreamReader(request.Body).ReadToEndAsync();
    var data = JsonConvert.DeserializeObject<TodoDto>(requestBody);

    var tableQuery = new TableQuery<TodoTableEntity>();

    tableQuery.FilterString = TableQuery.CombineFilters(
        TableQuery.GenerateFilterCondition(nameof(TableEntity.PartitionKey), QueryComparisons.NotEqual, "Key"),
        TableOperators.And,
        TableQuery.GenerateFilterCondition(nameof(TodoTableEntity.Title), QueryComparisons.Equal, data.Title));
    var result = todoTable.ExecuteQuery(tableQuery);

    var itemToUpdate = result.First();
    itemToUpdate.Description = data.Description;
    itemToUpdate.IsCompleted = data.IsCompletd;

    var updateOperation = TableOperation.Replace(itemToUpdate);
    var updateResponse = await todoTable.ExecuteAsync(updateOperation);
    return new OkObjectResult(updateResponse);
}

As you can observe, thanks to the rich API provided by Microsoft, the basic operations with Azure Storage are pretty straightforward. We will address Deletion in the next post, until then, have a great day.

CRUD Operations with Azure Table Storage in an Azure Function – R

In an earlier post, we discussed how to insert a new item in the Azure Storage Table. In this article, we will delve into how to retrieve data from Azure Storage Table.

Retrieve a Single Entity

In the previous article, we had partitioned the entities based on their first letter of their Title. Here is how our table looked at end our insert operations.

As mentioned before, we would use CloudTable to retrieve the entity we desire. For the sake of example, let us assume that the RowKey of the desired record would be passed via QueryString in the Http Request.

[FunctionName("TodoGetOne")]
public static async Task<IActionResult> GetOne(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
[Table("todos")] CloudTable todoTable,
ILogger log)
{
    string id = req.Query["id"];

    var tableQuery = new TableQuery<TodoTableEntity>();

    tableQuery.FilterString = TableQuery.CombineFilters(
        TableQuery.GenerateFilterCondition(nameof(TableEntity.PartitionKey), QueryComparisons.NotEqual, "Key"), 
        TableOperators.And, 
        TableQuery.GenerateFilterCondition(nameof(TableEntity.RowKey), QueryComparisons.Equal, id));

    var result = todoTable.ExecuteQuery(tableQuery);
    return new OkObjectResult(result);
}

As you can observe, we have used the TableQuery to filter our desired entity.

var tableQuery = new TableQuery<TodoTableEntity>();

tableQuery.FilterString = TableQuery.CombineFilters(
    TableQuery.GenerateFilterCondition(nameof(TableEntity.PartitionKey), QueryComparisons.NotEqual, "Key"), 
    TableOperators.And, 
    TableQuery.GenerateFilterCondition(nameof(TableEntity.RowKey), QueryComparisons.Equal, id));

The TableQuery.FilterString property enables us to provide Custom filters for the query. This is further facilitated by supporting utility methods in TableQuery, such as CombineFilters, and GeneratedFilterCondition. In our case, as seen in code above, we are filtering the data where the PartitionKey is not equal to text Key (remember, the partition key in our example is a special partition which keeps track of next Primary Id available ) and RowKey equavalent to the Id passed via querystring.

Further, we execute the query using the CloudTable.ExecuteQuery method.

var result = todoTable.ExecuteQuery(tableQuery);

That’s all you would need to fetch the data from Azure Table Storage.

Retrieve One Entity Using Binding

Table Binding also helps us retrieve a single record skipping a lot of boiler plate code, provided we know the parition key and the row key. For example, consider the following code.

[FunctionName("TodoGetOneBinding")]
public static async Task<IActionResult> TodoGetOneBinding1(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "TodoGetOneBinding/{partition}/{id}")] HttpRequest req,
[Table("todos", "{partition}", "{id}")] TodoTableEntity todo,
ILogger log)
{
    return new OkObjectResult(todo);
}

This effectively does the same as the code in our previous example, but provides a less cluttered code. The {parition} and {id} parameters from the Route is used as parameters for filter the table here.

Retrieve Multiple Entities

I guess there is very little to explain here once we have done the above examples. So let us write the code straightaway for retrieve all the todo items

[FunctionName("TodoGetAll")]
public static async Task<IActionResult> GetAll(
    [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
    [Table("todos")] CloudTable todoTable,
    ILogger log)
{
    var tableQuery = new TableQuery<TodoTableEntity>();
    tableQuery.SelectColumns = new List<string> { nameof(TodoTableEntity.Description) };
    tableQuery.FilterString = TableQuery.GenerateFilterCondition(nameof(TableEntity.PartitionKey), QueryComparisons.NotEqual, "Key");

    var result = todoTable.ExecuteQuery(tableQuery);
    return new OkObjectResult(result);
}

That’s all for now. We will continue our journey exploring the Azure Cloud Storage in upcoming articles.