Why CloudBlockBlob.Startcopyblob copies only 0bytes? - azure-blob-storage

Sometimes I have a case that,copying from one blob to input assets blob copies only 0bytes...
I am retrying after the first try and also delay it for 80sec, but nothing changes...
The file is video and its size is 340mb... If you guys need any information, I can reply it...
private async Task CreateInputAssetBlobAsync(UploadRequest request)
{
var cloudBlobContainer = new CloudBlobContainer(request.InputAssetStorageUri);
var blockBlob = cloudBlobContainer.GetBlockBlobReference(request.BlobName);
var storageCredentials = new Microsoft.Azure.Storage.Auth.StorageCredentials(_apiAccess.TempBlobAccountName, _apiAccess.TempBlobContainerKey);
var tempBlobContainer = new CloudBlobContainer(new Uri(_apiAccess.TempBlobContainerAddress), storageCredentials);
var tempBlockBlob = tempBlobContainer.GetBlockBlobReference(request.BlobName);
try
{
await blockBlob.StartCopyAsync(tempBlockBlob);
do
{
if (blockBlob.CopyState.Status == CopyStatus.Pending)
await Task.Delay(1000);
await blockBlob.FetchAttributesAsync();
}
while (blockBlob.CopyState.Status != CopyStatus.Success);
await blockBlob.FetchAttributesAsync();
if (blockBlob.Properties.Length <= 0)
{
Task.Delay(80000);
await blockBlob.StartCopyAsync(tempBlockBlob);
do
{
if (blockBlob.CopyState.Status == CopyStatus.Pending)
await Task.Delay(1000);
await blockBlob.FetchAttributesAsync();
}
while (blockBlob.CopyState.Status != CopyStatus.Success);
}
return;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}

You may want to take a look at the Remarks section of the Azure Blob API here
https://learn.microsoft.com/en-us/rest/api/storageservices/copy-blob
There are several remarks to be aware of with StartCopy blob.
“The Blob service copies blobs on a best-effort basis."
“For a block blob or an append blob, the Blob service creates a committed blob of zero length before returning from this operation."
“For all blob types, you can call Get Blob or Get Blob Properties on the destination blob to check the status of the copy operation. The final blob will be committed when the copy completes."
If the copies in your storage account are never completing, I would advise opening a support ticket with the details on the storage account, time and operation ids, etc.
Hope that is somewhat helpful.

Note: you should not use
do
{
if (blockBlob.CopyState.Status == CopyStatus.Pending)
await Task.Delay(1000);
await blockBlob.FetchAttributesAsync();
}
while (blockBlob.CopyState.Status != CopyStatus.Success);
but
do
{
await Task.Delay(1000);
await blockBlob.FetchAttributesAsync();
}
while (blockBlob.CopyState.Status == CopyStatus.Pending);
otherwise you will get an infinite loop if the copy has an error.
May be this is what happening in your case ?

In my code that works, I see that I retrieve a new CloudBlockBlob object once the copy is launched. Add the second line :
await tempBlockBlob.StartCopyAsync(blockBlob);
tempBlockBlob = (CloudBlockBlob)await tempBlobContainer.GetBlobReferenceFromServerAsync(request.BlobName);
and then do the fetchattribute and checks with tempBlockBlob. I got a 0 byte blob if I don't add the second line.

Related

What would cause a for / foreach loop to break without explicitly calling a break?

I have a durable function that calls a method that simply adds a row to an efcore object. It doesn't call db save.
When I step through the code, and get to the for loop, it will immediately jump to the line after the for loop. If I step into the call to add the efcore object, and back to the for loop, it continues and loops to the next item. If I press F5 to let it go without debugging, it immediately "breaks" the for loop.
It jumps out of the for loop where i wrote //HERE!!!!!!
I'm pulling my hair out on this one.
obligatory code:
//foreach (stagingFileMap stagingFileMap in fileMaps)
foreach (stagingFileMap stagingFileMap in fileMaps)
{
if (ActivitySyncHelper.IsSyncCancelled(aso, _configuration))
{
break;
}
if (!string.IsNullOrEmpty(stagingFileMap.URL))
{
// Ensure the url is valid
try
{
string x = await GetTotalBytes(stagingFileMap.URL);
double.TryParse(x, out double fileByteCount);
if (fileByteCount > 0)
{
// Create or update the video in vimeo
if (string.IsNullOrEmpty(stagingFileMap.VimeoId))
{
// Azure won't be ready with its backups, so use confex host for video 'get'
string title = stagingFileMap.FileName;
if (stagingFileMap.FileName.Length > 127)
{
title = stagingFileMap.FileName.Substring(0, 127);
}
Video video = vimeoClient.UploadPullLinkAsync(stagingFileMap.URL, title, stagingFileMap.id, meetingIdFolder.Uri).Result;
stagingFileMap.VimeoId = video.Id.ToString();
stagingFileMap.VimeoId = video.Id.ToString();
//HERE!!!!!!
await syncLog.WriteInfoMsg($"Vimeo create {stagingFileMap.FileName}");
//HERE!!!!!!
}
else
{
// Attempt to pull the existing video and update it
if (long.TryParse(stagingFileMap.VimeoId, out long videoId))
{
Video video = vimeoClient.GetVideoAsync(videoId).Result;
if (video.Id.HasValue)
{
Video res = await vimeoClient.UploadPullReplaceAsync(stagingFileMap.URL, video.Id.Value, fileByteCount);
await syncLog.WriteInfoMsg($"Vimeo replace {stagingFileMap.FileName} id {res.Id}");
}
}
}
break;
}
}
catch (Exception ex)
{
// IDK what to do besides skip it and continue
// log something once logging works
await syncLog.WriteErrorMsg(aso, ex.Message);
await syncLog.Save();
continue;
}
// We need to save here requently because if there is big error, all the work syncing to vimeo will be desync with the DB
dbContext.Update(stagingFileMap);
await dbContext.SaveChangesAsync();
await syncLog.Save();
}
}
await dbContext.DisposeAsync();
public async Task WriteInfoMsg( string msg)
{
SyncAttemptDetail sad = new()
{
SyncAttemptId = _id,
Message = msg,
MsgLevel = SyncAttemptMessageLevel.Info,
AddDate = DateTime.UtcNow,
AddUser = "SYSTEM"
};
await _dbContext.SyncAttemptDetail.AddAsync(sad);
}
I'm dumb. Theres LITERALLY a break command in there.
The await will create a task and immediately return it (the debugger will follow this path too). The loop will continue in the task.
To attach the debugger to the task, add a break point after the await.

Xamarin - ask again for device location

I am using Xamarin.Essentials. When I try to get the last known location, the message about device location permission is shown.
If I deny the permission the PermissionException is caught.
How I can check for location and fired again the location permission message?
try
{
var location = await Geolocation.GetLastKnownLocationAsync();
if (location != null)
{
await this.Navigation.PushModalAsync(Nav_to_MAP);
}
}
catch (PermissionException pEx)
{
// if deny location
}
This issue was opened last year, this is the response from James Montemagno:
Right now it will request the permission for you based on how the system handles it. On iOS a permission can only be requested once and on Android, it can be multiple times. If the user declines you will get a permission denied exception.
You can use the Permission Plugin today to handle checking and requesting
https://github.com/jamesmontemagno/PermissionsPlugin
I will open a new proposal for permissions as they are a tad bit tricky.
So, You could use the Permissions Plugin for Xamarin to check for the permission before asking. like so:
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Location);
if (status != PermissionStatus.Granted)
{
if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Location))
{
await DisplayAlert("Need location", "Gunna need that location", "OK");
}
var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Location);
//Best practice to always check that the key exists
if (results.ContainsKey(Permission.Location))
status = results[Permission.Location];
}
if (status == PermissionStatus.Granted)
{
try
{
var location = await Geolocation.GetLastKnownLocationAsync();
if (location != null)
{
await Navigation.PushModalAsync(Nav_to_MAP);
}
}
catch (PermissionException pEx)
{
// if deny location
}
}
See the Docs on how to set it up

