Upload to Azure Blob from Xamarin.Forms PCL - xamarin

I'm trying to upload an image's stream to Azure Blob from a Xamarin.Forms PCL app using WindowsAzure.Storage 7.0.2-preview. For some reason, the StorageCredentials doesn't recognize the AccountName of the SAS token.
var credentials = new StorageCredentials("https://<ACCOUNT-NAME>.blob.core.windows.net/...");
CloudStorageAccount Account = new CloudStorageAccount(credentials, true);
And then uploading it like this:
public async Task<string> WriteFile(string containerName, string fileName, System.IO.Stream stream, string contentType = "")
{
var container = GetBlobClient().GetContainerReference(containerName);
var fileBase = container.GetBlockBlobReference(fileName);
await fileBase.UploadFromStreamAsync(stream);
if (!string.IsNullOrEmpty(contentType))
{
fileBase.Properties.ContentType = contentType;
await fileBase.SetPropertiesAsync();
}
return fileBase.Uri.ToString();
}
How can I resolve my problem? Is there a better solution of uploading to Azure Storage?
Thank you!

The StorageCredentials constructor that takes in a SAS token expects just the query part of the SAS token, not the full URI string. If you have the full URI to a resource, including the SAS token, the most common thing to do is to use the constructor for that object directly. For example, if you have the URI:
string myBlobUri = #"https://myaccount.blob.core.windows.net/sascontainer/sasblob.txt?sv=2015-04-05&st=2015-04-29T22%3A18%3A26Z&se=2015-04-30T02%3A23%3A26Z&sr=b&sp=rw&sip=168.1.5.60-168.1.5.70&spr=https&sig=Z%2FRHIX5Xcg0Mq2rqI3OlWTjEg2tYkboXr1P9ZUXDtkk%3D";
you can just create a blob object as such:
CloudBlockBlob fileBase = new CloudBlockBlob(new Uri(myBlobUri));
If you do want to use the StorageCredentials and CloudStorageAccount classes for some reason (maybe you have an AccountSAS, for example), here is one way to make that work:
string sasToken = #"sv=2015-04-05&st=2015-04-29T22%3A18%3A26Z&se=2015-04-30T02%3A23%3A26Z&sr=b&sp=rw&sip=168.1.5.60-168.1.5.70&spr=https&sig=Z%2FRHIX5Xcg0Mq2rqI3OlWTjEg2tYkboXr1P9ZUXDtkk%3D";
StorageCredentials credentials = new StorageCredentials(sasToken);
CloudStorageAccount account = new CloudStorageAccount(credentials, "myaccount", "core.windows.net", true)

Related

Get Azure Batch ResourceFile from existing file in Azure Blob Container

I am following this tutorial to do my first steps with Azure Batch
https://github.com/Azure-Samples/batch-dotnet-ffmpeg-tutorial/blob/master/BatchDotnetTutorialFfmpeg/Program.cs
There is one method to upload files to a container and to get back a ResourceFile for further processing.
private static ResourceFile UploadFileToContainer(CloudBlobClient blobClient, string containerName, string filePath)
{
Console.WriteLine("Uploading file {0} to container [{1}]...", filePath, containerName);
string blobName = Path.GetFileName(filePath);
filePath = Path.Combine(Environment.CurrentDirectory, filePath);
CloudBlobContainer container = blobClient.GetContainerReference(containerName);
CloudBlockBlob blobData = container.GetBlockBlobReference(blobName);
blobData.UploadFromFileAsync(filePath).Wait();
// Set the expiry time and permissions for the blob shared access signature.
// In this case, no start time is specified, so the shared access signature
// becomes valid immediately
SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy
{
SharedAccessExpiryTime = DateTime.UtcNow.AddHours(2),
Permissions = SharedAccessBlobPermissions.Read
};
// Construct the SAS URL for blob
string sasBlobToken = blobData.GetSharedAccessSignature(sasConstraints);
string blobSasUri = String.Format("{0}{1}", blobData.Uri, sasBlobToken);
return ResourceFile.FromUrl(blobSasUri, filePath);
}
This works fine as long as you want to upload your files again and again. For some reason my upload broke down and I did not get the ResourceFile Object.
So how can I get a ResourceFile Object from an already uploaded file to an existing container?
Regards
Michael

Getting an error while retrieving a blob using user assigned managed identity

