Yanayaya
Yanayaya

Reputation: 2184

Why cannot I not delete any blobs in my Azure Storage account from my ASP.NET Core Application?

My azure storage account is set to private, you can add files to the storage account from my ASP.NET Core web application. I've tried to allow the user the ability to delete blobs as well, however, no matter what configuration I use, I get the same error:

The specified blob does not exist.

Because my account is private, a SasToken is created lasting about 1 minute. For the sake of this question, let's assume that the location of the blob is something like:

https://mycompany.blob.core.windows.net/uploads (container)

Let's also assume that the blob I wish to delete is sitting within some subdirectories.

/car/1022/files/mazda.jpg (filename)

So, I constructed a string pointing to the blob I wanted to delete and passed that to DeleteBlob(string), I tried to do this in a number of ways and all of them had the error of Blob does not exist.

Here is my code for handling that in my controller.

CarController.cs

public string GenerateSasToken(string uri)
{
    BlobSasBuilder blobSasBuilder = new BlobSasBuilder()
    {
        BlobContainerName = "uploads",
        BlobName = uri,
        ExpiresOn = DateTime.UtcNow.AddMinutes(1),
    };
    blobSasBuilder.SetPermissions(BlobAccountSasPermissions.All);            
    var sasToken = blobSasBuilder.ToSasQueryParameters(new Azure.Storage.StorageSharedKeyCredential("MyAccountName", "MyAccessKey")).ToString();
    return (sasToken);
}

The above code creates a SasToken with a lifespan of 1 minute that has full permissions (for testing purposes). Here is the method that attempts to delete the file when it's called.

[HttpPost]
public IActionResult DeleteAzureFiles([DataSourceRequest] DataSourceRequest request, BlobListViewModel files)
{
    if (files != null)
    {
        try
        {
            string strContainerName = "uploads";                    
            BlobServiceClient blobServiceClient = new BlobServiceClient(accessKey);
            BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(strContainerName);

            //Filename is passed in from the model
            string fileName = files.FileUrl

            //Generate a token to use
            var getFileToken = GenerateSasToken(fileName);

            //Construct the URI including the newly made token
            string blob = fileName + "?" + getFileToken;

            //Attempt to delete the blob
            containerClient.DeleteBlob(blob);

            //Return the model to the grid
            return Json(files);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
    return Json(files);
}

Although not directly related to the question, I have included the code for my KendoUI grid that is sending this request for the sake of good order:

Index.cshtml

<kendo-grid name="blobsGrid" deferred="true">
    <datasource type="DataSourceTagHelperType.Ajax" page-size="50">
        <transport>
            <read url="/Car/ReadAzureFiles" data="GetCarId" />
            <destroy url="/Car/DeleteAzureFiles" data="GetCarId" />
        </transport>
        <schema data="Data" total="Total">
            <model id="Id">
                <fields>
                    <field type="int" name="Id" editable="false" />
                </fields>
            </model>
        </schema>
    </datasource>     
    <editable enabled="true" mode="inline" />
    <sortable enabled="true" />
    <pageable button-count="5" refresh="true" page-sizes="new int[] { 5, 10, 20 }"></pageable>
    <filterable enabled="true" />
    <columns>
        <column field="Id" title="Id" />
        <column field="FileName" title="Name" template="<a href='#=FileUrl#'>#=FileName#</a>" />
        <column field="FileUrl" title="URL" />
        <column field="FileToken" title="Token" />
        <column field="FileCreated" title="Created" format="{0:yyyy}" />
        <column field="FileUpdated" title="Updated" format="{0:yyyy}" />
        <column>
            <commands>
                <column-command text="Destroy" name="destroy"></column-command>
            </commands>
        </column>
    </columns>
</kendo-grid>

Setting breakpoints on the blob that I'm attempting to delete on the line with DeleteBlob(blob) shows that the string I've constructed is valid unless my use of DeleteBlob is totally incorrect. Any help would be appreciated.

Upvotes: 2

Views: 1730

Answers (1)

Gaurav Mantri
Gaurav Mantri

Reputation: 136196

I believe the problem is in the following line of code:

string blob = fileName + "?" + getFileToken;

Basically you're appending the SAS token to the name of the blob and then calling DeleteBlob method on your container client. Considering DeleteBlob method expects the name of the blob and because you changed the name of the blob by appending SAS token, you're getting a 404 error as a blob by the changed name (blob name + sas token) does not exist in the container.

Also, since you're creating your BlobServiceClient using a connection string (assuming your accessKey variable is in fact the connection string to your storage account), you don't really need a SAS token to delete the blob. You can simply delete the blob.

I believe using the code below should also work:

containerClient.DeleteBlob(fileName);

Another thing I noticed is that your blob name starts with / and that will create the problem. The name of the blob should be car/1022/files/mazda.jpg (without starting /).

Upvotes: 2

Related Questions