Plugin.Geolocator exits method (deadlock?)

I'm building a Xamarin app and for the geolocation, I'm using the GeolocatorPlugin
The problem is that once the code wants to get the position, the code exists without warning.
My class fields:
private Position position;
private IGeolocator locator = CrossGeolocator.Current;
My page constructor:
public MainPage()
{
InitializeComponent();
locator.PositionChanged += Locator_PositionChanged;
locator.PositionError += Locator_PositionError;
}
OnAppearing event is calling the getLocationPermission:
private async Task GetLocationPermission()
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.LocationWhenInUse);
if (status != PermissionStatus.Granted)
{
//Not granted, request permission
if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.LocationWhenInUse))
{
// This is not the actual permission request
await DisplayAlert("Need your permission", "We need to access your location", "Ok");
}
// This is the actual permission request
var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.LocationWhenInUse);
if (results.ContainsKey(Permission.LocationWhenInUse))
status = results[Permission.LocationWhenInUse];
}
//Already granted, go on
if (status == PermissionStatus.Granted)
{
//Granted, get the location
GetLocation();
await GetVenues();
await locator.StartListeningAsync(TimeSpan.FromMinutes(30), 500);
}
else
{
await DisplayAlert("Access to location denied", "We don't have access to your location.", "OK");
}
}
The permission is granted and gets to the GetLocation() method:
private async void GetLocation()
{
//var locator = CrossGeolocator.Current;
try
{
var myPosition = await locator.GetPositionAsync();
position = new Position(myPosition.Latitude, myPosition.Longitude);
}
catch (Exception ex)
{
throw;
}
if (position == null)
{
//Handle exception
}
}
Once the line is reached with locator.GetPositionAsync(), it stops. No exception is thrown, also the PositionError isn't raised.
I have no idea why, but in the beginning it worked once, never worked after that.
The location settings in de Android Emulator are as follow:
Based on my research, you did not acheved that Location Changes like this link
I wrote a demo about Location changes. This is running screenshot.
This is my demo
https://github.com/851265601/GeolocationDemo