We have a C# code which used to retrieve a blob from storage account. The authentication is done using user assigned service principal. These things works till December. But now we are getting some weird error as follows.
ManagedIdentityCredential authentication unavailable. The requested identity has not been assigned to this resource.
Status: 400 (Bad Request)
Content:
{"error":"invalid_request","error_description":"Identity not found"}
The managed identity has storage data blob contributor access in the storage account.
Attaching the code for reference:
public static async Task<string> GetBlobAsync()
{
string storageName = "storage account name";
Uri blobUri = new Uri("blob uri");
TokenCredential cred = new ManagedIdentityCredential("client id");
var blobClient = new BlobClient(blobUri, cred, null);
try
{
var downloadInfo = await blobClient.DownloadAsync();
using (TextReader reader = new StreamReader(downloadInfo.Value.Content))
{
string metadataBlob = await reader.ReadToEndAsync();
return metadataBlob;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine("");
return null;
}
P:S: the three environmental variables such as app id, app secret and tenant id are correct.
I have been stuck here for almost a month. Nothing works.
This document demonstrates how to use managed identity to access App Configuration from App Service, but you can replace the App Service with any other Azure services that support managed identity. https://learn.microsoft.com/en-us/azure/azure-app-configuration/howto-integrate-azure-managed-service-identity
Here are a few things I'd like to call out
Make sure the managed identity is enabled in the Azure service where your application runs.
When you are using system assigned managed identity, you don't need to provide the client Id. You only need to provide the client Id when you use user assigned managed identity.
Make sure the managed identity is granted either App Configuration Data Reader or App Configuration Data Owner role in the access control of your App Configuration instance.
Wait for at least 15 minutes after the role assignment for the permission to propagate.
Managed identity can ONLY work when your code is running in the Azure service. It will NOT work when running locally
Try this
Uri blobUri = new Uri("blob uri");
var cred = new DefaultAzureCredential(
new DefaultAzureCredentialOptions {
ManagedIdentityClientId = "your client id" });
var blobClient = new BlobClient(blobUri, cred, null);
ref: https://learn.microsoft.com/pt-br/dotnet/api/azure.identity.defaultazurecredential?view=azure-dotnet
Option 2 (work for me)
Create Identity and add in app service
Assign RBAC "Storage Blob Data Contributor" to your storage resource.
Add Key AZURE_CLIENT_ID (clientid of the identity that was created) in Environment App Service
Code to access blob
(you don't need to specify client id in the code because it will use the AZURE_CLIENT_ID configured in the AppService)
app.MapGet("/read", async () =>
{
Uri blobUri = new Uri("https://xxxx.blob.core.windows.net/texts/text.txt");
var cred = new DefaultAzureCredential();
var blobClient = new BlobClient(blobUri, cred, null);
var downloadInfo = await blobClient.DownloadAsync();
using (TextReader reader = new StreamReader(downloadInfo.Value.Content))
{
string metadataBlob = await reader.ReadToEndAsync();
return metadataBlob;
}
});
Result print

Xamarin Uploading sqllite file to Azure Blob storage, sqlite .db3 file is empty on Blob storage

I'm trying to upload the local database of the app build in Xamarin forms iOS. There is data in the local database and the app can see all the table and data just fine.
I want to investigate the database, so I upload it to an Azure Blob storage.
The code look like this:
public class BlobStorageService
{
readonly static CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(Constants.blogStorageConnectionString);
readonly static CloudBlobClient blobClient = cloudStorageAccount.CreateCloudBlobClient();
public static async Task UploadFileToBlobStorage(string filePath)
{
if (!File.Exists(filePath))
return;
var fileName = Path.GetFileName(filePath);
CloudBlobContainer container = blobClient.GetContainerReference("sqllitefiles");
await container.CreateIfNotExistsAsync();
BlobContainerPermissions permissions = await container.GetPermissionsAsync();
permissions.PublicAccess = BlobContainerPublicAccessType.Container; //TODO: disable this later.
await container.SetPermissionsAsync(permissions);
CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName);
await blockBlob.UploadFromFileAsync(filePath);
}
}
And the filePath is :
public static readonly string DatabasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CaseNotesSQLite.db3");
Database file is uploaded successfully, however, the file is only 4KB and when I open the database file using SQLLite Browser, there is no data and no table structure at all.
Anyone know why ?

How to let user click to open the CSV file in browser C# BotFramework SDK3

As the title, I want to let user click to open a file in browser which is created by Bot. I'm using webChat.
The code is what I have tried.
In botframework-emulator, if I click the link, the CSV file will open in the browser.
But in the webChat, it will request user to download, not open in the browser.
var aaa = await GetCSVAttachmentAsync(replymes.ServiceUrl, replymes.Conversation.Id);
foreach(var aa in aaa)
replymes.Attachments.Add(aa);
await context.PostAsync(replymes);
private async Task<IList<Attachment>> GetCSVAttachmentAsync(string serviceUrl, string conversationId)
{
string str = "this is a text CSV";
byte[] array = Encoding.GetEncoding("shift_jis").GetBytes(str);
using (var connector = new ConnectorClient(new Uri(serviceUrl)))
{
var attachments = new Attachments(connector);
var response = await attachments.Client.Conversations.UploadAttachmentAsync(
conversationId,
new AttachmentData
{
Name = "userinfo.csv",
OriginalBase64 = array,
Type = "text/csv"
});
message.Add(new Attachment
{
Name = "userinfo.html",
ContentType = "text/html",
ContentUrl = response.Id
});
return message;
}
}
To solve this problem, I also tried storageV2. But it seems the URI can't be accessed directly.
I still couldn't figure it out without creating a real file.
But instead of using storage V2, I can solve the problem. The thought is as below.
Let the bot create a file.
Upload it to Storage V2 using static website
Send the static website to user.

primary and secondary location URI ina storageURI must point to the same resource windows azure

I am just try to connect my Blob Storage with .net SDK with MVC application and here is my code;
public static CloudBlobClient CreateClient(UnitOfWork uow)
{
CloudStorageList credentials;
CloudBlobClient client;
credentials = uow.RepositoryFor<CloudStorageList>().GetAll(filter: xx => !xx.IsDeleted).FirstOrDefault();
var storageCredentials = new StorageCredentials(credentials.Name, credentials.PrimaryAccessKey);
var storage =
new CloudStorageAccount(storageCredentials,true);
client = storage.CreateCloudBlobClient();
return client;
}
But I am facing the error when I reached the line;
var storage =
new CloudStorageAccount(storageCredentials,true);
I have just mention the error in the subject i.e. primary and secondear location URI in a storageUI must point to the same resource.
Any help will be a favor.
Regards,
var storageCredential = new StorageCredentials(*, **);
is the account name : this is the name of your storagename
** is the keyValue : vieuw in the image

Resources