Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 22 additions & 30 deletions docs/fsharp/using-fsharp-on-azure/file-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,77 +26,69 @@ Next, use a [package manager](package-management.md) such as [Paket](https://fsp

Add the following `open` statements to the top of the `files.fsx` file:

[!code-fsharp[FileStorage](~/samples/snippets/fsharp/azure/file-storage.fsx#L1-L5)]
[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L1-L8)]

### Get your connection string

You'll need an Azure Storage connection string for this tutorial. For more information about connection strings, see [Configure Storage Connection Strings](/azure/storage/storage-configure-connection-string).

For the tutorial, you'll enter your connection string in your script, like this:

[!code-fsharp[FileStorage](~/samples/snippets/fsharp/azure/file-storage.fsx#L11-L11)]
[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L14-L14)]

However, this is **not recommended** for real projects. Your storage account key is similar to the root password for your storage account. Always be careful to protect your storage account key. Avoid distributing it to other users, hard-coding it, or saving it in a plain-text file that is accessible to others. You can regenerate your key using the Azure portal if you believe it may have been compromised.

For real applications, the best way to maintain your storage connection string is in a configuration file. To fetch the connection string from a configuration file, you can do this:

[!code-fsharp[FileStorage](~/samples/snippets/fsharp/azure/file-storage.fsx#L13-L15)]
[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L16-L18)]

Using Azure Configuration Manager is optional. You can also use an API such as the .NET Framework's `ConfigurationManager` type.

### Parse the connection string

To parse the connection string, use:

[!code-fsharp[FileStorage](~/samples/snippets/fsharp/azure/file-storage.fsx#L21-L22)]

This will return a `CloudStorageAccount`.

### Create the File service client

The `CloudFileClient` type enables you to programmatically use files stored in File storage. Here's one way to create the service client:
The `ShareClient` type enables you to programmatically use files stored in File storage. Here's one way to create the service client:

[!code-fsharp[FileStorage](~/samples/snippets/fsharp/azure/file-storage.fsx#L28-L28)]
[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L25-L25)]

Now you are ready to write code that reads data from and writes data to File storage.

## Create a file share

This example shows how to create a file share if it does not already exist:

[!code-fsharp[FileStorage](~/samples/snippets/fsharp/azure/file-storage.fsx#L34-L35)]
[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L31-L31)]

## Create a root directory and a subdirectory
## Create a directory

Here, you get the root directory and get a subdirectory of the root. You create both if they don't already exist.
Here, you get the directory. You create if it doesn't already exist.

[!code-fsharp[FileStorage](~/samples/snippets/fsharp/azure/file-storage.fsx#L41-L43)]
[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L37-L41)]

## Upload text as a file
## Upload a file to the sample directory

This example shows how to upload text as a file.
This example shows how to upload a file to the sample directory.

[!code-fsharp[FileStorage](~/samples/snippets/fsharp/azure/file-storage.fsx#L49-L50)]
[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L47-L52)]

### Download a file to a local copy of the file
### Download a file to a local file

Here you download the file just created, appending the contents to a local file.

[!code-fsharp[FileStorage](~/samples/snippets/fsharp/azure/file-storage.fsx#L56-L56)]
[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L58-L60)]

### Set the maximum size for a file share

The example below shows how to check the current usage for a share and how to set the quota for the share. `FetchAttributes` must be called to populate a share's `Properties`, and `SetProperties` to propagate local changes to Azure File Storage.
The example below shows how to check the current usage for a share and how to set the quota for the share.

[!code-fsharp[FileStorage](~/samples/snippets/fsharp/azure/file-storage.fsx#L62-L72)]
[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L66-L75)]

### Generate a shared access signature for a file or file share

You can generate a shared access signature (SAS) for a file share or for an individual file. You can also create a shared access policy on a file share to manage shared access signatures. Creating a shared access policy is recommended, as it provides a means of revoking the SAS if it should be compromised.
You can generate a shared access signature (SAS) for a file share or for an individual file. You can also create a shared access policy on a file share to manage shared access signatures. Creating a shared access permissions is recommended, as it provides a means of revoking the SAS if it should be compromised.

Here, you create a shared access policy on a share, and then use that policy to provide the constraints for a SAS on a file in the share.
Here, you create a shared access permissions on a share, and then set that permissions to provide the constraints for a SAS on a file in the share.

[!code-fsharp[FileStorage](~/samples/snippets/fsharp/azure/file-storage.fsx#L78-L94)]
[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L81-L101)]

For more information about creating and using shared access signatures, see [Using Shared Access Signatures (SAS)](/azure/storage/storage-dotnet-shared-access-signature-part-1) and [Create and use a SAS with Blob storage](/azure/storage/storage-dotnet-shared-access-signature-part-2).

Expand All @@ -108,13 +100,13 @@ You can copy a file to another file or to a blob, or a blob to a file. If you ar

Here, you copy a file to another file in the same share. Because this copy operation copies between files in the same storage account, you can use Shared Key authentication to perform the copy.

[!code-fsharp[FileStorage](~/samples/snippets/fsharp/azure/file-storage.fsx#L100-L101)]
[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L106-L108)]

### Copy a file to a blob

Here, you create a file and copy it to a blob within the same storage account. You create a SAS for the source file, which the service uses to authenticate access to the source file during the copy operation.

[!code-fsharp[FileStorage](~/samples/snippets/fsharp/azure/file-storage.fsx#L107-L120)]
[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L114-L131)]

You can copy a blob to a file in the same way. If the source object is a blob, then create a SAS to authenticate access to that blob during the copy operation.

Expand All @@ -124,7 +116,7 @@ Azure Storage Analytics supports metrics for File storage. With metrics data, yo

You can enable metrics for File storage from the [Azure portal](https://portal.azure.com), or you can do it from F# like this:

[!code-fsharp[FileStorage](~/samples/snippets/fsharp/azure/file-storage.fsx#L126-L140)]
[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L137-L155)]

## Next steps

Expand Down
151 changes: 83 additions & 68 deletions samples/snippets/fsharp/azure/file-storage.fsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
open System
open System.IO
open Microsoft.Azure // Namespace for CloudConfigurationManager
open Microsoft.Azure.Storage // Namespace for CloudStorageAccount
open Microsoft.Azure.Storage.File // Namespace for File storage types
open Azure
open Azure.Storage // Namespace for StorageSharedKeyCredential
open Azure.Storage.Blobs // Namespace for BlobContainerClient
open Azure.Storage.Sas // Namespace for ShareSasBuilder
open Azure.Storage.Files.Shares // Namespace for File storage types
open Azure.Storage.Files.Shares.Models // Namespace for ShareServiceProperties

//
// Get your connection string.
Expand All @@ -14,127 +17,139 @@ let storageConnString = "..." // fill this in from your storage account
let storageConnString =
CloudConfigurationManager.GetSetting("StorageConnectionString")
*)
//
// Parse the connection string.
//

// Parse the connection string and return a reference to the storage account.
let storageAccount = CloudStorageAccount.Parse(storageConnString)

//
// Create the File service client.
//

let fileClient = storageAccount.CreateCloudFileClient()
let share = ShareClient(storageConnString, "shareName")

//
// Create a file share.
//

let share = fileClient.GetShareReference("myfiles")
share.CreateIfNotExists()
share.CreateIfNotExistsAsync()

//
// Create a root directory and a subdirectory
// Create a directory
//

let rootDir = share.GetRootDirectoryReference()
let subDir = rootDir.GetDirectoryReference("myLogs")
subDir.CreateIfNotExists()
// Get a reference to the directory
let directory = share.GetDirectoryClient("directoryName")

// Create the directory if it doesn't already exist
directory.CreateIfNotExistsAsync()

//
// Upload a file to a subdirectory
// Upload a file to the sample directory
//

let file = subDir.GetFileReference("log.txt")
file.UploadText("This is the content of the log file")
let file = directory.GetFileClient("fileName")
let stream = File.OpenRead("localFilePath")
file.Create(stream.Length)
file.UploadRange(
HttpRange(0L, stream.Length),
stream)

//
// Download a file to a local fie
// Download a file to a local file
//

file.DownloadToFile("log.txt", FileMode.Append)
let download = file.Download()
let downStream = File.OpenWrite("Save_Download_Path")
download.Value.Content.CopyTo(stream)

//
// Set the maximum size for a file share.
//

// stats.Usage is current usage in GB
let stats = share.GetStats()
share.FetchAttributes()
let ONE_GIBIBYTE = 10_737_420_000L // Number of bytes in 1 gibibyte
let stats = share.GetStatistics().Value
let currentGiB = int (stats.ShareUsageInBytes / ONE_GIBIBYTE)

// Set the quota to 10 GB plus current usage
share.Properties.Quota <- stats.Usage + 10 |> Nullable
share.SetProperties()
share.SetQuotaAsync(currentGiB + 10)

// Remove the quota
share.Properties.Quota <- Nullable()
share.SetProperties()
share.SetQuotaAsync(0)

//
// Generate a shared access signature for a file or file share.
//

// Create a 24-hour read/write policy.
let policy =
SharedAccessFilePolicy
(SharedAccessExpiryTime = (DateTimeOffset.UtcNow.AddHours(24.) |> Nullable),
Permissions = (SharedAccessFilePermissions.Read ||| SharedAccessFilePermissions.Write))
let accountName = "..." // Input your storage account name
let accountKey = "..." // Input your storage account key

// Create a 24-hour read/write policy.
let expiration = DateTimeOffset.UtcNow.AddHours(24.)
let fileSAS = ShareSasBuilder(
ShareName = "shareName",
FilePath = "filePath",
Resource = "f",
ExpiresOn = expiration)

// Set the policy on the share.
let permissions = share.GetPermissions()
permissions.SharedAccessPolicies.Add("policyName", policy)
share.SetPermissions(permissions)
// Set the permissions for the SAS
let permissions = ShareFileSasPermissions.All
fileSAS.SetPermissions(permissions)

let sasToken = file.GetSharedAccessSignature(policy)
let sasUri = Uri(file.StorageUri.PrimaryUri.ToString() + sasToken)
// Create a SharedKeyCredential that we can use to sign the SAS token
let credential = StorageSharedKeyCredential(accountName, accountKey)

let fileSas = CloudFile(sasUri)
fileSas.UploadText("This write operation is authenticated via SAS")
// Build a SAS URI
let fileSasUri = UriBuilder($"https://{accountName}.file.core.windows.net/{fileSAS.ShareName}/{fileSAS.FilePath}")
fileSasUri.Query = fileSAS.ToSasQueryParameters(credential).ToString()

//
// Copy a file to another file.
//

let destFile = subDir.GetFileReference("log_copy.txt")
destFile.StartCopy(file)
let sourceFile = ShareFileClient(storageConnString, "shareName", "sourceFilePath")
let destFile = ShareFileClient(storageConnString, "shareName", "destFilePath")
destFile.StartCopyAsync(sourceFile.Uri)

//
// Copy a file to a blob.
//

// Get a reference to the blob to which the file will be copied.
let blobClient = storageAccount.CreateCloudBlobClient()
let container = blobClient.GetContainerReference("myContainer")
container.CreateIfNotExists()
let destBlob = container.GetBlockBlobReference("log_blob.txt")
// Create a new file SAS
let fileSASCopyToBlob = ShareSasBuilder(
ShareName = "shareName",
FilePath = "sourceFilePath",
Resource = "f",
ExpiresOn = DateTimeOffset.UtcNow.AddHours(24.))
let permissionsCopyToBlob = ShareFileSasPermissions.Read
fileSASCopyToBlob.SetPermissions(permissionsCopyToBlob)
let fileSasUriCopyToBlob = UriBuilder($"https://{accountName}.file.core.windows.net/{fileSASCopyToBlob.ShareName}/{fileSASCopyToBlob.FilePath}")

let filePolicy =
SharedAccessFilePolicy
(Permissions = SharedAccessFilePermissions.Read,
SharedAccessExpiryTime = (DateTimeOffset.UtcNow.AddHours(24.) |> Nullable))
// Get a reference to the file.
let sourceFileCopyToBlob = ShareFileClient(fileSasUriCopyToBlob.Uri)

let fileSas2 = file.GetSharedAccessSignature(filePolicy)
let sasUri2 = Uri(file.StorageUri.PrimaryUri.ToString() + fileSas2)
destBlob.StartCopy(sasUri2)
// Get a reference to the blob to which the file will be copied.
let containerCopyToBlob = BlobContainerClient(storageConnString, "containerName");
containerCopyToBlob.CreateIfNotExists()
let destBlob = containerCopyToBlob.GetBlobClient("blobName")
destBlob.StartCopyFromUriAsync(sourceFileCopyToBlob.Uri)

//
// Troubleshooting File storage using metrics.
//

open Microsoft.Azure.Storage.File.Protocol
open Microsoft.Azure.Storage.Shared.Protocol
// Instatiate a ShareServiceClient
let shareService = ShareServiceClient(storageConnString);

// Set metrics properties for File service
let props = ShareServiceProperties()

props.HourMetrics = ShareMetrics(
Enabled = true,
IncludeApis = true,
Version = "1.0",
RetentionPolicy = ShareRetentionPolicy(Enabled = true,Days = 14))

let props =
FileServiceProperties(
(HourMetrics = MetricsProperties(
MetricsLevel = MetricsLevel.ServiceAndApi,
RetentionDays = (14 |> Nullable),
Version = "1.0"),
MinuteMetrics = MetricsProperties(
MetricsLevel = MetricsLevel.ServiceAndApi,
RetentionDays = (7 |> Nullable),
Version = "1.0"))
props.MinuteMetrics = ShareMetrics(
Enabled = true,
IncludeApis = true,
Version = "1.0",
RetentionPolicy = ShareRetentionPolicy(Enabled = true,Days = 7))

fileClient.SetServiceProperties(props)
shareService.SetPropertiesAsync(props)