Await call to web service is stopping the execution flow of the program

I have the following code:
public async Task IntiateDataFetchingProcess(string[] args)
{
try
{
ProcessArgs(args);
Log.Information("Run Mode: {RunModeID}", RunModeID);
switch (RunModeID)
{
case RunModeType.A:
await MethodAAsync();
break;
case RunModeType.B:
await MethodBAsync();
break;
case RunModeType.C:
TestMethod();
break;
default:
break;
}
}
catch (Exception ex)
{
throw;
}
}
private async Task MethodBAsync()
{
Console.WriteLine(DateTime.Now.ToLongTimeString());
// Call to webservice to get the data
var response = await _service.GetDataAsync(input1, request);
Console.WriteLine(DateTime.Now.ToLongTimeString());
}
On debugging I found that the execution call comes to the below line (of method: MethodBAsync) and stops there.
var response = await _service.GetDataAsync(input1, request);
Can anyone help me to know is there anything that I am missing here.
Ah, your code is getting deadlocked!
You just need to add .ConfigureAwait(false); to each line that you are awaiting.
Example:
var response = await _service.GetDataAsync(input1, request);
becomes
var response = await _service.GetDataAsync(input1,
request).ConfigureAwait(false);
For more information on .ConfigureAwait(), Stephen Cleary wrote an awesome post on it.

reviving image through sockets [Windows Store Apps - C# ]

I'm receiving an image on a Metro app through network socket every 1 second, loading it in an array of bytes, then convert it to a BitmapImage and display it later. All of this work fine.
The image is changing constantly on the other side. For some reason, it throws an OutOfMemory exceptions from now and then(like 1 in 10) . I fixed it by clearing the array of bytes every time the image is received. Now it works like charm.
See below for my main issue:
public static BitmapImage imag;
public static byte[] save = new byte[1];
if(recieved)
{
await reader.LoadAsync(4);
var sz = reader.ReadUInt32(); //read size
await reader.LoadAsync(sz); //read content
save = new byte[sz];
reader.ReadBytes(save);
await ImgSrcFromBytes(save)
Array.Clear(save, 0, save.Length); //issue here !!
}
public async Task<ImageSource> ImgSrcFromBytes(byte[] a)
{
imag = new BitmapImage();
var stream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
await stream.WriteAsync(a.AsBuffer());
stream.Seek(0);
imag.SetSource(stream);
return imag;
}
Now, i'm implementing a new function to save the image as a file if requested by the user with the code below, however, if i clear the array of bytes above, i get an unreadable image, but if i don't clear the array, i get a perfect image.
Note that no exceptions are thrown and both images have the same size.
FileSavePicker picker = new FileSavePicker();
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
picker.SuggestedFileName = "capture.png";
picker.FileTypeChoices.Add("Png File", new List<string>() { ".png" });
StorageFile file = await picker.PickSaveFileAsync();
if (file != null)
{
CachedFileManager.DeferUpdates(file);
await FileIO.WriteBytesAsync(file, save);
await CachedFileManager.CompleteUpdatesAsync(file);
await new Windows.UI.Popups.MessageDialog("Image Saved Successfully !").ShowAsync();
}
I hope i'm clear. It's a trade-off, if i clear the array, i will get no exceptions while receiving streams over sockets, but i won't be able to get a readable image when saving. and vice versa.

Resources