From 0ee0269384e7889beebba692e0ecedbf384e35ff Mon Sep 17 00:00:00 2001 From: Sylvan Clebsch Date: Wed, 21 Sep 2016 15:38:57 +0100 Subject: [PATCH 01/60] F# Blob Storage documentation This is part of an effort to document using F# for Azure. --- .../using-fsharp-on-azure/blob-storage.md | 371 ++++++++++++++++++ .../package-management.md | 86 ++++ 2 files changed, 457 insertions(+) create mode 100644 docs/fsharp/using-fsharp-on-azure/blob-storage.md create mode 100644 docs/fsharp/using-fsharp-on-azure/package-management.md diff --git a/docs/fsharp/using-fsharp-on-azure/blob-storage.md b/docs/fsharp/using-fsharp-on-azure/blob-storage.md new file mode 100644 index 0000000000000..e891a839a1675 --- /dev/null +++ b/docs/fsharp/using-fsharp-on-azure/blob-storage.md @@ -0,0 +1,371 @@ +--- +title: Get started with Azure Blob storage using F# +description: Store unstructured data in the cloud with Azure Blob storage. +keywords: visual f#, f#, functional programming, .NET, .NET Core, Azure +author: syclebsc +manager: jbronsk +ms.date: 09/20/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: c5b74a4f-dcd1-4849-930c-904b6c8a04e1 +--- + +# Get started with Azure Blob storage using F# + +Azure Blob storage is a service that stores unstructured data in the cloud as objects/blobs. Blob storage can store any type of text or binary data, such as a document, media file, or application installer. Blob storage is also referred to as object storage. + +### About this tutorial + +This article shows you how to perform common tasks using Blob storage. The samples are written using F# using the Azure Storage Client Library for .NET. The tasks covered include how to upload, list, download, and delete blobs. + +### Conceptual overview + +For a conceptual overview of blob storage, please see [the .NET guide for blob storage](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-blobs/) + +### Create an Azure storage account + +To use this guide, you must first [create an Azure storage account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/). +You'll also need your storage access key for this account. + +## Create an F# Script and Start F# Interactive + +The samples in this article can be used in either an F# application or an F# script. To create an F# script, create a file with the `.fsx` extension, for example `blobs.fsx`, in your F# development environment. + +Next, use a [package manager](package-management.md) such as Paket or NuGet to install the `WindowsAzure.Storage` package and reference `WindowsAzure.Storage.dll` in your script using a `#r` directive. + +### Add namespace declarations + +Add the following `open` statements to the top of the `blobs.fsx` file: + + open System + open System.IO + open Microsoft.Azure // Namespace for CloudConfigurationManager + open Microsoft.WindowsAzure.Storage // Namespace for CloudStorageAccount + open Microsoft.WindowsAzure.Storage.Blob // Namespace for Blob storage types + +### 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](https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/). + +For the tutorial, you'll enter your connection string in your script, like this: + + let storageConnString = "..." // fill this in from your storage account + +However, this is a **bad idea** 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: + + // Parse the connection string and return a reference to the storage account. + let storageConnString = + CloudConfigurationManager.GetSetting("StorageConnectionString") + +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: + + // Parse the connection string and return a reference to the storage account. + let storageAccount = CloudStorageAccount.Parse(storageConnString) + +This will return a `CloudStorageAccount`. + +### Create the Blob service client + +The `CloudBlobClient` type enables you to retrieve containers and blobs stored in Blob storage. Here's one way to create the service client: + + let blobClient = storageAccount.CreateCloudBlobClient() + +Now you are ready to write code that reads data from and writes data to Blob storage. + +## Create a container + +This example shows how to create a container if it does not already exist: + + // Retrieve a reference to a container. + let container = blobClient.GetContainerReference("mycontainer") + + // Create the container if it doesn't already exist. + container.CreateIfNotExists() + +By default, the new container is private, meaning that you must specify your storage access key to download blobs from this container. If you want to make the files within the container available to everyone, you can set the container to be public using the following code: + + container.SetPermissions( + BlobContainerPermissions( + PublicAccess = BlobContainerPublicAccessType.Blob)) + +Anyone on the Internet can see blobs in a public container, but you can modify or delete them only if you have the appropriate account access key or a shared access signature. + +## Upload a blob into a container + +Azure Blob Storage supports block blobs and page blobs. In the majority of cases, a block blob is the recommended type to use. + +To upload a file to a block blob, get a container reference and use it to get a block blob reference. Once you have a blob reference, you can upload any stream of data to it by calling the `UploadFromStream` method. This operation will create the blob if it didn't previously exist, or overwrite it if it does exist. + + // Retrieve reference to a blob named "myblob". + let blockBlob = container.GetBlockBlobReference("myblob") + + // Create or overwrite the "myblob" blob with contents from a local file. + do + use fileStream = File.OpenRead(@"path\myfile") + blockBlob.UploadFromStream(fileStream) + +## List the blobs in a container + +To list the blobs in a container, first get a container reference. You can then use the container's `ListBlobs` method to retrieve the blobs and/or directories within it. To access the rich set of properties and methods for a returned `IListBlobItem`, you must cast it to a `CloudBlockBlob`, `CloudPageBlob`, or `CloudBlobDirectory` object. If the type is unknown, you can use a type check to determine which to cast it to. The following code demonstrates how to retrieve and output the URI of each item in the `photos` container: + + // Retrieve reference to a previously created container. + let photosContainer = blobClient.GetContainerReference("photos") + + // Loop over items within the container and output the length and URI. + for item in photosContainer.ListBlobs(null, false) do + match item with + | :? CloudBlockBlob as blob -> + Console.WriteLine( + "Block blob of length {0}: {1}", + blob.Properties.Length, blob.Uri) + + | :? CloudPageBlob as pageBlob -> + Console.WriteLine( + "Page blob of length {0}: {1}", + pageBlob.Properties.Length, pageBlob.Uri) + + | :? CloudBlobDirectory as directory -> + Console.WriteLine("Directory: {0}", directory.Uri) + + | _ -> + Console.WriteLine("Unknown blob type: {0}", + item.GetType().ToString()) + +As shown above, you can name blobs with path information in their names. This creates a virtual directory structure that you can organize and traverse as you would a traditional file system. Note that the directory structure is virtual only - the only resources available in Blob storage are containers and blobs. However, the storage client library offers a `CloudBlobDirectory` object to refer to a virtual directory and simplify the process of working with blobs that are organized in this way. + +For example, consider the following set of block blobs in a container named `photos`: + + photo1.jpg + 2015/architecture/description.txt + 2015/architecture/photo3.jpg + 2015/architecture/photo4.jpg + 2016/architecture/photo5.jpg + 2016/architecture/photo6.jpg + 2016/architecture/description.txt + 2016/photo7.jpg + +When you call `ListBlobs` on the 'photos' container (as in the above sample), a hierarchical listing is returned. It contains both `CloudBlobDirectory` and `CloudBlockBlob` objects, representing the directories and blobs in the container, respectively. The resulting output looks like: + + Directory: https://.blob.core.windows.net/photos/2015/ + Directory: https://.blob.core.windows.net/photos/2016/ + Block blob of length 505623: https://.blob.core.windows.net/photos/photo1.jpg + + +Optionally, you can set the `UseFlatBlobListing` parameter of of the `ListBlobs` method to `true`. In this case, every blob in the container is returned as a `CloudBlockBlob` object. The call to `ListBlobs` to return a flat listing looks like this: + + // Loop over items within the container and output the length and URI. + for item in container.ListBlobs(null, true) do + ... + +and the results look like this: + + Block blob of length 4: https://.blob.core.windows.net/photos/2015/architecture/description.txt + Block blob of length 314618: https://.blob.core.windows.net/photos/2015/architecture/photo3.jpg + Block blob of length 522713: https://.blob.core.windows.net/photos/2015/architecture/photo4.jpg + Block blob of length 4: https://.blob.core.windows.net/photos/2016/architecture/description.txt + Block blob of length 419048: https://.blob.core.windows.net/photos/2016/architecture/photo5.jpg + Block blob of length 506388: https://.blob.core.windows.net/photos/2016/architecture/photo6.jpg + Block blob of length 399751: https://.blob.core.windows.net/photos/2016/photo7.jpg + Block blob of length 505623: https://.blob.core.windows.net/photos/photo1.jpg + + +## Download blobs + +To download blobs, first retrieve a blob reference and then call the `DownloadToStream` method. The following example uses the `DownloadToStream` method to transfer the blob contents to a stream object that you can then persist to a local file. + + // Retrieve reference to a blob named "photo1.jpg". + let photoBlob = container.GetBlockBlobReference("photo1.jpg") + + // Save blob contents to a file. + do + use fileStream = File.OpenWrite(@"path\myfile") + photoBlob.DownloadToStream(fileStream) + +You can also use the `DownloadToStream` method to download the contents of a blob as a text string. + + // Retrieve reference to a blob named "myblob.txt" + let photoBlob2 = container.GetBlockBlobReference("myblob.txt") + + let text = + use memoryStream = new MemoryStream() + photoBlob2.DownloadToStream(memoryStream) + Text.Encoding.UTF8.GetString(memoryStream.ToArray()) + +## Delete blobs + +To delete a blob, first get a blob reference and then call the +`Delete` method on it. + + // Retrieve reference to a blob named "myblob.txt". + let blockBlob3 = container.GetBlockBlobReference("myblob.txt") + + // Delete the blob. + blockBlob3.Delete() + +## List blobs in pages asynchronously + +If you are listing a large number of blobs, or you want to control the number of results you return in one listing operation, you can list blobs in pages of results. This example shows how to return results in pages asynchronously, so that execution is not blocked while waiting to return a large set of results. + +This example shows a flat blob listing, but you can also perform a hierarchical listing, by setting the `useFlatBlobListing` parameter of the `ListBlobsSegmentedAsync` method to `false`. + +Because the sample method calls an asynchronous method, it must be prefaced with the `async` keyword, and it must return a `Task` object. The await keyword specified for the `ListBlobsSegmentedAsync` method suspends execution of the sample method until the listing task completes. + + let ListBlobsSegmentedInFlatListing(container:CloudBlobContainer) = + async { + + // List blobs to the console window, with paging. + Console.WriteLine("List blobs in pages:") + + // Call ListBlobsSegmentedAsync and enumerate the result segment + // returned, while the continuation token is non-null. + // When the continuation token is null, the last page has been + // returned and execution can exit the loop. + + let rec loop continuationToken (i:int) = + async { + // This overload allows control of the page size. You can return + // all remaining results by passing null for the maxResults + // parameter, or by calling a different overload. + let! ct = Async.CancellationToken + let! resultSegment = + container.ListBlobsSegmentedAsync( + "", true, BlobListingDetails.All, Nullable 10, + continuationToken, null, null, ct) + |> Async.AwaitTask + + if (resultSegment.Results |> Seq.length > 0) then + Console.WriteLine("Page {0}:", i) + + for blobItem in resultSegment.Results do + Console.WriteLine("\t{0}", blobItem.StorageUri.PrimaryUri) + + Console.WriteLine() + + // Get the continuation token. + let continuationToken = resultSegment.ContinuationToken + if (continuationToken <> null) then + do! loop continuationToken (i+1) + } + + do! loop null 1 + } + +## Writing to an append blob + +An append blob is optimized for append operations, such as logging. Like a block blob, an append blob is comprised of blocks, but when you add a new block to an append blob, it is always appended to the end of the blob. You cannot update or delete an existing block in an append blob. The block IDs for an append blob are not exposed as they are for a block blob. + +Each block in an append blob can be a different size, up to a maximum of 4 MB, and an append blob can include a maximum of 50,000 blocks. The maximum size of an append blob is therefore slightly more than 195 GB (4 MB X 50,000 blocks). + +The example below creates a new append blob and appends some data to it, simulating a simple logging operation. + + // Get a reference to a container. + let appendContainer = blobClient.GetContainerReference("my-append-blobs") + + // Create the container if it does not already exist. + appendContainer.CreateIfNotExists() |> ignore + + // Get a reference to an append blob. + let appendBlob = appendContainer.GetAppendBlobReference("append-blob.log") + + // Create the append blob. Note that if the blob already exists, the + // CreateOrReplace() method will overwrite it. You can check whether the + // blob exists to avoid overwriting it by using CloudAppendBlob.Exists(). + appendBlob.CreateOrReplace() + + let numBlocks = 10 + + // Generate an array of random bytes. + let rnd = new Random() + let bytes = Array.zeroCreate(numBlocks) + rnd.NextBytes(bytes) + + // Simulate a logging operation by writing text data and byte data to the + // end of the append blob. + for i in 0 .. numBlocks - 1 do + let msg = + String.Format("Timestamp: {0:u} \tLog Entry: {1}{2}", + DateTime.UtcNow, bytes.[i], Environment.NewLine) + appendBlob.AppendText(msg) + + // Read the append blob to the console window. + Console.WriteLine(appendBlob.DownloadText()) + +See [Understanding Block Blobs, Page Blobs, and Append Blobs](https://msdn.microsoft.com/library/azure/ee691964.aspx) for more information about the differences between the three types of blobs. + +## Concurrent access + +To support concurrent access to a blob from multiple clients or multiple process instances, you can use **ETags** or **leases**. + +* **Etag** - provides a way to detect that the blob or container has been modified by another process + +* **Lease** - provides a way to obtain exclusive, renewable, write or delete access to a blob for a period of time + +For further information see [Managing Concurrency in Microsoft Azure Storage](https://azure.microsoft.com/en-us/blog/managing-concurrency-in-microsoft-azure-storage-2/). + +## Naming containers + +Every blob in Azure storage must reside in a container. The container forms part of the blob name. For example, `mycontainer` is the name of the container in these sample blob URIs: + + https://storagesample.blob.core.windows.net/mycontainer/blob1.txt + https://storagesample.blob.core.windows.net/mycontainer/photos/myphoto.jpg + +A container name must be a valid DNS name, conforming to the following naming rules: + +1. Container names must start with a letter or number, and can contain only letters, numbers, and the dash (-) character. +1. Every dash (-) character must be immediately preceded and followed by a letter or number; consecutive dashes are not permitted in container names. +1. All letters in a container name must be lowercase. +1. Container names must be from 3 through 63 characters long. + +Note that the name of a container must always be lowercase. If you include an upper-case letter in a container name, or otherwise violate the container naming rules, you may receive a 400 error (Bad Request). + +## Managing security for blobs + +By default, Azure Storage keeps your data secure by limiting access to the account owner, who is in possession of the account access keys. When you need to share blob data in your storage account, it is important to do so without compromising the security of your account access keys. Additionally, you can encrypt blob data to ensure that it is secure going over the wire and in Azure Storage. + +### Controlling access to blob data + +By default, the blob data in your storage account is accessible only to storage account owner. Authenticating requests against Blob storage requires the account access key by default. However, you might want to make certain blob data available to other users. + +For details on how to control access to blob storage, see [the .NET guide for blob storage section on access control](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-blobs/#controlling-access-to-blob-data). + + +### Encrypting blob data + +Azure Storage supports encrypting blob data both at the client and on the server. + +For details on encrypting blob data, see [the .NET guide for blob storage section on enryption](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-blobs/#encrypting-blob-data). + +## Next steps + +Now that you've learned the basics of Blob storage, follow these links +to learn more. + +### Microsoft Azure Storage Explorer +- [Microsoft Azure Storage Explorer (MASE)](https://azure.microsoft.com/en-us/documentation/articles/vs-azure-tools-storage-manage-with-storage-explorer/) is a free, standalone app from Microsoft that enables you to work visually with Azure Storage data on Windows, OS X, and Linux. + +### Blob storage samples + +- [Getting Started with Azure Blob Storage in C#](https://azure.microsoft.com/documentation/samples/storage-blob-dotnet-getting-started/) + +### Blob storage reference + +- [Storage Client Library for .NET reference](http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409) +- [REST API reference](http://msdn.microsoft.com/library/azure/dd179355) + +### Conceptual guides + +- [Transfer data with the AzCopy command-line utility](https://azure.microsoft.com/en-us/documentation/articles/storage-use-azcopy/) +- [Get started with File storage for .NET](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-files/) +- [How to use Azure blob storage with the WebJobs SDK](https://azure.microsoft.com/en-us/documentation/articles/websites-dotnet-webjobs-sdk-storage-blobs-how-to/) +- [Azure Storage Team Blog]: http://blogs.msdn.com/b/windowsazurestorage/ +- [Configuring Connection Strings](http://msdn.microsoft.com/library/azure/ee758697.aspx) +- [.NET client library reference](http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409) +- [REST API reference](http://msdn.microsoft.com/library/azure/dd179355) diff --git a/docs/fsharp/using-fsharp-on-azure/package-management.md b/docs/fsharp/using-fsharp-on-azure/package-management.md new file mode 100644 index 0000000000000..587ed0365021a --- /dev/null +++ b/docs/fsharp/using-fsharp-on-azure/package-management.md @@ -0,0 +1,86 @@ +--- +title: Using Package Management with F# for Azure +description: Use Paket or Nuget to manage F# Azure dependencies +keywords: visual f#, f#, functional programming, .NET, .NET Core, Azure +author: syclebsc +manager: jbronsk +ms.date: 09/20/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: dd32ef9c-5416-467e-9fa3-c9ee3bb08456 +--- + +# Package Management for F# Azure Dependencies + +Obtaining packages for Azure development is easy when you use a package manager. The two options are [Paket](https://fsprojects.github.io/Paket/) and [NuGet](https://www.nuget.org/). + +## Using Paket + +If you're using [Paket](https://fsprojects.github.io/Paket/) as your dependency manager, you can use the `paket.exe` tool to add Azure dependencies. For example: + + > paket add nuget WindowsAzure.Storage + +Or, if you're using [Mono](http://www.mono-project.com/) for cross-platform .NET development: + + > mono paket.exe add nuget WindowsAzure.Storage + +This will add `WindowsAzure.Storage` to your set of package dependencies for the project in the current directory, modify the `paket.dependencies` file, and download the package. If you have previously set up dependencies, or are working with a project where dependencies have been set up by another developer, you can resolve and install dependencies locally like this: + + > paket install + +Or, for Mono development: + + > mono paket.exe install + +You can update all your package dependencies to the latest version like this: + + > paket update + +Or, for Mono development: + + > mono paket.exe update + +## Using Nuget + +If you're using [NuGet](https://www.nuget.org/) as your dependency manager, you can use the `nuget.exe` tool to add Azure dependencies. For example: + + > nuget install WindowsAzure.Storage -ExcludeVersion + +Or, for Mono development: + + > mono nuget.exe install WindowsAzure.Storage -ExcludeVersion + +This will add `WindowsAzure.Storage` to your set of package dependencies for the project in the current directory, and download the package. If you have previously set up dependencies, or are working with a project where dependencies have been set up by another developer, you can resolve and install dependencies locally like this: + + > nuget restore + +Or, for Mono development: + + > mono nuget.exe restore + +You can update all your package dependencies to the latest version like this: + + > nuget update + +Or, for Mono development: + + > mono nuget.exe update + +# Referencing Assemblies + +In order to use your packages in your F# script, you need to reference the assemblies included in the packages using a `#r` directive. For example: + + > #r "packages/WindowsAzure.Storage/lib/net40/Microsoft.WindowsAzure.Storage.dll" + +As you can see, you'll need to specify the relative path to the DLL and the full DLL name, which may not be exactly the same as the package name. The path will include a framework version and possibly a package version number. To find all the installed assemblies, you can use something like this on a Windows command line: + + > cd packages/WindowsAzure.Storage + > dir /s/b *.dll + +Or in a Unix shell, something like this: + + > find packages/WindowsAzure.Storage -name "*.dll" + +This will give you the paths to the installed assemblies. From there, you can select the correct path for your framework version. From 35bfd81e525194b842440274aed8b2b6017475ab Mon Sep 17 00:00:00 2001 From: Sylvan Clebsch Date: Wed, 21 Sep 2016 16:57:06 +0100 Subject: [PATCH 02/60] F# Queue Storage documentation --- .../using-fsharp-on-azure/blob-storage.md | 4 +- .../using-fsharp-on-azure/queue-storage.md | 200 ++++++++++++++++++ 2 files changed, 201 insertions(+), 3 deletions(-) create mode 100644 docs/fsharp/using-fsharp-on-azure/queue-storage.md diff --git a/docs/fsharp/using-fsharp-on-azure/blob-storage.md b/docs/fsharp/using-fsharp-on-azure/blob-storage.md index e891a839a1675..f30c2ea50218b 100644 --- a/docs/fsharp/using-fsharp-on-azure/blob-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/blob-storage.md @@ -363,9 +363,7 @@ to learn more. ### Conceptual guides - [Transfer data with the AzCopy command-line utility](https://azure.microsoft.com/en-us/documentation/articles/storage-use-azcopy/) -- [Get started with File storage for .NET](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-files/) -- [How to use Azure blob storage with the WebJobs SDK](https://azure.microsoft.com/en-us/documentation/articles/websites-dotnet-webjobs-sdk-storage-blobs-how-to/) -- [Azure Storage Team Blog]: http://blogs.msdn.com/b/windowsazurestorage/ +- [Azure Storage Team Blog](http://blogs.msdn.com/b/windowsazurestorage/) - [Configuring Connection Strings](http://msdn.microsoft.com/library/azure/ee758697.aspx) - [.NET client library reference](http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409) - [REST API reference](http://msdn.microsoft.com/library/azure/dd179355) diff --git a/docs/fsharp/using-fsharp-on-azure/queue-storage.md b/docs/fsharp/using-fsharp-on-azure/queue-storage.md new file mode 100644 index 0000000000000..98b2ffc26a9b8 --- /dev/null +++ b/docs/fsharp/using-fsharp-on-azure/queue-storage.md @@ -0,0 +1,200 @@ +--- +title: Get started with Azure Queue storage using F# +description: Azure Queues provide reliable, asynchronous messaging between application components. Cloud messaging enables your application components to scale independently. +keywords: visual f#, f#, functional programming, .NET, .NET Core, Azure +author: syclebsc +manager: jbronsk +ms.date: 09/20/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: 70dc554c-8f4d-42a7-8e2a-6438657d012a +--- + +# Get started with Azure Queue storage using F# + +Azure Queue storage provides cloud messaging between application components. In designing applications for scale, application components are often decoupled, so that they can scale independently. Queue storage delivers asynchronous messaging for communication between application components, whether they are running in the cloud, on the desktop, on an on-premises server, or on a mobile device. Queue storage also supports managing asynchronous tasks and building process work flows. + +### About this tutorial + +This tutorial shows how to write F# code for some common tasks using Azure Queue storage. Tasks covered include creating and deleting queues and adding, reading, and deleting queue messages. + +### Conceptual overview + +For a conceptual overview of queue storage, please see [the .NET guide for queue storage](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-queues/). + +### Create an Azure storage account + +To use this guide, you must first [create an Azure storage account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/). +You'll also need your storage access key for this account. + +## Create an F# Script and Start F# Interactive + +The samples in this article can be used in either an F# application or an F# script. To create an F# script, create a file with the `.fsx` extension, for example `queues.fsx`, in your F# development environment. + +Next, use a [package manager](package-management.md) such as Paket or NuGet to install the `WindowsAzure.Storage` package and reference `WindowsAzure.Storage.dll` in your script using a `#r` directive. + +### Add namespace declarations + +Add the following `open` statements to the top of the `queues.fsx` file: + + open Microsoft.Azure // Namespace for CloudConfigurationManager + open Microsoft.WindowsAzure.Storage // Namespace for CloudStorageAccount + open Microsoft.WindowsAzure.Storage.Queue // Namespace for Queue storage types + +### 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](https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/). + +For the tutorial, you'll enter your connection string in your script, like this: + + let storageConnString = "..." // fill this in from your storage account + +However, this is a **bad idea** 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: + + // Parse the connection string and return a reference to the storage account. + let storageConnString = + CloudConfigurationManager.GetSetting("StorageConnectionString") + +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: + + // Parse the connection string and return a reference to the storage account. + let storageAccount = CloudStorageAccount.Parse(storageConnString) + +This will return a `CloudStorageAccount`. + +### Create the Queue service client + +The `CloudQueueClient` class enables you to retrieve queues stored in Queue storage. Here's one way to create the service client: + + let queueClient = storageAccount.CreateCloudQueueClient() + +Now you are ready to write code that reads data from and writes data to Queue storage. + +## Create a queue + +This example shows how to create a queue if it doesn't already exist: + + // Retrieve a reference to a container. + let queue = queueClient.GetQueueReference("myqueue") + + // Create the queue if it doesn't already exist + queue.CreateIfNotExists() + +## Insert a message into a queue + +To insert a message into an existing queue, first create a new +`CloudQueueMessage`. Next, call the `AddMessage` method. A +`CloudQueueMessage` can be created from either a string (in UTF-8 +format) or a `byte` array, like this: + + // Create a message and add it to the queue. + let message = new CloudQueueMessage("Hello, World") + queue.AddMessage(message); + +## Peek at the next message + +You can peek at the message in the front of a queue, without removing it +from the queue, by calling the `PeekMessage` method. + + // Peek at the next message. + let peekedMessage = queue.PeekMessage() + let msgAsString = peekedMessage.AsString + +## Change the contents of a queued message + +You can change the contents of a message in-place in the queue. If the +message represents a work task, you could use this feature to update the +status of the work task. The following code updates the queue message +with new contents, and sets the visibility timeout to extend another 60 +seconds. This saves the state of work associated with the message, and +gives the client another minute to continue working on the message. You +could use this technique to track multi-step workflows on queue +messages, without having to start over from the beginning if a +processing step fails due to hardware or software failure. Typically, +you would keep a retry count as well, and if the message is retried more +than some number of times, you would delete it. This protects against a message +that triggers an application error each time it is processed. + + // Update the message contents and set a new timeout. + message.SetMessageContent("Updated contents.") + queue.UpdateMessage(message, + TimeSpan.FromSeconds(60.0), + MessageUpdateFields.Content ||| MessageUpdateFields.Visibility) + +## De-queue the next message + +Your code de-queues a message from a queue in two steps. When you call +`GetMessage`, you get the next message in a queue. A message returned +from `GetMessage` becomes invisible to any other code reading messages +from this queue. By default, this message stays invisible for 30 +seconds. To finish removing the message from the queue, you must also +call `DeleteMessage`. This two-step process of removing a message +assures that if your code fails to process a message due to hardware or +software failure, another instance of your code can get the same message +and try again. Your code calls `DeleteMessage` right after the message +has been processed. + + // Process the message in less than 30 seconds, and then delete the message. + queue.DeleteMessage(message) + +## Use Async-Await pattern with common Queue storage APIs + +This example shows how to use an async workflow with common Queue storage APIs. + + async { + let! exists = queue.CreateIfNotExistsAsync() |> Async.AwaitTask + let msg = new CloudQueueMessage("My message") + queue.AddMessageAsync(msg) |> Async.AwaitTask + let! retrieved = queue.GetMessageAsync() |> Async.AwaitTask + queue.DeleteMessageAsync(retrieved) |> Async.AwaitTask + } + +## Additional options for de-queuing messages + +There are two ways you can customize message retrieval from a queue. +First, you can get a batch of messages (up to 32). Second, you can set a +longer or shorter invisibility timeout, allowing your code more or less +time to fully process each message. The following code example uses +`GetMessages` to get 20 messages in one call and then processes +each message. It also sets the invisibility timeout to five minutes for +each message. Note that the 5 minutes starts for all messages at the same +time, so after 5 minutes have passed since the call to `GetMessages`, any +messages which have not been deleted will become visible again. + + for msg in queue.GetMessages(20, Nullable(TimeSpan.FromMinutes(5.))) do + // Process the message here. + queue.DeleteMessage(msg) + +## Get the queue length + +You can get an estimate of the number of messages in a queue. The `FetchAttributes` method asks the Queue service to retrieve the queue attributes, including the message count. The `ApproximateMessageCount` property returns the last value retrieved by the `FetchAttributes` method, without calling the Queue service. + + queue.FetchAttributes() + let count = queue.ApproximateMessageCount.GetValueOrDefault() + +## Delete a queue + +To delete a queue and all the messages contained in it, call the +`Delete` method on the queue object. + + // Delete the queue. + queue.Delete() + +## Next steps + +Now that you've learned the basics of Queue storage, follow these links +to learn about more complex storage tasks. + +- [Storage Client Library for .NET reference](http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409) +- [Azure Storage Team Blog](http://blogs.msdn.com/b/windowsazurestorage/) +- [Configuring Connection Strings](http://msdn.microsoft.com/library/azure/ee758697.aspx) +- [.NET client library reference](http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409) +- [REST API reference](http://msdn.microsoft.com/library/azure/dd179355) From 014642f961bf85357221699d8b2c52ced200c080 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 21 Sep 2016 17:00:14 +0100 Subject: [PATCH 03/60] Update queue-storage.md --- docs/fsharp/using-fsharp-on-azure/queue-storage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fsharp/using-fsharp-on-azure/queue-storage.md b/docs/fsharp/using-fsharp-on-azure/queue-storage.md index 98b2ffc26a9b8..1a59be1c9313a 100644 --- a/docs/fsharp/using-fsharp-on-azure/queue-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/queue-storage.md @@ -1,5 +1,5 @@ --- -title: Get started with Azure Queue storage using F# +title: Get started with Azure Queue storage using F# description: Azure Queues provide reliable, asynchronous messaging between application components. Cloud messaging enables your application components to scale independently. keywords: visual f#, f#, functional programming, .NET, .NET Core, Azure author: syclebsc From ee882f1fa5178dd21998b57f63b74d1bfaa88912 Mon Sep 17 00:00:00 2001 From: Sylvan Clebsch Date: Thu, 22 Sep 2016 12:49:39 +0100 Subject: [PATCH 04/60] table storage WIP --- .../using-fsharp-on-azure/table-storage.md | 338 ++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100644 docs/fsharp/using-fsharp-on-azure/table-storage.md diff --git a/docs/fsharp/using-fsharp-on-azure/table-storage.md b/docs/fsharp/using-fsharp-on-azure/table-storage.md new file mode 100644 index 0000000000000..c9b0d8f51f1b5 --- /dev/null +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -0,0 +1,338 @@ +--- +title: Get started with Azure Table storage using F# +description: Store structured data in the cloud using Azure Table storage, a NoSQL data store. +keywords: visual f#, f#, functional programming, .NET, .NET Core, Azure +author: syclebsc +manager: jbronsk +ms.date: 09/20/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: 9e5d6cea-a98c-461e-a5cc-75f1d154eafd +--- + +# Get started with Azure Table storage using F# + +Azure Table storage is a service that stores structured NoSQL data in the cloud. Table storage is a key/attribute store with a schemaless design. Because Table storage is schemaless, it's easy to adapt your data as the needs of your application evolve. Access to data is fast and cost-effective for all kinds of applications. Table storage is typically significantly lower in cost than traditional SQL for similar volumes of data. + +You can use Table storage to store flexible datasets, such as user data for web applications, address books, device information, and any other type of metadata that your service requires. You can store any number of entities in a table, and a storage account may contain any number of tables, up to the capacity limit of the storage account. + +### About this tutorial + +This tutorial shows how to write F# code to do some common tasks using Azure Table storage, including creating and deleting a table and inserting, updating, deleting, and querying table data. + +### Conceptual overview + +For a conceptual overview of table storage, please see [the .NET guide for table storage](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-tables/) + +### Create an Azure storage account + +To use this guide, you must first [create an Azure storage account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/). +You'll also need your storage access key for this account. + +## Create an F# Script and Start F# Interactive + +The samples in this article can be used in either an F# application or an F# script. To create an F# script, create a file with the `.fsx` extension, for example `tables.fsx`, in your F# development environment. + +Next, use a [package manager](package-management.md) such as Paket or NuGet to install the `WindowsAzure.Storage` package and reference `WindowsAzure.Storage.dll` in your script using a `#r` directive. + +### Add namespace declarations + +Add the following `open` statements to the top of the `blobs.fsx` file: + + open System + open System.IO + open Microsoft.Azure // Namespace for CloudConfigurationManager + open Microsoft.WindowsAzure.Storage // Namespace for CloudStorageAccount + open Microsoft.WindowsAzure.Storage.Table // Namespace for Table storage types + +### 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](https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/). + +For the tutorial, you'll enter your connection string in your script, like this: + + let storageConnString = "..." // fill this in from your storage account + +However, this is a **bad idea** 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: + + // Parse the connection string and return a reference to the storage account. + let storageConnString = + CloudConfigurationManager.GetSetting("StorageConnectionString") + +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: + + // Parse the connection string and return a reference to the storage account. + let storageAccount = CloudStorageAccount.Parse(storageConnString) + +This will return a `CloudStorageAccount`. + +### Create the Table service client + +The `CloudTableClient` class enables you to retrieve tables and entities stored in Table storage. Here's one way to create the service client: + + // Create the table client. + let tableClient = storageAccount.CreateCloudTableClient() + +Now you are ready to write code that reads data from and writes data to Table storage. + +## Create a table + +This example shows how to create a table if it does not already exist: + + // Retrieve a reference to the table. + let table = tableClient.GetTableReference("people") + + // Create the table if it doesn't exist. + table.CreateIfNotExists() + +## Add an entity to a table + +An entity has to have a type that inherits from `TableEntity`. You can extend `TableEntity` in any way you like, but your type *must* have a parameter-less constructor. Only properties that have both `get` and `set` will be stored in your Azure Table. + +An entity's partition and row key uniquely identify the entity in the table. Entities with the same partition key can be queried faster than those with different partition keys, but using diverse partition keys allows for greater scalability of parallel operations. + +Here's an example of a `Customer` that uses the `lastName` as the partition key and the `firstName` as the row key. + + type Customer + (firstName, lastName, email: string, phone: string) = + inherit TableEntity(lastName, firstName) + new() = Customer(null, null, null, null) + member val Email = email with get, set + member val PhoneNumber = phone with get, set + + let customer = + Customer("Larry", "Buster", "larry@example.com", "425-555-0101") + +Now we'll add our `Customer` to the table. To do so, we create a `TableOperation` that we will execute on the table. In this case, we create an `Insert` operation. + + let insertOp = TableOperation.Insert(customer) + table.Execute(insertOp) + +## Insert a batch of entities + +You can insert a batch of entities into a table using a single write operation. Batch operations allow you to combine operations into a single execution, but they have some restrictions: + +- You can perform updates, deletes, and inserts in the same batch operation. +- A batch operation can include up to 100 entities. +- All entities in a batch operation must have the same partition key. +- While it is possible to perform a query in a batch operation, it must be the only operation in the batch. + +Here's some code that combines two inserts into a batch operation: + + let customer2 = + Customer("Bob", "Boomer", "bob@example.com", "425-555-0102") + + let batchOp = TableBatchOperation() + batchOp.Insert(customer) + batchOp.Insert(customer2) + table.ExecuteBatch(batchOp) + +## Retrieve all entities in a partition + +To query a table for all entities in a partition, use a `TableQuery` object. Here, we filter for entities where "Buster" is the partition key. + + let query = + TableQuery().Where( + TableQuery.GenerateFilterCondition( + "PartitionKey", QueryComparisons.Equal, "Buster")) + + let result = table.ExecuteQuery(query) + +## Retrieve a range of entities in a partition + +If you don't want to query all the entities in a partition, you can specify a range by combining the partition key filter with a row key filter. Here, we use two filters to get all entities in the "Buster" partition where the row key (first name) starts with a letter earlier than "M" in the alphabet. + + let range = + TableQuery().Where( + TableQuery.CombineFilters( + TableQuery.GenerateFilterCondition( + "PartitionKey", QueryComparisons.Equal, "Buster"), + TableOperators.And, + TableQuery.GenerateFilterCondition( + "RowKey", QueryComparisons.LessThan, "M"))) + + let rangeResult = table.ExecuteQuery(query) + +## Retrieve a single entity + +You can write a query to retrieve a single, specific entity. Here, we use a `TableOperation` to specify the customer "Larry Buster". Instead of a collection, we get back a `Customer`. Specifying both the partition key and the row key in a query is the fastest way to retrieve a single entity from the Table service. + + let retrieveOp = TableOperation.Retrieve("Buster", "Larry") + let retrieveResult = table.Execute(retrieveOp) + +## Replace an entity + +To update an entity, retrieve it from the Table service, modify the entity object, and then save the changes back to the Table service using a `Replace` operation. This causes the entity to be fully replaced on the server, unless the entity on the server has changed since it was retrieved, in which case the operation will fail. This failure is to prevent your application from inadvertently overwriting changes from other sources. + + try + let customer = retrieveResult.Result :?> Customer + customer.PhoneNumber <- "425-555-0103" + let replaceOp = TableOperation.Replace(customer) + table.Execute(replaceOp) |> ignore + with e -> + Console.WriteLine("Update failed") + +## Insert-or-replace an entity + +Sometimes, you don't know if the entity exists in the table or not. And if it does, the current values stored in it are no longer needed. We can use `InsertOrReplace` to create the entity, or replace it if it exists, regardless of its state. + + try + customer.PhoneNumber <- "425-555-0104" + let replaceOp = TableOperation.InsertOrReplace(customer) + table.Execute(replaceOp) |> ignore + with e -> + Console.WriteLine("Update failed") + +TODO: from here + +## Query a subset of entity properties + +A table query can retrieve just a few properties from an entity instead of all the entity properties. This technique, called projection, reduces bandwidth and can improve query performance, especially for large entities. The query in the +following code returns only the email addresses of entities in the +table. This is done by using a query of **DynamicTableEntity** and +also **EntityResolver**. You can learn more about projection on the [Introducing Upsert and Query Projection blog post][]. Note that projection is not supported on the local storage emulator, so this code runs only when you're using an account on the Table service. + + // Retrieve the storage account from the connection string. + CloudStorageAccount storageAccount = CloudStorageAccount.Parse( + CloudConfigurationManager.GetSetting("StorageConnectionString")); + + // Create the table client. + CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); + + // Create the CloudTable that represents the "people" table. + CloudTable table = tableClient.GetTableReference("people"); + + // Define the query, and select only the Email property. + TableQuery projectionQuery = new TableQuery().Select(new string[] { "Email" }); + + // Define an entity resolver to work with the entity after retrieval. + EntityResolver resolver = (pk, rk, ts, props, etag) => props.ContainsKey("Email") ? props["Email"].StringValue : null; + + foreach (string projectedEmail in table.ExecuteQuery(projectionQuery, resolver, null, null)) + { + Console.WriteLine(projectedEmail); + } + +## Delete an entity + +You can easily delete an entity after you have retrieved it, by using the same pattern +shown for updating an entity. The following code +retrieves and deletes a customer entity. + + // Retrieve the storage account from the connection string. + CloudStorageAccount storageAccount = CloudStorageAccount.Parse( + CloudConfigurationManager.GetSetting("StorageConnectionString")); + + // Create the table client. + CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); + + // Create the CloudTable that represents the "people" table. + CloudTable table = tableClient.GetTableReference("people"); + + // Create a retrieve operation that expects a customer entity. + TableOperation retrieveOperation = TableOperation.Retrieve("Smith", "Ben"); + + // Execute the operation. + TableResult retrievedResult = table.Execute(retrieveOperation); + + // Assign the result to a CustomerEntity. + CustomerEntity deleteEntity = (CustomerEntity)retrievedResult.Result; + + // Create the Delete TableOperation. + if (deleteEntity != null) + { + TableOperation deleteOperation = TableOperation.Delete(deleteEntity); + + // Execute the operation. + table.Execute(deleteOperation); + + Console.WriteLine("Entity deleted."); + } + + else + Console.WriteLine("Could not retrieve the entity."); + +## Delete a table + +Finally, the following code example deletes a table from a storage account. A +table that has been deleted will be unavailable to be re-created for a +period of time following the deletion. + + // Retrieve the storage account from the connection string. + CloudStorageAccount storageAccount = CloudStorageAccount.Parse( + CloudConfigurationManager.GetSetting("StorageConnectionString")); + + // Create the table client. + CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); + + // Create the CloudTable that represents the "people" table. + CloudTable table = tableClient.GetTableReference("people"); + + // Delete the table it if exists. + table.DeleteIfExists(); + +## Retrieve entities in pages asynchronously + +If you are reading a large number of entities, and you want to process/display entities as they are retrieved rather than waiting for them all to return, you can retrieve entities by using a segmented query. This example shows how to return results in pages by using the Async-Await pattern so that execution is not blocked while you're waiting for a large set of results to return. For more details on using the Async-Await pattern in .NET, see [Asynchronous programming with Async and Await (C# and Visual Basic)](https://msdn.microsoft.com/library/hh191443.aspx). + + // Initialize a default TableQuery to retrieve all the entities in the table. + TableQuery tableQuery = new TableQuery(); + + // Initialize the continuation token to null to start from the beginning of the table. + TableContinuationToken continuationToken = null; + + do + { + // Retrieve a segment (up to 1,000 entities). + TableQuerySegment tableQueryResult = + await table.ExecuteQuerySegmentedAsync(tableQuery, continuationToken); + + // Assign the new continuation token to tell the service where to + // continue on the next iteration (or null if it has reached the end). + continuationToken = tableQueryResult.ContinuationToken; + + // Print the number of rows retrieved. + Console.WriteLine("Rows retrieved {0}", tableQueryResult.Results.Count); + + // Loop until a null continuation token is received, indicating the end of the table. + } while(continuationToken != null); + +## Next steps + +Now that you've learned the basics of Table storage, follow these links +to learn about more complex storage tasks: + +- See more Table storage samples in [Getting Started with Azure Table Storage in .NET](https://azure.microsoft.com/documentation/samples/storage-table-dotnet-getting-started/) +- View the Table service reference documentation for complete details about available APIs: + - [Storage Client Library for .NET reference](http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409) + - [REST API reference](http://msdn.microsoft.com/library/azure/dd179355) +- Learn how to simplify the code you write to work with Azure Storage by using the [Azure WebJobs SDK](../app-service-web/websites-dotnet-webjobs-sdk-get-started.md) +- View more feature guides to learn about additional options for storing data in Azure. + - [Get started with Azure Blob storage using .NET](storage-dotnet-how-to-use-blobs.md) to store unstructured data. + - [How to use Azure SQL Database in .NET applications](sql-database-dotnet-how-to-use.md) to store relational data. + + [Download and install the Azure SDK for .NET]: /develop/net/ + [Creating an Azure Project in Visual Studio]: http://msdn.microsoft.com/library/azure/ee405487.aspx + + [Blob5]: ./media/storage-dotnet-how-to-use-table-storage/blob5.png + [Blob6]: ./media/storage-dotnet-how-to-use-table-storage/blob6.png + [Blob7]: ./media/storage-dotnet-how-to-use-table-storage/blob7.png + [Blob8]: ./media/storage-dotnet-how-to-use-table-storage/blob8.png + [Blob9]: ./media/storage-dotnet-how-to-use-table-storage/blob9.png + + [Introducing Upsert and Query Projection blog post]: http://blogs.msdn.com/b/windowsazurestorage/archive/2011/09/15/windows-azure-tables-introducing-upsert-and-query-projection.aspx + [.NET Client Library reference]: http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409 + [Azure Storage Team blog]: http://blogs.msdn.com/b/windowsazurestorage/ + [Configure Azure Storage connection strings]: http://msdn.microsoft.com/library/azure/ee758697.aspx + [OData]: http://nuget.org/packages/Microsoft.Data.OData/5.0.2 + [Edm]: http://nuget.org/packages/Microsoft.Data.Edm/5.0.2 + [Spatial]: http://nuget.org/packages/System.Spatial/5.0.2 + [How to: Programmatically access Table storage]: #tablestorage \ No newline at end of file From d342253e814ef2fe7f385bf967781ba37fcf138a Mon Sep 17 00:00:00 2001 From: Sylvan Clebsch Date: Thu, 22 Sep 2016 14:51:40 +0100 Subject: [PATCH 05/60] Update table-storage.md --- .../using-fsharp-on-azure/queue-storage.md | 1 - .../using-fsharp-on-azure/table-storage.md | 155 ++++-------------- 2 files changed, 35 insertions(+), 121 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/queue-storage.md b/docs/fsharp/using-fsharp-on-azure/queue-storage.md index 1a59be1c9313a..90f06ab883d01 100644 --- a/docs/fsharp/using-fsharp-on-azure/queue-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/queue-storage.md @@ -196,5 +196,4 @@ to learn about more complex storage tasks. - [Storage Client Library for .NET reference](http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409) - [Azure Storage Team Blog](http://blogs.msdn.com/b/windowsazurestorage/) - [Configuring Connection Strings](http://msdn.microsoft.com/library/azure/ee758697.aspx) -- [.NET client library reference](http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409) - [REST API reference](http://msdn.microsoft.com/library/azure/dd179355) diff --git a/docs/fsharp/using-fsharp-on-azure/table-storage.md b/docs/fsharp/using-fsharp-on-azure/table-storage.md index c9b0d8f51f1b5..28be3c8173b2e 100644 --- a/docs/fsharp/using-fsharp-on-azure/table-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -78,8 +78,8 @@ This will return a `CloudStorageAccount`. The `CloudTableClient` class enables you to retrieve tables and entities stored in Table storage. Here's one way to create the service client: - // Create the table client. - let tableClient = storageAccount.CreateCloudTableClient() + // Create the table client. + let tableClient = storageAccount.CreateCloudTableClient() Now you are ready to write code that reads data from and writes data to Table storage. @@ -191,148 +191,63 @@ Sometimes, you don't know if the entity exists in the table or not. And if it do with e -> Console.WriteLine("Update failed") -TODO: from here - ## Query a subset of entity properties -A table query can retrieve just a few properties from an entity instead of all the entity properties. This technique, called projection, reduces bandwidth and can improve query performance, especially for large entities. The query in the -following code returns only the email addresses of entities in the -table. This is done by using a query of **DynamicTableEntity** and -also **EntityResolver**. You can learn more about projection on the [Introducing Upsert and Query Projection blog post][]. Note that projection is not supported on the local storage emulator, so this code runs only when you're using an account on the Table service. - - // Retrieve the storage account from the connection string. - CloudStorageAccount storageAccount = CloudStorageAccount.Parse( - CloudConfigurationManager.GetSetting("StorageConnectionString")); - - // Create the table client. - CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); - - // Create the CloudTable that represents the "people" table. - CloudTable table = tableClient.GetTableReference("people"); +A table query can retrieve just a few properties from an entity instead of all of them. This technique, called projection, can improve query performance, especially for large entities. Here, we return only email addresses using `DynamicTableEntity` and `EntityResolver`. Note that projection is not supported on the local storage emulator, so this code runs only when you're using an account on the Table service. // Define the query, and select only the Email property. - TableQuery projectionQuery = new TableQuery().Select(new string[] { "Email" }); + let projectionQ = TableQuery().Select([|"Email"|]) // Define an entity resolver to work with the entity after retrieval. - EntityResolver resolver = (pk, rk, ts, props, etag) => props.ContainsKey("Email") ? props["Email"].StringValue : null; + let resolver = EntityResolver(fun pk rk ts props etag -> + if props.ContainsKey("Email") then + props.["Email"].StringValue + else + null + ) - foreach (string projectedEmail in table.ExecuteQuery(projectionQuery, resolver, null, null)) - { - Console.WriteLine(projectedEmail); - } + table.ExecuteQuery(projectionQ, resolver, null, null) ## Delete an entity -You can easily delete an entity after you have retrieved it, by using the same pattern -shown for updating an entity. The following code -retrieves and deletes a customer entity. - - // Retrieve the storage account from the connection string. - CloudStorageAccount storageAccount = CloudStorageAccount.Parse( - CloudConfigurationManager.GetSetting("StorageConnectionString")); - - // Create the table client. - CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); - - // Create the CloudTable that represents the "people" table. - CloudTable table = tableClient.GetTableReference("people"); - - // Create a retrieve operation that expects a customer entity. - TableOperation retrieveOperation = TableOperation.Retrieve("Smith", "Ben"); - - // Execute the operation. - TableResult retrievedResult = table.Execute(retrieveOperation); +You can delete an entity after you have retrieved it. As with updating an entity, this will fail if the entity has changed since you retrieved it. - // Assign the result to a CustomerEntity. - CustomerEntity deleteEntity = (CustomerEntity)retrievedResult.Result; - - // Create the Delete TableOperation. - if (deleteEntity != null) - { - TableOperation deleteOperation = TableOperation.Delete(deleteEntity); - - // Execute the operation. - table.Execute(deleteOperation); - - Console.WriteLine("Entity deleted."); - } - - else - Console.WriteLine("Could not retrieve the entity."); + let deleteOp = TableOperation.Delete(customer) + table.Execute(deleteOp) ## Delete a table -Finally, the following code example deletes a table from a storage account. A -table that has been deleted will be unavailable to be re-created for a -period of time following the deletion. - - // Retrieve the storage account from the connection string. - CloudStorageAccount storageAccount = CloudStorageAccount.Parse( - CloudConfigurationManager.GetSetting("StorageConnectionString")); +You can delete a table from a storage account. A table that has been deleted will be unavailable to be re-created for a period of time following the deletion. - // Create the table client. - CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); - - // Create the CloudTable that represents the "people" table. - CloudTable table = tableClient.GetTableReference("people"); - - // Delete the table it if exists. - table.DeleteIfExists(); + table.DeleteIfExists() ## Retrieve entities in pages asynchronously -If you are reading a large number of entities, and you want to process/display entities as they are retrieved rather than waiting for them all to return, you can retrieve entities by using a segmented query. This example shows how to return results in pages by using the Async-Await pattern so that execution is not blocked while you're waiting for a large set of results to return. For more details on using the Async-Await pattern in .NET, see [Asynchronous programming with Async and Await (C# and Visual Basic)](https://msdn.microsoft.com/library/hh191443.aspx). - - // Initialize a default TableQuery to retrieve all the entities in the table. - TableQuery tableQuery = new TableQuery(); - - // Initialize the continuation token to null to start from the beginning of the table. - TableContinuationToken continuationToken = null; - - do - { - // Retrieve a segment (up to 1,000 entities). - TableQuerySegment tableQueryResult = - await table.ExecuteQuerySegmentedAsync(tableQuery, continuationToken); +If you are reading a large number of entities, and you want to process them as they are retrieved rather than waiting for them all to return, you can use a segmented query. Here, we return results in pages by using an async workflow so that execution is not blocked while you're waiting for a large set of results to return. - // Assign the new continuation token to tell the service where to - // continue on the next iteration (or null if it has reached the end). - continuationToken = tableQueryResult.ContinuationToken; + let tableQ = TableQuery() - // Print the number of rows retrieved. - Console.WriteLine("Rows retrieved {0}", tableQueryResult.Results.Count); + async { + let rec q (cont: TableContinuationToken) = async { + let! result = + table.ExecuteQuerySegmentedAsync(tableQ, cont) + |> Async.AwaitTask - // Loop until a null continuation token is received, indicating the end of the table. - } while(continuationToken != null); + // Process the result here. + match result.ContinuationToken with + | null -> return () + | cont -> q cont |> Async.RunSynchronously + } + q null |> Async.RunSynchronously + } |> Async.RunSynchronously ## Next steps Now that you've learned the basics of Table storage, follow these links to learn about more complex storage tasks: -- See more Table storage samples in [Getting Started with Azure Table Storage in .NET](https://azure.microsoft.com/documentation/samples/storage-table-dotnet-getting-started/) -- View the Table service reference documentation for complete details about available APIs: - - [Storage Client Library for .NET reference](http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409) - - [REST API reference](http://msdn.microsoft.com/library/azure/dd179355) -- Learn how to simplify the code you write to work with Azure Storage by using the [Azure WebJobs SDK](../app-service-web/websites-dotnet-webjobs-sdk-get-started.md) -- View more feature guides to learn about additional options for storing data in Azure. - - [Get started with Azure Blob storage using .NET](storage-dotnet-how-to-use-blobs.md) to store unstructured data. - - [How to use Azure SQL Database in .NET applications](sql-database-dotnet-how-to-use.md) to store relational data. - - [Download and install the Azure SDK for .NET]: /develop/net/ - [Creating an Azure Project in Visual Studio]: http://msdn.microsoft.com/library/azure/ee405487.aspx - - [Blob5]: ./media/storage-dotnet-how-to-use-table-storage/blob5.png - [Blob6]: ./media/storage-dotnet-how-to-use-table-storage/blob6.png - [Blob7]: ./media/storage-dotnet-how-to-use-table-storage/blob7.png - [Blob8]: ./media/storage-dotnet-how-to-use-table-storage/blob8.png - [Blob9]: ./media/storage-dotnet-how-to-use-table-storage/blob9.png - - [Introducing Upsert and Query Projection blog post]: http://blogs.msdn.com/b/windowsazurestorage/archive/2011/09/15/windows-azure-tables-introducing-upsert-and-query-projection.aspx - [.NET Client Library reference]: http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409 - [Azure Storage Team blog]: http://blogs.msdn.com/b/windowsazurestorage/ - [Configure Azure Storage connection strings]: http://msdn.microsoft.com/library/azure/ee758697.aspx - [OData]: http://nuget.org/packages/Microsoft.Data.OData/5.0.2 - [Edm]: http://nuget.org/packages/Microsoft.Data.Edm/5.0.2 - [Spatial]: http://nuget.org/packages/System.Spatial/5.0.2 - [How to: Programmatically access Table storage]: #tablestorage \ No newline at end of file +- [Storage Client Library for .NET reference](http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409) +- [Azure Storage Team Blog](http://blogs.msdn.com/b/windowsazurestorage/) +- [Configuring Connection Strings](http://msdn.microsoft.com/library/azure/ee758697.aspx) +- [REST API reference](http://msdn.microsoft.com/library/azure/dd179355) +- [Getting Started with Azure Table Storage in .NET](https://azure.microsoft.com/documentation/samples/storage-table-dotnet-getting-started/) From 0a863bd58b8cfbd976b42d44677927c01c189826 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 22 Sep 2016 16:26:55 +0100 Subject: [PATCH 06/60] Update table-storage.md --- docs/fsharp/using-fsharp-on-azure/table-storage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fsharp/using-fsharp-on-azure/table-storage.md b/docs/fsharp/using-fsharp-on-azure/table-storage.md index 28be3c8173b2e..985b4171c04b5 100644 --- a/docs/fsharp/using-fsharp-on-azure/table-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -12,7 +12,7 @@ ms.devlang: dotnet ms.assetid: 9e5d6cea-a98c-461e-a5cc-75f1d154eafd --- -# Get started with Azure Table storage using F# +# Get started with Azure Table storage using F# Azure Table storage is a service that stores structured NoSQL data in the cloud. Table storage is a key/attribute store with a schemaless design. Because Table storage is schemaless, it's easy to adapt your data as the needs of your application evolve. Access to data is fast and cost-effective for all kinds of applications. Table storage is typically significantly lower in cost than traditional SQL for similar volumes of data. From 5b90766331a55efc4ccf1468f143a94d599eb4ca Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 22 Sep 2016 17:00:47 +0100 Subject: [PATCH 07/60] Various updates to make the walkthrough run more smoothly --- .../using-fsharp-on-azure/blob-storage.md | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/blob-storage.md b/docs/fsharp/using-fsharp-on-azure/blob-storage.md index f30c2ea50218b..6d58dcac408b6 100644 --- a/docs/fsharp/using-fsharp-on-azure/blob-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/blob-storage.md @@ -85,16 +85,15 @@ Now you are ready to write code that reads data from and writes data to Blob sto This example shows how to create a container if it does not already exist: // Retrieve a reference to a container. - let container = blobClient.GetContainerReference("mycontainer") + let container = blobClient.GetContainerReference("photos") // Create the container if it doesn't already exist. container.CreateIfNotExists() By default, the new container is private, meaning that you must specify your storage access key to download blobs from this container. If you want to make the files within the container available to everyone, you can set the container to be public using the following code: - container.SetPermissions( - BlobContainerPermissions( - PublicAccess = BlobContainerPublicAccessType.Blob)) + let permissions = BlobContainerPermissions(PublicAccess=BlobContainerPublicAccessType.Blob) + container.SetPermissions(permissions) Anyone on the Internet can see blobs in a public container, but you can modify or delete them only if you have the appropriate account access key or a shared access signature. @@ -107,9 +106,13 @@ To upload a file to a block blob, get a container reference and use it to get a // Retrieve reference to a blob named "myblob". let blockBlob = container.GetBlockBlobReference("myblob") - // Create or overwrite the "myblob" blob with contents from a local file. + // Create a dummy file in a local subdirectory to upload + let localFile = __SOURCE_DIRECTORY__ + "/myfile.txt" + File.WriteAllText(localFile, "some data") + + // Create or overwrite the "myblob" blob with contents from the local file. do - use fileStream = File.OpenRead(@"path\myfile") + use fileStream = System.IO.File.OpenRead(localFile) blockBlob.UploadFromStream(fileStream) ## List the blobs in a container @@ -163,7 +166,15 @@ Optionally, you can set the `UseFlatBlobListing` parameter of of the `ListBlobs` // Loop over items within the container and output the length and URI. for item in container.ListBlobs(null, true) do - ... + match item with + | :? CloudBlockBlob as blob -> + Console.WriteLine( + "Block blob of length {0}: {1}", + blob.Properties.Length, blob.Uri) + + | _ -> + Console.WriteLine("Unexpected blob type: {0}", + item.GetType().ToString()) and the results look like this: @@ -186,7 +197,7 @@ To download blobs, first retrieve a blob reference and then call the `DownloadTo // Save blob contents to a file. do - use fileStream = File.OpenWrite(@"path\myfile") + use fileStream = File.OpenWrite(__SOURCE_DIRECTORY__ + "/path/myfile") photoBlob.DownloadToStream(fileStream) You can also use the `DownloadToStream` method to download the contents of a blob as a text string. @@ -345,25 +356,21 @@ For details on encrypting blob data, see [the .NET guide for blob storage sectio ## Next steps -Now that you've learned the basics of Blob storage, follow these links -to learn more. +Now that you've learned the basics of Blob storage, follow these links to learn more. -### Microsoft Azure Storage Explorer +### Tools +- [F# AzureStorageTypeProvider](http://fsprojects.github.io/AzureStorageTypeProvider/) An F# Type Provider which can be used to explore Blob, Table and Queue Azure Storage assets and easily apply CRUD operations on them. +- [FSharp.Azure.Storage](https://github.com/fsprojects/FSharp.Azure.Storage) An F# API for using Microsoft Azure Table Storage service - [Microsoft Azure Storage Explorer (MASE)](https://azure.microsoft.com/en-us/documentation/articles/vs-azure-tools-storage-manage-with-storage-explorer/) is a free, standalone app from Microsoft that enables you to work visually with Azure Storage data on Windows, OS X, and Linux. -### Blob storage samples - -- [Getting Started with Azure Blob Storage in C#](https://azure.microsoft.com/documentation/samples/storage-blob-dotnet-getting-started/) - ### Blob storage reference - [Storage Client Library for .NET reference](http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409) - [REST API reference](http://msdn.microsoft.com/library/azure/dd179355) -### Conceptual guides +### Related guides +- [Getting Started with Azure Blob Storage in C#](https://azure.microsoft.com/documentation/samples/storage-blob-dotnet-getting-started/) - [Transfer data with the AzCopy command-line utility](https://azure.microsoft.com/en-us/documentation/articles/storage-use-azcopy/) -- [Azure Storage Team Blog](http://blogs.msdn.com/b/windowsazurestorage/) - [Configuring Connection Strings](http://msdn.microsoft.com/library/azure/ee758697.aspx) -- [.NET client library reference](http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409) -- [REST API reference](http://msdn.microsoft.com/library/azure/dd179355) +- [Azure Storage Team Blog](http://blogs.msdn.com/b/windowsazurestorage/) From 59b95c875b769d3d52ab438bdc514773803276d7 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 22 Sep 2016 17:22:04 +0100 Subject: [PATCH 08/60] Update blob-storage.md --- .../using-fsharp-on-azure/blob-storage.md | 82 ++++++++++--------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/blob-storage.md b/docs/fsharp/using-fsharp-on-azure/blob-storage.md index 6d58dcac408b6..bbc42a7263625 100644 --- a/docs/fsharp/using-fsharp-on-azure/blob-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/blob-storage.md @@ -72,6 +72,14 @@ To parse the connection string, use: This will return a `CloudStorageAccount`. +### Create some local dummy data + +Before we begin, create some dummy local data in the directory of our script. Later you will upload this data. + + // Create a dummy file in a local subdirectory to upload + let localFile = __SOURCE_DIRECTORY__ + "/myfile.txt" + File.WriteAllText(localFile, "some data") + ### Create the Blob service client The `CloudBlobClient` type enables you to retrieve containers and blobs stored in Blob storage. Here's one way to create the service client: @@ -85,7 +93,7 @@ Now you are ready to write code that reads data from and writes data to Blob sto This example shows how to create a container if it does not already exist: // Retrieve a reference to a container. - let container = blobClient.GetContainerReference("photos") + let container = blobClient.GetContainerReference("mydata") // Create the container if it doesn't already exist. container.CreateIfNotExists() @@ -103,44 +111,32 @@ Azure Blob Storage supports block blobs and page blobs. In the majority of cases To upload a file to a block blob, get a container reference and use it to get a block blob reference. Once you have a blob reference, you can upload any stream of data to it by calling the `UploadFromStream` method. This operation will create the blob if it didn't previously exist, or overwrite it if it does exist. - // Retrieve reference to a blob named "myblob". - let blockBlob = container.GetBlockBlobReference("myblob") - - // Create a dummy file in a local subdirectory to upload - let localFile = __SOURCE_DIRECTORY__ + "/myfile.txt" - File.WriteAllText(localFile, "some data") + // Retrieve reference to a blob named "myblob.txt". + let blockBlob = container.GetBlockBlobReference("myblob.txt") - // Create or overwrite the "myblob" blob with contents from the local file. + // Create or overwrite the "myblob.txt" blob with contents from the local file. do - use fileStream = System.IO.File.OpenRead(localFile) + use fileStream = File.OpenRead localFile blockBlob.UploadFromStream(fileStream) ## List the blobs in a container -To list the blobs in a container, first get a container reference. You can then use the container's `ListBlobs` method to retrieve the blobs and/or directories within it. To access the rich set of properties and methods for a returned `IListBlobItem`, you must cast it to a `CloudBlockBlob`, `CloudPageBlob`, or `CloudBlobDirectory` object. If the type is unknown, you can use a type check to determine which to cast it to. The following code demonstrates how to retrieve and output the URI of each item in the `photos` container: - - // Retrieve reference to a previously created container. - let photosContainer = blobClient.GetContainerReference("photos") +To list the blobs in a container, first get a container reference. You can then use the container's `ListBlobs` method to retrieve the blobs and/or directories within it. To access the rich set of properties and methods for a returned `IListBlobItem`, you must cast it to a `CloudBlockBlob`, `CloudPageBlob`, or `CloudBlobDirectory` object. If the type is unknown, you can use a type check to determine which to cast it to. The following code demonstrates how to retrieve and output the URI of each item in the `mydata` container: // Loop over items within the container and output the length and URI. - for item in photosContainer.ListBlobs(null, false) do + for item in container.ListBlobs(null, false) do match item with | :? CloudBlockBlob as blob -> - Console.WriteLine( - "Block blob of length {0}: {1}", - blob.Properties.Length, blob.Uri) + printfn "Block blob of length %d: %O" blob.Properties.Length blob.Uri | :? CloudPageBlob as pageBlob -> - Console.WriteLine( - "Page blob of length {0}: {1}", - pageBlob.Properties.Length, pageBlob.Uri) + printfn "Page blob of length %d: %O" pageBlob.Properties.Length pageBlob.Uri | :? CloudBlobDirectory as directory -> - Console.WriteLine("Directory: {0}", directory.Uri) + printfn "Directory: %O" directory.Uri | _ -> - Console.WriteLine("Unknown blob type: {0}", - item.GetType().ToString()) + printfn "Unknown blob type: %O" (item.GetType()) As shown above, you can name blobs with path information in their names. This creates a virtual directory structure that you can organize and traverse as you would a traditional file system. Note that the directory structure is virtual only - the only resources available in Blob storage are containers and blobs. However, the storage client library offers a `CloudBlobDirectory` object to refer to a virtual directory and simplify the process of working with blobs that are organized in this way. @@ -176,7 +172,7 @@ Optionally, you can set the `UseFlatBlobListing` parameter of of the `ListBlobs` Console.WriteLine("Unexpected blob type: {0}", item.GetType().ToString()) -and the results look like this: +and, depending on the current contents of your container, the results look like this: Block blob of length 4: https://.blob.core.windows.net/photos/2015/architecture/description.txt Block blob of length 314618: https://.blob.core.windows.net/photos/2015/architecture/photo3.jpg @@ -192,22 +188,19 @@ and the results look like this: To download blobs, first retrieve a blob reference and then call the `DownloadToStream` method. The following example uses the `DownloadToStream` method to transfer the blob contents to a stream object that you can then persist to a local file. - // Retrieve reference to a blob named "photo1.jpg". - let photoBlob = container.GetBlockBlobReference("photo1.jpg") + // Retrieve reference to a blob named "myblob.txt". + let blobToDownload = container.GetBlockBlobReference("myblob.txt") // Save blob contents to a file. do - use fileStream = File.OpenWrite(__SOURCE_DIRECTORY__ + "/path/myfile") - photoBlob.DownloadToStream(fileStream) + use fileStream = File.OpenWrite(__SOURCE_DIRECTORY__ + "/path/download.txt") + blobToDownload.DownloadToStream(fileStream) You can also use the `DownloadToStream` method to download the contents of a blob as a text string. - // Retrieve reference to a blob named "myblob.txt" - let photoBlob2 = container.GetBlockBlobReference("myblob.txt") - let text = use memoryStream = new MemoryStream() - photoBlob2.DownloadToStream(memoryStream) + blobToDownload.DownloadToStream(memoryStream) Text.Encoding.UTF8.GetString(memoryStream.ToArray()) ## Delete blobs @@ -216,10 +209,10 @@ To delete a blob, first get a blob reference and then call the `Delete` method on it. // Retrieve reference to a blob named "myblob.txt". - let blockBlob3 = container.GetBlockBlobReference("myblob.txt") + let blobToDelete = container.GetBlockBlobReference("myblob.txt") // Delete the blob. - blockBlob3.Delete() + blobToDelete.Delete() ## List blobs in pages asynchronously @@ -265,10 +258,23 @@ Because the sample method calls an asynchronous method, it must be prefaced with if (continuationToken <> null) then do! loop continuationToken (i+1) } - + do! loop null 1 } +We can now use this asynchronous routine as follows. First we upload some dummy data (using the local +file created earlier in this tutorial). + + // Create some dummy data by upoading the same file over andd over again + for i in 1 .. 100 do + let blob = container.GetBlockBlobReference("myblob" + string i + ".txt") + use fileStream = System.IO.File.OpenRead(localFile) + blob.UploadFromStream fileStream + +Now, call the routine. We use ``Async.RunSynchronously`` to force the execution of the asynchronous operation. + + ListBlobsSegmentedInFlatListing container |> Async.RunSynchronously + ## Writing to an append blob An append blob is optimized for append operations, such as logging. Like a block blob, an append blob is comprised of blocks, but when you add a new block to an append blob, it is always appended to the end of the blob. You cannot update or delete an existing block in an append blob. The block IDs for an append blob are not exposed as they are for a block blob. @@ -323,10 +329,10 @@ For further information see [Managing Concurrency in Microsoft Azure Storage](ht ## Naming containers -Every blob in Azure storage must reside in a container. The container forms part of the blob name. For example, `mycontainer` is the name of the container in these sample blob URIs: +Every blob in Azure storage must reside in a container. The container forms part of the blob name. For example, `mydata` is the name of the container in these sample blob URIs: - https://storagesample.blob.core.windows.net/mycontainer/blob1.txt - https://storagesample.blob.core.windows.net/mycontainer/photos/myphoto.jpg + https://storagesample.blob.core.windows.net/mydata/blob1.txt + https://storagesample.blob.core.windows.net/mydata/photos/myphoto.jpg A container name must be a valid DNS name, conforming to the following naming rules: From 7ab6426029654e3108840e9fd252a1e6d27b6687 Mon Sep 17 00:00:00 2001 From: Sylvan Clebsch Date: Thu, 22 Sep 2016 17:23:54 +0100 Subject: [PATCH 09/60] Add file-storage.md --- .../using-fsharp-on-azure/file-storage.md | 219 ++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 docs/fsharp/using-fsharp-on-azure/file-storage.md diff --git a/docs/fsharp/using-fsharp-on-azure/file-storage.md b/docs/fsharp/using-fsharp-on-azure/file-storage.md new file mode 100644 index 0000000000000..09eece3bf40e2 --- /dev/null +++ b/docs/fsharp/using-fsharp-on-azure/file-storage.md @@ -0,0 +1,219 @@ +--- +title: Get started with Azure File storage using F# +description: Store file data in the cloud with Azure File storage, and mount your cloud file share from an Azure virtual machine (VM) or from an on-premises application running Windows. +keywords: visual f#, f#, functional programming, .NET, .NET Core, Azure +author: syclebsc +manager: jbronsk +ms.date: 09/20/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: 5c26a0aa-186e-476c-9f87-e0191754579e +--- + +# Get started with Azure File storage using F# + +Azure File storage is a service that offers file shares in the cloud using the standard [Server Message Block (SMB) Protocol](https://msdn.microsoft.com/library/windows/desktop/aa365233.aspx). Both SMB 2.1 and SMB 3.0 are supported. With Azure File storage, you can migrate legacy applications that rely on file shares to Azure quickly and without costly rewrites. Applications running in Azure virtual machines or cloud services or from on-premises clients can mount a file share in the cloud, just as a desktop application mounts a typical SMB share. Any number of application components can then mount and access the File storage share simultaneously. + +### Conceptual overview + +For a conceptual overview of file storage, please see [the .NET guide for file storage](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-files/). + +### Create an Azure storage account + +To use this guide, you must first [create an Azure storage account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/). +You'll also need your storage access key for this account. + +## Create an F# Script and Start F# Interactive + +The samples in this article can be used in either an F# application or an F# script. To create an F# script, create a file with the `.fsx` extension, for example `blobs.fsx`, in your F# development environment. + +Next, use a [package manager](package-management.md) such as Paket or NuGet to install the `WindowsAzure.Storage` package and reference `WindowsAzure.Storage.dll` in your script using a `#r` directive. + +### Add namespace declarations + +Add the following `open` statements to the top of the `blobs.fsx` file: + + open System + open System.IO + open Microsoft.Azure // Namespace for CloudConfigurationManager + open Microsoft.WindowsAzure.Storage // Namespace for CloudStorageAccount + open Microsoft.WindowsAzure.Storage.File // Namespace for File storage types + +### 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](https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/). + +For the tutorial, you'll enter your connection string in your script, like this: + + let storageConnString = "..." // fill this in from your storage account + +However, this is a **bad idea** 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: + + // Parse the connection string and return a reference to the storage account. + let storageConnString = + CloudConfigurationManager.GetSetting("StorageConnectionString") + +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: + + // Parse the connection string and return a reference to the storage account. + let storageAccount = CloudStorageAccount.Parse(storageConnString) + +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: + + let fileClient = storageAccount.CreateCloudFileClient() + +Now you are ready to write code that reads data from and writes data to Blob storage. + +## Create a file share + +This example shows how to create a file share if it does not already exist: + + let share = fileClient.GetShareReference("myFiles") + share.CreateIfNotExists() + +### Access the file share programmatically + +Here, we get the root directory and get a sub-directory of the root. If the sub-directory exists, we get a file in the sub-directory, and if that exists too, we download the file, appending the contents to a local file. + + let rootDir = share.GetRootDirectoryReference() + let subDir = rootDir.GetDirectoryReference("myLogs") + + if subDir.Exists() then + let file = subDir.GetFileReference("log.txt") + if file.Exists() then + file.DownloadToFile("log.txt", FileMode.Append) + +### 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. + + // stats.Usage is current usage in GB + let stats = share.GetStats() + share.FetchAttributes() + + // Set the quota to 10 GB plus current usage + share.Properties.Quota <- stats.Usage + 10 |> Nullable + share.SetProperties() + + // Remove the quota + share.Properties.Quota <- Nullable() + share.SetProperties() + +### 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. + +Here, we 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. + + // Create a 24 hour read/write policy. + let policy = SharedAccessFilePolicy() + policy.SharedAccessExpiryTime <- + DateTimeOffset.UtcNow.AddHours(24.) |> Nullable + policy.Permissions <- + SharedAccessFilePermissions.Read ||| SharedAccessFilePermissions.Write + + // Set the policy on the share. + let permissions = share.GetPermissions() + permissions.SharedAccessPolicies.Add("policyName", policy) + share.SetPermissions(permissions) + + let file = subDir.GetFileReference("log.txt") + let sasToken = file.GetSharedAccessSignature(policy) + let sasUri = Uri(file.StorageUri.PrimaryUri.ToString() + sasToken) + + let fileSas = CloudFile(sasUri) + fileSas.UploadText("This write operation is authenticated via SAS") + +For more information about creating and using shared access signatures, see [Using Shared Access Signatures (SAS)](https://azure.microsoft.com/en-gb/documentation/articles/storage-dotnet-shared-access-signature-part-1/) and [Create and use a SAS with Blob storage](https://azure.microsoft.com/en-gb/documentation/articles/storage-dotnet-shared-access-signature-part-2/). + +### Copy files + +You can copy a file to another file, a file to a blob, or a blob to a file. If you are copying a blob to a file, or a file to a blob, you *must* use a shared access signature (SAS) to authenticate the source object, even if you are copying within the same storage account. + +### Copy a file to another file + +Here, we 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. + + let destFile = subDir.GetFileReference("log_copy.txt") + destFile.StartCopy(file) + +### Copy a file to a blob + +Here, we create a file and copy it to a blob within the same storage account. We create a SAS for the source file, which the service uses to authenticate access to the source file during the copy operation. + + // 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") + + let filePolicy = SharedAccessFilePolicy() + filePolicy.Permissions <- SharedAccessFilePermissions.Read + filePolicy.SharedAccessExpiryTime <- + DateTimeOffset.UtcNow.AddHours(24.) |> Nullable + + let fileSas2 = file.GetSharedAccessSignature(filePolicy) + let sasUri2 = Uri(file.StorageUri.PrimaryUri.ToString() + fileSas2) + destBlob.StartCopy(sasUri2) + +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. + +## Troubleshooting File storage using metrics + +Azure Storage Analytics supports metrics for File storage. With metrics data, you can trace requests and diagnose issues. + +You can enable metrics for File storage from the [Azure Portal](https://portal.azure.com), or you can do it from F# like this: + + open Microsoft.WindowsAzure.Storage.File.Protocol + open Microsoft.WindowsAzure.Storage.Shared.Protocol + + let props = FileServiceProperties() + props.HourMetrics <- MetricsProperties() + props.HourMetrics.MetricsLevel <- MetricsLevel.ServiceAndApi + props.HourMetrics.RetentionDays <- 14 |> Nullable + props.HourMetrics.Version <- "1.0" + props.MinuteMetrics <- MetricsProperties() + props.MinuteMetrics.MetricsLevel <- MetricsLevel.ServiceAndApi + props.MinuteMetrics.RetentionDays <- 7 |> Nullable + props.MinuteMetrics.Version <- "1.0" + + fileClient.SetServiceProperties(props) + +## Next steps + +See these links for more information about Azure File storage. + +### Conceptual articles and videos + +- [Azure Files Storage: a frictionless cloud SMB file system for Windows and Linux](https://azure.microsoft.com/documentation/videos/azurecon-2015-azure-files-storage-a-frictionless-cloud-smb-file-system-for-windows-and-linux/) +- [How to use Azure File Storage with Linux](https://azure.microsoft.com/en-gb/documentation/articles/storage-how-to-use-files-linux/) + +### Tooling support for File storage + +- [Using Azure PowerShell with Azure Storage](https://azure.microsoft.com/en-gb/documentation/articles/storage-powershell-guide-full/) +- [How to use AzCopy with Microsoft Azure Storage](https://azure.microsoft.com/en-gb/documentation/articles/storage-use-azcopy/) +- [Using the Azure CLI with Azure Storage](https://azure.microsoft.com/en-gb/documentation/articles/storage-azure-cli/#create-and-manage-file-shares) + +### Reference + +- [Storage Client Library for .NET reference](https://msdn.microsoft.com/library/azure/dn261237.aspx) +- [File Service REST API reference](http://msdn.microsoft.com/library/azure/dn167006.aspx) + +### Blog posts + +- [Azure File storage is now generally available](https://azure.microsoft.com/blog/azure-file-storage-now-generally-available/) +- [Inside Azure File Storage](https://azure.microsoft.com/blog/inside-azure-file-storage/) +- [Introducing Microsoft Azure File Service](http://blogs.msdn.com/b/windowsazurestorage/archive/2014/05/12/introducing-microsoft-azure-file-service.aspx) +- [Persisting connections to Microsoft Azure Files](http://blogs.msdn.com/b/windowsazurestorage/archive/2014/05/27/persisting-connections-to-microsoft-azure-files.aspx) From a1532e070ad5c52923cbb60db4bab99d2ada9621 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 22 Sep 2016 17:32:09 +0100 Subject: [PATCH 10/60] Write a small landing page Here's a small landing page --- docs/fsharp/using-fsharp-on-azure/index.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index f72151f1f6740..a54c7d0201d79 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -1,4 +1,19 @@ # Using F# on Azure -> [!NOTE] -This is still in progress. \ No newline at end of file +F# is a superb language for cloud programming and is frequently used to write web applications, cloud services, cloud-hosted microservices, and for scalable data processing. + +In the sections below, you will find resources on how to use a range of Azure services with F#. + +> Note: If a particular Azure service doesn't have documentation below, please consult the C# documentation for that service. Some +> Azure services are entirely language-independent systems services and require no language-specific documentation, and in this +> case are not listed here. + +## Using Azure Storage with F# + +* [Get started with Azure Blob storage using F#](blob-storage.md) +* [Get started with Azure Queue storage using F#](queue-storage.md) +* [Get started with Azure Table storage using F#](table-storage.md) + +## Other resources + +* [Full documentation on all Azure services](https://azure.microsoft.com/en-us/documentation/) From 776e26349bf4907b4d59e051d6ec6b6625141bbd Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 22 Sep 2016 17:34:33 +0100 Subject: [PATCH 11/60] Update index.md --- docs/fsharp/using-fsharp-on-azure/index.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index a54c7d0201d79..fa26f8a4d7b7e 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -1,3 +1,18 @@ +--- +title: Using F# on Azure +description: Guide to using Azure services with F# +keywords: Azure, cloud, visual f#, f#, functional programming, .NET, .NET Core +author: dsyme +manager: jbronsk +ms.date: 09/22/2016 +ms.topic: article +ms.prod: .net-core +ms.technology: .net-core-technologies +ms.devlang: dotnet +ms.assetid: FAD4D11E-703A-42D4-9F72-893D9E0F569B +--- + + # Using F# on Azure F# is a superb language for cloud programming and is frequently used to write web applications, cloud services, cloud-hosted microservices, and for scalable data processing. From f25a2a14e2610c39d6ab007a49bf4ed1d3a7e863 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 22 Sep 2016 17:39:21 +0100 Subject: [PATCH 12/60] Remove uses of Console.WriteLine Let's prefer to use F# ``printf`` in samples. --- .../using-fsharp-on-azure/blob-storage.md | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/blob-storage.md b/docs/fsharp/using-fsharp-on-azure/blob-storage.md index bbc42a7263625..27f56422e8a97 100644 --- a/docs/fsharp/using-fsharp-on-azure/blob-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/blob-storage.md @@ -164,13 +164,10 @@ Optionally, you can set the `UseFlatBlobListing` parameter of of the `ListBlobs` for item in container.ListBlobs(null, true) do match item with | :? CloudBlockBlob as blob -> - Console.WriteLine( - "Block blob of length {0}: {1}", - blob.Properties.Length, blob.Uri) + printfn "Block blob of length %d: %O" blob.Properties.Length blob.Uri | _ -> - Console.WriteLine("Unexpected blob type: {0}", - item.GetType().ToString()) + printfn "Unexpected blob type: %O" (item.GetType()) and, depending on the current contents of your container, the results look like this: @@ -226,7 +223,7 @@ Because the sample method calls an asynchronous method, it must be prefaced with async { // List blobs to the console window, with paging. - Console.WriteLine("List blobs in pages:") + printfn "List blobs in pages:" // Call ListBlobsSegmentedAsync and enumerate the result segment // returned, while the continuation token is non-null. @@ -246,12 +243,12 @@ Because the sample method calls an asynchronous method, it must be prefaced with |> Async.AwaitTask if (resultSegment.Results |> Seq.length > 0) then - Console.WriteLine("Page {0}:", i) + printfn "Page %d:" i for blobItem in resultSegment.Results do - Console.WriteLine("\t{0}", blobItem.StorageUri.PrimaryUri) + printfn "\t%O" blobItem.StorageUri.PrimaryUri - Console.WriteLine() + printfn "" // Get the continuation token. let continuationToken = resultSegment.ContinuationToken @@ -307,13 +304,12 @@ The example below creates a new append blob and appends some data to it, simulat // Simulate a logging operation by writing text data and byte data to the // end of the append blob. for i in 0 .. numBlocks - 1 do - let msg = - String.Format("Timestamp: {0:u} \tLog Entry: {1}{2}", - DateTime.UtcNow, bytes.[i], Environment.NewLine) + let msg = sprintf "Timestamp: %u \tLog Entry: %d\n" DateTime.UtcNow bytes.[i] appendBlob.AppendText(msg) // Read the append blob to the console window. - Console.WriteLine(appendBlob.DownloadText()) + let downloadedText = appendBlob.DownloadText() + printfn "%s" downloadedText See [Understanding Block Blobs, Page Blobs, and Append Blobs](https://msdn.microsoft.com/library/azure/ee691964.aspx) for more information about the differences between the three types of blobs. From a64909c7fb68047597802b03a7c11f098745a103 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 22 Sep 2016 17:41:18 +0100 Subject: [PATCH 13/60] Update index.md --- docs/fsharp/using-fsharp-on-azure/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index fa26f8a4d7b7e..566f5773c0dc1 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -26,6 +26,7 @@ In the sections below, you will find resources on how to use a range of Azure se ## Using Azure Storage with F# * [Get started with Azure Blob storage using F#](blob-storage.md) +* [Get started with Azure File storage using F#](file-storage.md) * [Get started with Azure Queue storage using F#](queue-storage.md) * [Get started with Azure Table storage using F#](table-storage.md) From 31c2dc1ac39cdcf78fa38bd1fdca320e51fd0724 Mon Sep 17 00:00:00 2001 From: cartermp Date: Thu, 22 Sep 2016 13:56:10 -0700 Subject: [PATCH 14/60] Update blob storage to use script samples. --- .../using-fsharp-on-azure/blob-storage.md | 176 +++------------ docs/fsharp/using-fsharp-on-azure/index.md | 4 +- .../snippets/fsharp/azure/blob-storage.fsx | 203 ++++++++++++++++++ 3 files changed, 230 insertions(+), 153 deletions(-) create mode 100644 samples/snippets/fsharp/azure/blob-storage.fsx diff --git a/docs/fsharp/using-fsharp-on-azure/blob-storage.md b/docs/fsharp/using-fsharp-on-azure/blob-storage.md index 27f56422e8a97..67136a614a649 100644 --- a/docs/fsharp/using-fsharp-on-azure/blob-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/blob-storage.md @@ -39,11 +39,7 @@ Next, use a [package manager](package-management.md) such as Paket or NuGet to i Add the following `open` statements to the top of the `blobs.fsx` file: - open System - open System.IO - open Microsoft.Azure // Namespace for CloudConfigurationManager - open Microsoft.WindowsAzure.Storage // Namespace for CloudStorageAccount - open Microsoft.WindowsAzure.Storage.Blob // Namespace for Blob storage types +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L5)] ### Get your connection string @@ -51,15 +47,13 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: - let storageConnString = "..." // fill this in from your storage account +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L11)] However, this is a **bad idea** 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: - // Parse the connection string and return a reference to the storage account. - let storageConnString = - CloudConfigurationManager.GetSetting("StorageConnectionString") +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L13-L15)] Using Azure Configuration Manager is optional. You can also use an API such as the .NET Framework's `ConfigurationManager` type. @@ -67,8 +61,7 @@ Using Azure Configuration Manager is optional. You can also use an API such as t To parse the connection string, use: - // Parse the connection string and return a reference to the storage account. - let storageAccount = CloudStorageAccount.Parse(storageConnString) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L21-L22)] This will return a `CloudStorageAccount`. @@ -76,15 +69,13 @@ This will return a `CloudStorageAccount`. Before we begin, create some dummy local data in the directory of our script. Later you will upload this data. - // Create a dummy file in a local subdirectory to upload - let localFile = __SOURCE_DIRECTORY__ + "/myfile.txt" - File.WriteAllText(localFile, "some data") +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L28-L30)] ### Create the Blob service client The `CloudBlobClient` type enables you to retrieve containers and blobs stored in Blob storage. Here's one way to create the service client: - let blobClient = storageAccount.CreateCloudBlobClient() +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L36)] Now you are ready to write code that reads data from and writes data to Blob storage. @@ -92,16 +83,11 @@ Now you are ready to write code that reads data from and writes data to Blob sto This example shows how to create a container if it does not already exist: - // Retrieve a reference to a container. - let container = blobClient.GetContainerReference("mydata") - - // Create the container if it doesn't already exist. - container.CreateIfNotExists() +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L42-L46)] By default, the new container is private, meaning that you must specify your storage access key to download blobs from this container. If you want to make the files within the container available to everyone, you can set the container to be public using the following code: - let permissions = BlobContainerPermissions(PublicAccess=BlobContainerPublicAccessType.Blob) - container.SetPermissions(permissions) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L48-L49)] Anyone on the Internet can see blobs in a public container, but you can modify or delete them only if you have the appropriate account access key or a shared access signature. @@ -111,45 +97,26 @@ Azure Blob Storage supports block blobs and page blobs. In the majority of cases To upload a file to a block blob, get a container reference and use it to get a block blob reference. Once you have a blob reference, you can upload any stream of data to it by calling the `UploadFromStream` method. This operation will create the blob if it didn't previously exist, or overwrite it if it does exist. - // Retrieve reference to a blob named "myblob.txt". - let blockBlob = container.GetBlockBlobReference("myblob.txt") - - // Create or overwrite the "myblob.txt" blob with contents from the local file. - do - use fileStream = File.OpenRead localFile - blockBlob.UploadFromStream(fileStream) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L55-L61)] ## List the blobs in a container To list the blobs in a container, first get a container reference. You can then use the container's `ListBlobs` method to retrieve the blobs and/or directories within it. To access the rich set of properties and methods for a returned `IListBlobItem`, you must cast it to a `CloudBlockBlob`, `CloudPageBlob`, or `CloudBlobDirectory` object. If the type is unknown, you can use a type check to determine which to cast it to. The following code demonstrates how to retrieve and output the URI of each item in the `mydata` container: - // Loop over items within the container and output the length and URI. - for item in container.ListBlobs(null, false) do - match item with - | :? CloudBlockBlob as blob -> - printfn "Block blob of length %d: %O" blob.Properties.Length blob.Uri - - | :? CloudPageBlob as pageBlob -> - printfn "Page blob of length %d: %O" pageBlob.Properties.Length pageBlob.Uri - - | :? CloudBlobDirectory as directory -> - printfn "Directory: %O" directory.Uri - - | _ -> - printfn "Unknown blob type: %O" (item.GetType()) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L67-L80)] As shown above, you can name blobs with path information in their names. This creates a virtual directory structure that you can organize and traverse as you would a traditional file system. Note that the directory structure is virtual only - the only resources available in Blob storage are containers and blobs. However, the storage client library offers a `CloudBlobDirectory` object to refer to a virtual directory and simplify the process of working with blobs that are organized in this way. For example, consider the following set of block blobs in a container named `photos`: - photo1.jpg - 2015/architecture/description.txt - 2015/architecture/photo3.jpg - 2015/architecture/photo4.jpg - 2016/architecture/photo5.jpg - 2016/architecture/photo6.jpg - 2016/architecture/description.txt - 2016/photo7.jpg + photo1.jpg + 2015/architecture/description.txt + 2015/architecture/photo3.jpg + 2015/architecture/photo4.jpg + 2016/architecture/photo5.jpg + 2016/architecture/photo6.jpg + 2016/architecture/description.txt + 2016/photo7.jpg When you call `ListBlobs` on the 'photos' container (as in the above sample), a hierarchical listing is returned. It contains both `CloudBlobDirectory` and `CloudBlockBlob` objects, representing the directories and blobs in the container, respectively. The resulting output looks like: @@ -160,14 +127,7 @@ When you call `ListBlobs` on the 'photos' container (as in the above sample), a Optionally, you can set the `UseFlatBlobListing` parameter of of the `ListBlobs` method to `true`. In this case, every blob in the container is returned as a `CloudBlockBlob` object. The call to `ListBlobs` to return a flat listing looks like this: - // Loop over items within the container and output the length and URI. - for item in container.ListBlobs(null, true) do - match item with - | :? CloudBlockBlob as blob -> - printfn "Block blob of length %d: %O" blob.Properties.Length blob.Uri - - | _ -> - printfn "Unexpected blob type: %O" (item.GetType()) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L82-L89)] and, depending on the current contents of your container, the results look like this: @@ -185,31 +145,18 @@ and, depending on the current contents of your container, the results look like To download blobs, first retrieve a blob reference and then call the `DownloadToStream` method. The following example uses the `DownloadToStream` method to transfer the blob contents to a stream object that you can then persist to a local file. - // Retrieve reference to a blob named "myblob.txt". - let blobToDownload = container.GetBlockBlobReference("myblob.txt") - - // Save blob contents to a file. - do - use fileStream = File.OpenWrite(__SOURCE_DIRECTORY__ + "/path/download.txt") - blobToDownload.DownloadToStream(fileStream) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L95-L101)] You can also use the `DownloadToStream` method to download the contents of a blob as a text string. - let text = - use memoryStream = new MemoryStream() - blobToDownload.DownloadToStream(memoryStream) - Text.Encoding.UTF8.GetString(memoryStream.ToArray()) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L103-L106)] ## Delete blobs To delete a blob, first get a blob reference and then call the `Delete` method on it. - // Retrieve reference to a blob named "myblob.txt". - let blobToDelete = container.GetBlockBlobReference("myblob.txt") - - // Delete the blob. - blobToDelete.Delete() +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L112-L116)] ## List blobs in pages asynchronously @@ -219,58 +166,16 @@ This example shows a flat blob listing, but you can also perform a hierarchical Because the sample method calls an asynchronous method, it must be prefaced with the `async` keyword, and it must return a `Task` object. The await keyword specified for the `ListBlobsSegmentedAsync` method suspends execution of the sample method until the listing task completes. - let ListBlobsSegmentedInFlatListing(container:CloudBlobContainer) = - async { - - // List blobs to the console window, with paging. - printfn "List blobs in pages:" - - // Call ListBlobsSegmentedAsync and enumerate the result segment - // returned, while the continuation token is non-null. - // When the continuation token is null, the last page has been - // returned and execution can exit the loop. - - let rec loop continuationToken (i:int) = - async { - // This overload allows control of the page size. You can return - // all remaining results by passing null for the maxResults - // parameter, or by calling a different overload. - let! ct = Async.CancellationToken - let! resultSegment = - container.ListBlobsSegmentedAsync( - "", true, BlobListingDetails.All, Nullable 10, - continuationToken, null, null, ct) - |> Async.AwaitTask - - if (resultSegment.Results |> Seq.length > 0) then - printfn "Page %d:" i - - for blobItem in resultSegment.Results do - printfn "\t%O" blobItem.StorageUri.PrimaryUri - - printfn "" - - // Get the continuation token. - let continuationToken = resultSegment.ContinuationToken - if (continuationToken <> null) then - do! loop continuationToken (i+1) - } - - do! loop null 1 - } +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L122-L160)] We can now use this asynchronous routine as follows. First we upload some dummy data (using the local file created earlier in this tutorial). - // Create some dummy data by upoading the same file over andd over again - for i in 1 .. 100 do - let blob = container.GetBlockBlobReference("myblob" + string i + ".txt") - use fileStream = System.IO.File.OpenRead(localFile) - blob.UploadFromStream fileStream +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L162-L166)] Now, call the routine. We use ``Async.RunSynchronously`` to force the execution of the asynchronous operation. - ListBlobsSegmentedInFlatListing container |> Async.RunSynchronously +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L168)] ## Writing to an append blob @@ -280,36 +185,7 @@ Each block in an append blob can be a different size, up to a maximum of 4 MB, a The example below creates a new append blob and appends some data to it, simulating a simple logging operation. - // Get a reference to a container. - let appendContainer = blobClient.GetContainerReference("my-append-blobs") - - // Create the container if it does not already exist. - appendContainer.CreateIfNotExists() |> ignore - - // Get a reference to an append blob. - let appendBlob = appendContainer.GetAppendBlobReference("append-blob.log") - - // Create the append blob. Note that if the blob already exists, the - // CreateOrReplace() method will overwrite it. You can check whether the - // blob exists to avoid overwriting it by using CloudAppendBlob.Exists(). - appendBlob.CreateOrReplace() - - let numBlocks = 10 - - // Generate an array of random bytes. - let rnd = new Random() - let bytes = Array.zeroCreate(numBlocks) - rnd.NextBytes(bytes) - - // Simulate a logging operation by writing text data and byte data to the - // end of the append blob. - for i in 0 .. numBlocks - 1 do - let msg = sprintf "Timestamp: %u \tLog Entry: %d\n" DateTime.UtcNow bytes.[i] - appendBlob.AppendText(msg) - - // Read the append blob to the console window. - let downloadedText = appendBlob.DownloadText() - printfn "%s" downloadedText +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L174-L203)] See [Understanding Block Blobs, Page Blobs, and Append Blobs](https://msdn.microsoft.com/library/azure/ee691964.aspx) for more information about the differences between the three types of blobs. diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index 566f5773c0dc1..d8656e4df9d5d 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -19,9 +19,7 @@ F# is a superb language for cloud programming and is frequently used to write we In the sections below, you will find resources on how to use a range of Azure services with F#. -> Note: If a particular Azure service doesn't have documentation below, please consult the C# documentation for that service. Some -> Azure services are entirely language-independent systems services and require no language-specific documentation, and in this -> case are not listed here. +> [!NOTE] If a particular Azure service doesn't have documentation below, please consult the C# documentation for that service. Some Azure services are entirely language-independent systems services and require no language-specific documentation, and in this case are not listed here. ## Using Azure Storage with F# diff --git a/samples/snippets/fsharp/azure/blob-storage.fsx b/samples/snippets/fsharp/azure/blob-storage.fsx new file mode 100644 index 0000000000000..2032bc761a8c3 --- /dev/null +++ b/samples/snippets/fsharp/azure/blob-storage.fsx @@ -0,0 +1,203 @@ +open System +open System.IO +open Microsoft.Azure // Namespace for CloudConfigurationManager +open Microsoft.WindowsAzure.Storage // Namespace for CloudStorageAccount +open Microsoft.WindowsAzure.Storage.Blob // Namespace for Blob storage types + +// +// Get your connection string. +// + +let storageConnString = "..." // fill this in from your storage account + +// Parse the connection string and return a reference to the 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 some local dummy data. +// + +// Create a dummy file in a local subdirectory to upload +let localFile = __SOURCE_DIRECTORY__ + "/myfile.txt" +File.WriteAllText(localFile, "some data") + +// +// Create the blob service client. +// + +let blobClient = storageAccount.CreateCloudBlobClient() + +// +// Create a container. +// + + // Retrieve a reference to a container. +let container = blobClient.GetContainerReference("mydata") + +// Create the container if it doesn't already exist. +container.CreateIfNotExists() + +let permissions = BlobContainerPermissions(PublicAccess=BlobContainerPublicAccessType.Blob) +container.SetPermissions(permissions) + +// +// Upload a blob into a container. +// + +// Retrieve reference to a blob named "myblob.txt". +let blockBlob = container.GetBlockBlobReference("myblob.txt") + +// Create or overwrite the "myblob.txt" blob with contents from the local file. +do + use fileStream = File.OpenRead localFile + blockBlob.UploadFromStream(fileStream) + +// +// List the blobs in a container. +// + +// Loop over items within the container and output the length and URI. +for item in container.ListBlobs(null, false) do + match item with + | :? CloudBlockBlob as blob -> + printfn "Block blob of length %d: %O" blob.Properties.Length blob.Uri + + | :? CloudPageBlob as pageBlob -> + printfn "Page blob of length %d: %O" pageBlob.Properties.Length pageBlob.Uri + + | :? CloudBlobDirectory as directory -> + printfn "Directory: %O" directory.Uri + + | _ -> + printfn "Unknown blob type: %O" (item.GetType()) + +// Loop over items within the container and output the length and URI. +for item in container.ListBlobs(null, true) do + match item with + | :? CloudBlockBlob as blob -> + printfn "Block blob of length %d: %O" blob.Properties.Length blob.Uri + + | _ -> + printfn "Unexpected blob type: %O" (item.GetType()) + +// +// Download Blobs. +// + +// Retrieve reference to a blob named "myblob.txt". +let blobToDownload = container.GetBlockBlobReference("myblob.txt") + +// Save blob contents to a file. +do + use fileStream = File.OpenWrite(__SOURCE_DIRECTORY__ + "/path/download.txt") + blobToDownload.DownloadToStream(fileStream) + +let text = + use memoryStream = new MemoryStream() + blobToDownload.DownloadToStream(memoryStream) + Text.Encoding.UTF8.GetString(memoryStream.ToArray()) + +// +// Delete blobs. +// + +// Retrieve reference to a blob named "myblob.txt". +let blobToDelete = container.GetBlockBlobReference("myblob.txt") + +// Delete the blob. +blobToDelete.Delete() + +// +// List blobs in pages asynchronously +// + +let ListBlobsSegmentedInFlatListing(container:CloudBlobContainer) = + async { + + // List blobs to the console window, with paging. + printfn "List blobs in pages:" + + // Call ListBlobsSegmentedAsync and enumerate the result segment + // returned, while the continuation token is non-null. + // When the continuation token is null, the last page has been + // returned and execution can exit the loop. + + let rec loop continuationToken (i:int) = + async { + // This overload allows control of the page size. You can return + // all remaining results by passing null for the maxResults + // parameter, or by calling a different overload. + let! ct = Async.CancellationToken + let! resultSegment = + container.ListBlobsSegmentedAsync( + "", true, BlobListingDetails.All, Nullable 10, + continuationToken, null, null, ct) + |> Async.AwaitTask + + if (resultSegment.Results |> Seq.length > 0) then + printfn "Page %d:" i + + for blobItem in resultSegment.Results do + printfn "\t%O" blobItem.StorageUri.PrimaryUri + + printfn "" + + // Get the continuation token. + let continuationToken = resultSegment.ContinuationToken + if (continuationToken <> null) then + do! loop continuationToken (i+1) + } + + do! loop null 1 + } + +// Create some dummy data by upoading the same file over andd over again +for i in 1 .. 100 do + let blob = container.GetBlockBlobReference("myblob" + string i + ".txt") + use fileStream = System.IO.File.OpenRead(localFile) + blob.UploadFromStream fileStream + +ListBlobsSegmentedInFlatListing container |> Async.RunSynchronously + +// +// Writing to an append blob. +// + +// Get a reference to a container. +let appendContainer = blobClient.GetContainerReference("my-append-blobs") + +// Create the container if it does not already exist. +appendContainer.CreateIfNotExists() |> ignore + +// Get a reference to an append blob. +let appendBlob = appendContainer.GetAppendBlobReference("append-blob.log") + +// Create the append blob. Note that if the blob already exists, the +// CreateOrReplace() method will overwrite it. You can check whether the +// blob exists to avoid overwriting it by using CloudAppendBlob.Exists(). +appendBlob.CreateOrReplace() + +let numBlocks = 10 + +// Generate an array of random bytes. +let rnd = new Random() +let bytes = Array.zeroCreate(numBlocks) +rnd.NextBytes(bytes) + +// Simulate a logging operation by writing text data and byte data to the +// end of the append blob. +for i in 0 .. numBlocks - 1 do + let msg = sprintf "Timestamp: %u \tLog Entry: %d\n" DateTime.UtcNow bytes.[i] + appendBlob.AppendText(msg) + +// Read the append blob to the console window. +let downloadedText = appendBlob.DownloadText() +printfn "%s" downloadedText From e73861e629f0e129cd695cf4e1e63d01d0a6d521 Mon Sep 17 00:00:00 2001 From: cartermp Date: Thu, 22 Sep 2016 14:06:39 -0700 Subject: [PATCH 15/60] Update file storage to use script samples. --- .../using-fsharp-on-azure/file-storage.md | 92 ++---------- .../snippets/fsharp/azure/file-storage.fsx | 131 ++++++++++++++++++ 2 files changed, 143 insertions(+), 80 deletions(-) create mode 100644 samples/snippets/fsharp/azure/file-storage.fsx diff --git a/docs/fsharp/using-fsharp-on-azure/file-storage.md b/docs/fsharp/using-fsharp-on-azure/file-storage.md index 09eece3bf40e2..f22b3f5769976 100644 --- a/docs/fsharp/using-fsharp-on-azure/file-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/file-storage.md @@ -35,11 +35,7 @@ Next, use a [package manager](package-management.md) such as Paket or NuGet to i Add the following `open` statements to the top of the `blobs.fsx` file: - open System - open System.IO - open Microsoft.Azure // Namespace for CloudConfigurationManager - open Microsoft.WindowsAzure.Storage // Namespace for CloudStorageAccount - open Microsoft.WindowsAzure.Storage.File // Namespace for File storage types +[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L5)] ### Get your connection string @@ -47,15 +43,13 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: - let storageConnString = "..." // fill this in from your storage account +[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L11)] However, this is a **bad idea** 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: - // Parse the connection string and return a reference to the storage account. - let storageConnString = - CloudConfigurationManager.GetSetting("StorageConnectionString") +[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L13-L15)] Using Azure Configuration Manager is optional. You can also use an API such as the .NET Framework's `ConfigurationManager` type. @@ -63,8 +57,7 @@ Using Azure Configuration Manager is optional. You can also use an API such as t To parse the connection string, use: - // Parse the connection string and return a reference to the storage account. - let storageAccount = CloudStorageAccount.Parse(storageConnString) +[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L21-L22)] This will return a `CloudStorageAccount`. @@ -72,7 +65,7 @@ This will return a `CloudStorageAccount`. The `CloudFileClient` type enables you to programmatically use files stored in File storage. Here's one way to create the service client: - let fileClient = storageAccount.CreateCloudFileClient() +[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L28)] Now you are ready to write code that reads data from and writes data to Blob storage. @@ -80,36 +73,19 @@ Now you are ready to write code that reads data from and writes data to Blob sto This example shows how to create a file share if it does not already exist: - let share = fileClient.GetShareReference("myFiles") - share.CreateIfNotExists() +[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L34-L35)] ### Access the file share programmatically Here, we get the root directory and get a sub-directory of the root. If the sub-directory exists, we get a file in the sub-directory, and if that exists too, we download the file, appending the contents to a local file. - let rootDir = share.GetRootDirectoryReference() - let subDir = rootDir.GetDirectoryReference("myLogs") - - if subDir.Exists() then - let file = subDir.GetFileReference("log.txt") - if file.Exists() then - file.DownloadToFile("log.txt", FileMode.Append) +[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L41-L47)] ### 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. - // stats.Usage is current usage in GB - let stats = share.GetStats() - share.FetchAttributes() - - // Set the quota to 10 GB plus current usage - share.Properties.Quota <- stats.Usage + 10 |> Nullable - share.SetProperties() - - // Remove the quota - share.Properties.Quota <- Nullable() - share.SetProperties() +[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L53-L63)] ### Generate a shared access signature for a file or file share @@ -117,24 +93,7 @@ You can generate a shared access signature (SAS) for a file share or for an indi Here, we 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. - // Create a 24 hour read/write policy. - let policy = SharedAccessFilePolicy() - policy.SharedAccessExpiryTime <- - DateTimeOffset.UtcNow.AddHours(24.) |> Nullable - policy.Permissions <- - SharedAccessFilePermissions.Read ||| SharedAccessFilePermissions.Write - - // Set the policy on the share. - let permissions = share.GetPermissions() - permissions.SharedAccessPolicies.Add("policyName", policy) - share.SetPermissions(permissions) - - let file = subDir.GetFileReference("log.txt") - let sasToken = file.GetSharedAccessSignature(policy) - let sasUri = Uri(file.StorageUri.PrimaryUri.ToString() + sasToken) - - let fileSas = CloudFile(sasUri) - fileSas.UploadText("This write operation is authenticated via SAS") +[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L69-L86)] For more information about creating and using shared access signatures, see [Using Shared Access Signatures (SAS)](https://azure.microsoft.com/en-gb/documentation/articles/storage-dotnet-shared-access-signature-part-1/) and [Create and use a SAS with Blob storage](https://azure.microsoft.com/en-gb/documentation/articles/storage-dotnet-shared-access-signature-part-2/). @@ -146,27 +105,13 @@ You can copy a file to another file, a file to a blob, or a blob to a file. If y Here, we 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. - let destFile = subDir.GetFileReference("log_copy.txt") - destFile.StartCopy(file) +[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L92-L93)] ### Copy a file to a blob Here, we create a file and copy it to a blob within the same storage account. We create a SAS for the source file, which the service uses to authenticate access to the source file during the copy operation. - // 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") - - let filePolicy = SharedAccessFilePolicy() - filePolicy.Permissions <- SharedAccessFilePermissions.Read - filePolicy.SharedAccessExpiryTime <- - DateTimeOffset.UtcNow.AddHours(24.) |> Nullable - - let fileSas2 = file.GetSharedAccessSignature(filePolicy) - let sasUri2 = Uri(file.StorageUri.PrimaryUri.ToString() + fileSas2) - destBlob.StartCopy(sasUri2) +[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L99-L112)] 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. @@ -176,20 +121,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: - open Microsoft.WindowsAzure.Storage.File.Protocol - open Microsoft.WindowsAzure.Storage.Shared.Protocol - - let props = FileServiceProperties() - props.HourMetrics <- MetricsProperties() - props.HourMetrics.MetricsLevel <- MetricsLevel.ServiceAndApi - props.HourMetrics.RetentionDays <- 14 |> Nullable - props.HourMetrics.Version <- "1.0" - props.MinuteMetrics <- MetricsProperties() - props.MinuteMetrics.MetricsLevel <- MetricsLevel.ServiceAndApi - props.MinuteMetrics.RetentionDays <- 7 |> Nullable - props.MinuteMetrics.Version <- "1.0" - - fileClient.SetServiceProperties(props) +[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L118-L131)] ## Next steps diff --git a/samples/snippets/fsharp/azure/file-storage.fsx b/samples/snippets/fsharp/azure/file-storage.fsx new file mode 100644 index 0000000000000..6ea0f3119d8a6 --- /dev/null +++ b/samples/snippets/fsharp/azure/file-storage.fsx @@ -0,0 +1,131 @@ +open System +open System.IO +open Microsoft.Azure // Namespace for CloudConfigurationManager +open Microsoft.WindowsAzure.Storage // Namespace for CloudStorageAccount +open Microsoft.WindowsAzure.Storage.File // Namespace for File storage types + +// +// Get your connection string. +// + +let storageConnString = "..." // fill this in from your storage account + +// Parse the connection string and return a reference to the 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() + +// +// Create a file share. +// + +let share = fileClient.GetShareReference("myFiles") +share.CreateIfNotExists() + +// +// Access the file share programmatically. +// + +let rootDir = share.GetRootDirectoryReference() +let subDir = rootDir.GetDirectoryReference("myLogs") + +if subDir.Exists() then + let file = subDir.GetFileReference("log.txt") + if file.Exists() then + file.DownloadToFile("log.txt", FileMode.Append) + +// +// Set the maximum size for a file share. +// + +// stats.Usage is current usage in GB +let stats = share.GetStats() +share.FetchAttributes() + +// Set the quota to 10 GB plus current usage +share.Properties.Quota <- stats.Usage + 10 |> Nullable +share.SetProperties() + +// Remove the quota +share.Properties.Quota <- Nullable() +share.SetProperties() + +// +// Generate a shared access signature for a file or file share. +// + +// Create a 24 hour read/write policy. +let policy = SharedAccessFilePolicy() +policy.SharedAccessExpiryTime <- + DateTimeOffset.UtcNow.AddHours(24.) |> Nullable +policy.Permissions <- + SharedAccessFilePermissions.Read ||| SharedAccessFilePermissions.Write + +// Set the policy on the share. +let permissions = share.GetPermissions() +permissions.SharedAccessPolicies.Add("policyName", policy) +share.SetPermissions(permissions) + +let file = subDir.GetFileReference("log.txt") +let sasToken = file.GetSharedAccessSignature(policy) +let sasUri = Uri(file.StorageUri.PrimaryUri.ToString() + sasToken) + +let fileSas = CloudFile(sasUri) +fileSas.UploadText("This write operation is authenticated via SAS") + +// +// Copy a file to another file. +// + +let destFile = subDir.GetFileReference("log_copy.txt") +destFile.StartCopy(file) + +// +// 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") + +let filePolicy = SharedAccessFilePolicy() +filePolicy.Permissions <- SharedAccessFilePermissions.Read +filePolicy.SharedAccessExpiryTime <- + DateTimeOffset.UtcNow.AddHours(24.) |> Nullable + +let fileSas2 = file.GetSharedAccessSignature(filePolicy) +let sasUri2 = Uri(file.StorageUri.PrimaryUri.ToString() + fileSas2) +destBlob.StartCopy(sasUri2) + +// +// Troubleshooting File storage using metrics. +// + +open Microsoft.WindowsAzure.Storage.File.Protocol +open Microsoft.WindowsAzure.Storage.Shared.Protocol + +let props = FileServiceProperties() +props.HourMetrics <- MetricsProperties() +props.HourMetrics.MetricsLevel <- MetricsLevel.ServiceAndApi +props.HourMetrics.RetentionDays <- 14 |> Nullable +props.HourMetrics.Version <- "1.0" +props.MinuteMetrics <- MetricsProperties() +props.MinuteMetrics.MetricsLevel <- MetricsLevel.ServiceAndApi +props.MinuteMetrics.RetentionDays <- 7 |> Nullable +props.MinuteMetrics.Version <- "1.0" + +fileClient.SetServiceProperties(props) From 0f8fe48615c0709f62622042248808f02a1eedd3 Mon Sep 17 00:00:00 2001 From: cartermp Date: Thu, 22 Sep 2016 14:21:48 -0700 Subject: [PATCH 16/60] Update queue storage to use script samples. --- .../using-fsharp-on-azure/queue-storage.md | 56 +++++-------------- 1 file changed, 14 insertions(+), 42 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/queue-storage.md b/docs/fsharp/using-fsharp-on-azure/queue-storage.md index 90f06ab883d01..3393abcc413f5 100644 --- a/docs/fsharp/using-fsharp-on-azure/queue-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/queue-storage.md @@ -39,9 +39,7 @@ Next, use a [package manager](package-management.md) such as Paket or NuGet to i Add the following `open` statements to the top of the `queues.fsx` file: - open Microsoft.Azure // Namespace for CloudConfigurationManager - open Microsoft.WindowsAzure.Storage // Namespace for CloudStorageAccount - open Microsoft.WindowsAzure.Storage.Queue // Namespace for Queue storage types +[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L3)] ### Get your connection string @@ -49,15 +47,13 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: - let storageConnString = "..." // fill this in from your storage account +[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L9-L13)] However, this is a **bad idea** 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: - // Parse the connection string and return a reference to the storage account. - let storageConnString = - CloudConfigurationManager.GetSetting("StorageConnectionString") +[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L13)] Using Azure Configuration Manager is optional. You can also use an API such as the .NET Framework's `ConfigurationManager` type. @@ -65,8 +61,7 @@ Using Azure Configuration Manager is optional. You can also use an API such as t To parse the connection string, use: - // Parse the connection string and return a reference to the storage account. - let storageAccount = CloudStorageAccount.Parse(storageConnString) +[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L19-L20)] This will return a `CloudStorageAccount`. @@ -74,7 +69,7 @@ This will return a `CloudStorageAccount`. The `CloudQueueClient` class enables you to retrieve queues stored in Queue storage. Here's one way to create the service client: - let queueClient = storageAccount.CreateCloudQueueClient() +[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L26)] Now you are ready to write code that reads data from and writes data to Queue storage. @@ -82,11 +77,7 @@ Now you are ready to write code that reads data from and writes data to Queue st This example shows how to create a queue if it doesn't already exist: - // Retrieve a reference to a container. - let queue = queueClient.GetQueueReference("myqueue") - - // Create the queue if it doesn't already exist - queue.CreateIfNotExists() +[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L32-L36)] ## Insert a message into a queue @@ -95,18 +86,14 @@ To insert a message into an existing queue, first create a new `CloudQueueMessage` can be created from either a string (in UTF-8 format) or a `byte` array, like this: - // Create a message and add it to the queue. - let message = new CloudQueueMessage("Hello, World") - queue.AddMessage(message); +[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L42-L44)] ## Peek at the next message You can peek at the message in the front of a queue, without removing it from the queue, by calling the `PeekMessage` method. - // Peek at the next message. - let peekedMessage = queue.PeekMessage() - let msgAsString = peekedMessage.AsString +[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L50-L52)] ## Change the contents of a queued message @@ -123,11 +110,7 @@ you would keep a retry count as well, and if the message is retried more than some number of times, you would delete it. This protects against a message that triggers an application error each time it is processed. - // Update the message contents and set a new timeout. - message.SetMessageContent("Updated contents.") - queue.UpdateMessage(message, - TimeSpan.FromSeconds(60.0), - MessageUpdateFields.Content ||| MessageUpdateFields.Visibility) +[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L58-L62)] ## De-queue the next message @@ -142,20 +125,13 @@ software failure, another instance of your code can get the same message and try again. Your code calls `DeleteMessage` right after the message has been processed. - // Process the message in less than 30 seconds, and then delete the message. - queue.DeleteMessage(message) +[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L68-L69)] ## Use Async-Await pattern with common Queue storage APIs This example shows how to use an async workflow with common Queue storage APIs. - async { - let! exists = queue.CreateIfNotExistsAsync() |> Async.AwaitTask - let msg = new CloudQueueMessage("My message") - queue.AddMessageAsync(msg) |> Async.AwaitTask - let! retrieved = queue.GetMessageAsync() |> Async.AwaitTask - queue.DeleteMessageAsync(retrieved) |> Async.AwaitTask - } +[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L75-L81)] ## Additional options for de-queuing messages @@ -169,24 +145,20 @@ each message. Note that the 5 minutes starts for all messages at the same time, so after 5 minutes have passed since the call to `GetMessages`, any messages which have not been deleted will become visible again. - for msg in queue.GetMessages(20, Nullable(TimeSpan.FromMinutes(5.))) do - // Process the message here. - queue.DeleteMessage(msg) +[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L87-L89)] ## Get the queue length You can get an estimate of the number of messages in a queue. The `FetchAttributes` method asks the Queue service to retrieve the queue attributes, including the message count. The `ApproximateMessageCount` property returns the last value retrieved by the `FetchAttributes` method, without calling the Queue service. - queue.FetchAttributes() - let count = queue.ApproximateMessageCount.GetValueOrDefault() +[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L95-L96)] ## Delete a queue To delete a queue and all the messages contained in it, call the `Delete` method on the queue object. - // Delete the queue. - queue.Delete() +[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L102-L103)] ## Next steps From fa379854661b41ea38e01c2df0d2ff7d17b2abf3 Mon Sep 17 00:00:00 2001 From: cartermp Date: Thu, 22 Sep 2016 14:36:35 -0700 Subject: [PATCH 17/60] Update table storage to use script samples. --- .../using-fsharp-on-azure/table-storage.md | 115 ++---------- .../snippets/fsharp/azure/queue-storage.fsx | 103 +++++++++++ .../snippets/fsharp/azure/table-storage.fsx | 174 ++++++++++++++++++ 3 files changed, 295 insertions(+), 97 deletions(-) create mode 100644 samples/snippets/fsharp/azure/queue-storage.fsx create mode 100644 samples/snippets/fsharp/azure/table-storage.fsx diff --git a/docs/fsharp/using-fsharp-on-azure/table-storage.md b/docs/fsharp/using-fsharp-on-azure/table-storage.md index 985b4171c04b5..34afbfe74f22c 100644 --- a/docs/fsharp/using-fsharp-on-azure/table-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -41,11 +41,7 @@ Next, use a [package manager](package-management.md) such as Paket or NuGet to i Add the following `open` statements to the top of the `blobs.fsx` file: - open System - open System.IO - open Microsoft.Azure // Namespace for CloudConfigurationManager - open Microsoft.WindowsAzure.Storage // Namespace for CloudStorageAccount - open Microsoft.WindowsAzure.Storage.Table // Namespace for Table storage types +[!code-fsharp[TableStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L5)] ### Get your connection string @@ -53,15 +49,13 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: - let storageConnString = "..." // fill this in from your storage account +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L11)] However, this is a **bad idea** 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: - // Parse the connection string and return a reference to the storage account. - let storageConnString = - CloudConfigurationManager.GetSetting("StorageConnectionString") +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L13-L15)] Using Azure Configuration Manager is optional. You can also use an API such as the .NET Framework's `ConfigurationManager` type. @@ -69,8 +63,7 @@ Using Azure Configuration Manager is optional. You can also use an API such as t To parse the connection string, use: - // Parse the connection string and return a reference to the storage account. - let storageAccount = CloudStorageAccount.Parse(storageConnString) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L21-L22)] This will return a `CloudStorageAccount`. @@ -78,8 +71,7 @@ This will return a `CloudStorageAccount`. The `CloudTableClient` class enables you to retrieve tables and entities stored in Table storage. Here's one way to create the service client: - // Create the table client. - let tableClient = storageAccount.CreateCloudTableClient() +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L28-L29)] Now you are ready to write code that reads data from and writes data to Table storage. @@ -87,11 +79,7 @@ Now you are ready to write code that reads data from and writes data to Table st This example shows how to create a table if it does not already exist: - // Retrieve a reference to the table. - let table = tableClient.GetTableReference("people") - - // Create the table if it doesn't exist. - table.CreateIfNotExists() +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L35-L39)] ## Add an entity to a table @@ -101,20 +89,11 @@ An entity's partition and row key uniquely identify the entity in the table. Ent Here's an example of a `Customer` that uses the `lastName` as the partition key and the `firstName` as the row key. - type Customer - (firstName, lastName, email: string, phone: string) = - inherit TableEntity(lastName, firstName) - new() = Customer(null, null, null, null) - member val Email = email with get, set - member val PhoneNumber = phone with get, set - - let customer = - Customer("Larry", "Buster", "larry@example.com", "425-555-0101") +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L45-L53)] Now we'll add our `Customer` to the table. To do so, we create a `TableOperation` that we will execute on the table. In this case, we create an `Insert` operation. - let insertOp = TableOperation.Insert(customer) - table.Execute(insertOp) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L55-L56)] ## Insert a batch of entities @@ -127,119 +106,61 @@ You can insert a batch of entities into a table using a single write operation. Here's some code that combines two inserts into a batch operation: - let customer2 = - Customer("Bob", "Boomer", "bob@example.com", "425-555-0102") - - let batchOp = TableBatchOperation() - batchOp.Insert(customer) - batchOp.Insert(customer2) - table.ExecuteBatch(batchOp) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L62-L68)] ## Retrieve all entities in a partition To query a table for all entities in a partition, use a `TableQuery` object. Here, we filter for entities where "Buster" is the partition key. - let query = - TableQuery().Where( - TableQuery.GenerateFilterCondition( - "PartitionKey", QueryComparisons.Equal, "Buster")) - - let result = table.ExecuteQuery(query) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L74-L79)] ## Retrieve a range of entities in a partition If you don't want to query all the entities in a partition, you can specify a range by combining the partition key filter with a row key filter. Here, we use two filters to get all entities in the "Buster" partition where the row key (first name) starts with a letter earlier than "M" in the alphabet. - let range = - TableQuery().Where( - TableQuery.CombineFilters( - TableQuery.GenerateFilterCondition( - "PartitionKey", QueryComparisons.Equal, "Buster"), - TableOperators.And, - TableQuery.GenerateFilterCondition( - "RowKey", QueryComparisons.LessThan, "M"))) - - let rangeResult = table.ExecuteQuery(query) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L85-L94)] ## Retrieve a single entity You can write a query to retrieve a single, specific entity. Here, we use a `TableOperation` to specify the customer "Larry Buster". Instead of a collection, we get back a `Customer`. Specifying both the partition key and the row key in a query is the fastest way to retrieve a single entity from the Table service. - let retrieveOp = TableOperation.Retrieve("Buster", "Larry") - let retrieveResult = table.Execute(retrieveOp) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L100-L101)] ## Replace an entity To update an entity, retrieve it from the Table service, modify the entity object, and then save the changes back to the Table service using a `Replace` operation. This causes the entity to be fully replaced on the server, unless the entity on the server has changed since it was retrieved, in which case the operation will fail. This failure is to prevent your application from inadvertently overwriting changes from other sources. - try - let customer = retrieveResult.Result :?> Customer - customer.PhoneNumber <- "425-555-0103" - let replaceOp = TableOperation.Replace(customer) - table.Execute(replaceOp) |> ignore - with e -> - Console.WriteLine("Update failed") +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L107-L113)] ## Insert-or-replace an entity Sometimes, you don't know if the entity exists in the table or not. And if it does, the current values stored in it are no longer needed. We can use `InsertOrReplace` to create the entity, or replace it if it exists, regardless of its state. - try - customer.PhoneNumber <- "425-555-0104" - let replaceOp = TableOperation.InsertOrReplace(customer) - table.Execute(replaceOp) |> ignore - with e -> - Console.WriteLine("Update failed") +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L119-L124)] ## Query a subset of entity properties A table query can retrieve just a few properties from an entity instead of all of them. This technique, called projection, can improve query performance, especially for large entities. Here, we return only email addresses using `DynamicTableEntity` and `EntityResolver`. Note that projection is not supported on the local storage emulator, so this code runs only when you're using an account on the Table service. - // Define the query, and select only the Email property. - let projectionQ = TableQuery().Select([|"Email"|]) - - // Define an entity resolver to work with the entity after retrieval. - let resolver = EntityResolver(fun pk rk ts props etag -> - if props.ContainsKey("Email") then - props.["Email"].StringValue - else - null - ) - - table.ExecuteQuery(projectionQ, resolver, null, null) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L130-L141)] ## Delete an entity You can delete an entity after you have retrieved it. As with updating an entity, this will fail if the entity has changed since you retrieved it. - let deleteOp = TableOperation.Delete(customer) - table.Execute(deleteOp) +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L147-L148)] ## Delete a table You can delete a table from a storage account. A table that has been deleted will be unavailable to be re-created for a period of time following the deletion. - table.DeleteIfExists() +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L154)] ## Retrieve entities in pages asynchronously If you are reading a large number of entities, and you want to process them as they are retrieved rather than waiting for them all to return, you can use a segmented query. Here, we return results in pages by using an async workflow so that execution is not blocked while you're waiting for a large set of results to return. - let tableQ = TableQuery() - - async { - let rec q (cont: TableContinuationToken) = async { - let! result = - table.ExecuteQuerySegmentedAsync(tableQ, cont) - |> Async.AwaitTask - - // Process the result here. - match result.ContinuationToken with - | null -> return () - | cont -> q cont |> Async.RunSynchronously - } - q null |> Async.RunSynchronously - } |> Async.RunSynchronously +[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L160-L174)] ## Next steps diff --git a/samples/snippets/fsharp/azure/queue-storage.fsx b/samples/snippets/fsharp/azure/queue-storage.fsx new file mode 100644 index 0000000000000..25eb9adeb59f6 --- /dev/null +++ b/samples/snippets/fsharp/azure/queue-storage.fsx @@ -0,0 +1,103 @@ +open Microsoft.Azure // Namespace for CloudConfigurationManager +open Microsoft.WindowsAzure.Storage // Namespace for CloudStorageAccount +open Microsoft.WindowsAzure.Storage.Queue // Namespace for Queue storage types + +// +// Get your connection string. +// + +let storageConnString = "..." // fill this in from your storage account + +// Parse the connection string and return a reference to the 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 Queue Service client. +// + +let queueClient = storageAccount.CreateCloudQueueClient() + +// +// Create a queue. +// + +// Retrieve a reference to a container. +let queue = queueClient.GetQueueReference("myqueue") + +// Create the queue if it doesn't already exist +queue.CreateIfNotExists() + +// +// Insert a message into a queue. +// + +// Create a message and add it to the queue. +let message = new CloudQueueMessage("Hello, World") +queue.AddMessage(message) + +// +// Peek at the next message. +// + +// Peek at the next message. +let peekedMessage = queue.PeekMessage() +let msgAsString = peekedMessage.AsString + +// +// Change the contents of a queued message. +// + +// Update the message contents and set a new timeout. +message.SetMessageContent("Updated contents.") +queue.UpdateMessage(message, + TimeSpan.FromSeconds(60.0), + MessageUpdateFields.Content ||| MessageUpdateFields.Visibility) + +// +// De-queue the next message. +// + +// Process the message in less than 30 seconds, and then delete the message. +queue.DeleteMessage(message) + +// +// Use Async-Await pattern with common Queue storage APIs. +// + +async { + let! exists = queue.CreateIfNotExistsAsync() |> Async.AwaitTask + let msg = new CloudQueueMessage("My message") + queue.AddMessageAsync(msg) |> Async.AwaitTask + let! retrieved = queue.GetMessageAsync() |> Async.AwaitTask + queue.DeleteMessageAsync(retrieved) |> Async.AwaitTask +} + +// +// Additional options for de-queuing messages. +// + +for msg in queue.GetMessages(20, Nullable(TimeSpan.FromMinutes(5.))) do + // Process the message here. + queue.DeleteMessage(msg) + +// +// Get the queue length. +// + +queue.FetchAttributes() +let count = queue.ApproximateMessageCount.GetValueOrDefault() + +// +// Delete a queue. +// + +// Delete the queue. +queue.Delete() diff --git a/samples/snippets/fsharp/azure/table-storage.fsx b/samples/snippets/fsharp/azure/table-storage.fsx new file mode 100644 index 0000000000000..5a2567698dbf3 --- /dev/null +++ b/samples/snippets/fsharp/azure/table-storage.fsx @@ -0,0 +1,174 @@ +open System +open System.IO +open Microsoft.Azure // Namespace for CloudConfigurationManager +open Microsoft.WindowsAzure.Storage // Namespace for CloudStorageAccount +open Microsoft.WindowsAzure.Storage.Table // Namespace for Table storage types + +// +// Get your connection string. +// + +let storageConnString = "..." // fill this in from your storage account + +// Parse the connection string and return a reference to the 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 Table service client. +// + +// Create the table client. +let tableClient = storageAccount.CreateCloudTableClient() + +// +// Create a table. +// + +// Retrieve a reference to the table. +let table = tableClient.GetTableReference("people") + +// Create the table if it doesn't exist. +table.CreateIfNotExists() + +// +// Add an entity to a table. +// + +type Customer + (firstName, lastName, email: string, phone: string) = + inherit TableEntity(lastName, firstName) + new() = Customer(null, null, null, null) + member val Email = email with get, set + member val PhoneNumber = phone with get, set + +let customer = + Customer("Larry", "Buster", "larry@example.com", "425-555-0101") + +let insertOp = TableOperation.Insert(customer) +table.Execute(insertOp) + +// +// Insert a batch of entities. +// + +let customer2 = + Customer("Bob", "Boomer", "bob@example.com", "425-555-0102") + +let batchOp = TableBatchOperation() +batchOp.Insert(customer) +batchOp.Insert(customer2) +table.ExecuteBatch(batchOp) + +// +// Retreive all entities in a partition. +// + +let query = + TableQuery().Where( + TableQuery.GenerateFilterCondition( + "PartitionKey", QueryComparisons.Equal, "Buster")) + +let result = table.ExecuteQuery(query) + +// +// Retrieve a range of entities in a partition. +// + +let range = + TableQuery().Where( + TableQuery.CombineFilters( + TableQuery.GenerateFilterCondition( + "PartitionKey", QueryComparisons.Equal, "Buster"), + TableOperators.And, + TableQuery.GenerateFilterCondition( + "RowKey", QueryComparisons.LessThan, "M"))) + +let rangeResult = table.ExecuteQuery(query) + +// +// Retrieve a single entity. +// + +let retrieveOp = TableOperation.Retrieve("Buster", "Larry") +let retrieveResult = table.Execute(retrieveOp) + +// +// Replace an entity. +// + +try + let customer = retrieveResult.Result :?> Customer + customer.PhoneNumber <- "425-555-0103" + let replaceOp = TableOperation.Replace(customer) + table.Execute(replaceOp) |> ignore +with e -> + Console.WriteLine("Update failed") + +// +// Insert-or-update an entity. +// + +try + customer.PhoneNumber <- "425-555-0104" + let replaceOp = TableOperation.InsertOrReplace(customer) + table.Execute(replaceOp) |> ignore +with e -> + Console.WriteLine("Update failed") + +// +// Query a subset of entity properties. +// + +// Define the query, and select only the Email property. +let projectionQ = TableQuery().Select([|"Email"|]) + +// Define an entity resolver to work with the entity after retrieval. +let resolver = EntityResolver(fun pk rk ts props etag -> + if props.ContainsKey("Email") then + props.["Email"].StringValue + else + null + ) + +table.ExecuteQuery(projectionQ, resolver, null, null) + +// +// Delete an entity. +// + +let deleteOp = TableOperation.Delete(customer) +table.Execute(deleteOp) + +// +// Delete a table. +// + +table.DeleteIfExists() + +// +// Retrieve entities in pages asynchronously. +// + +let tableQ = TableQuery() + +async { + let rec q (cont: TableContinuationToken) = async { + let! result = + table.ExecuteQuerySegmentedAsync(tableQ, cont) + |> Async.AwaitTask + + // Process the result here. + match result.ContinuationToken with + | null -> return () + | cont -> q cont |> Async.RunSynchronously + } + q null |> Async.RunSynchronously +} |> Async.RunSynchronously From a4e176b431dafbec4dc5c15d9e2d40e26ed91c0f Mon Sep 17 00:00:00 2001 From: cartermp Date: Thu, 22 Sep 2016 14:37:30 -0700 Subject: [PATCH 18/60] Adjust NOTE --- .../using-fsharp-on-azure-service-fabric.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/using-fsharp-on-azure-service-fabric.md b/docs/fsharp/using-fsharp-on-azure/using-fsharp-on-azure-service-fabric.md index f4ebc8f4a0339..0bb533ef8c1de 100644 --- a/docs/fsharp/using-fsharp-on-azure/using-fsharp-on-azure-service-fabric.md +++ b/docs/fsharp/using-fsharp-on-azure/using-fsharp-on-azure-service-fabric.md @@ -1,4 +1,3 @@ # Using F# on Azure Service Fabric -> [!NOTE] -This is still in progress. \ No newline at end of file +> [!NOTE] This is still in progress. \ No newline at end of file From 9352d06aeb3480a81d7534ca78e14a8e32caa1c6 Mon Sep 17 00:00:00 2001 From: Sylvan Clebsch Date: Mon, 26 Sep 2016 15:27:38 +0100 Subject: [PATCH 19/60] Fix relative path to .fsx snippets --- .../using-fsharp-on-azure/blob-storage.md | 36 +++++++++---------- .../using-fsharp-on-azure/file-storage.md | 24 ++++++------- .../using-fsharp-on-azure/queue-storage.md | 28 +++++++-------- .../using-fsharp-on-azure/table-storage.md | 36 +++++++++---------- 4 files changed, 62 insertions(+), 62 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/blob-storage.md b/docs/fsharp/using-fsharp-on-azure/blob-storage.md index 67136a614a649..6123ea1cd246d 100644 --- a/docs/fsharp/using-fsharp-on-azure/blob-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/blob-storage.md @@ -39,7 +39,7 @@ Next, use a [package manager](package-management.md) such as Paket or NuGet to i Add the following `open` statements to the top of the `blobs.fsx` file: -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L5)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L5)] ### Get your connection string @@ -47,13 +47,13 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L11)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11)] However, this is a **bad idea** 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[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L13-L15)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L13-L15)] Using Azure Configuration Manager is optional. You can also use an API such as the .NET Framework's `ConfigurationManager` type. @@ -61,7 +61,7 @@ Using Azure Configuration Manager is optional. You can also use an API such as t To parse the connection string, use: -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L21-L22)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L21-L22)] This will return a `CloudStorageAccount`. @@ -69,13 +69,13 @@ This will return a `CloudStorageAccount`. Before we begin, create some dummy local data in the directory of our script. Later you will upload this data. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L28-L30)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L28-L30)] ### Create the Blob service client The `CloudBlobClient` type enables you to retrieve containers and blobs stored in Blob storage. Here's one way to create the service client: -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L36)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L36)] Now you are ready to write code that reads data from and writes data to Blob storage. @@ -83,11 +83,11 @@ Now you are ready to write code that reads data from and writes data to Blob sto This example shows how to create a container if it does not already exist: -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L42-L46)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L42-L46)] By default, the new container is private, meaning that you must specify your storage access key to download blobs from this container. If you want to make the files within the container available to everyone, you can set the container to be public using the following code: -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L48-L49)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L48-L49)] Anyone on the Internet can see blobs in a public container, but you can modify or delete them only if you have the appropriate account access key or a shared access signature. @@ -97,13 +97,13 @@ Azure Blob Storage supports block blobs and page blobs. In the majority of cases To upload a file to a block blob, get a container reference and use it to get a block blob reference. Once you have a blob reference, you can upload any stream of data to it by calling the `UploadFromStream` method. This operation will create the blob if it didn't previously exist, or overwrite it if it does exist. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L55-L61)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L55-L61)] ## List the blobs in a container To list the blobs in a container, first get a container reference. You can then use the container's `ListBlobs` method to retrieve the blobs and/or directories within it. To access the rich set of properties and methods for a returned `IListBlobItem`, you must cast it to a `CloudBlockBlob`, `CloudPageBlob`, or `CloudBlobDirectory` object. If the type is unknown, you can use a type check to determine which to cast it to. The following code demonstrates how to retrieve and output the URI of each item in the `mydata` container: -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L67-L80)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L67-L80)] As shown above, you can name blobs with path information in their names. This creates a virtual directory structure that you can organize and traverse as you would a traditional file system. Note that the directory structure is virtual only - the only resources available in Blob storage are containers and blobs. However, the storage client library offers a `CloudBlobDirectory` object to refer to a virtual directory and simplify the process of working with blobs that are organized in this way. @@ -127,7 +127,7 @@ When you call `ListBlobs` on the 'photos' container (as in the above sample), a Optionally, you can set the `UseFlatBlobListing` parameter of of the `ListBlobs` method to `true`. In this case, every blob in the container is returned as a `CloudBlockBlob` object. The call to `ListBlobs` to return a flat listing looks like this: -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L82-L89)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L82-L89)] and, depending on the current contents of your container, the results look like this: @@ -145,18 +145,18 @@ and, depending on the current contents of your container, the results look like To download blobs, first retrieve a blob reference and then call the `DownloadToStream` method. The following example uses the `DownloadToStream` method to transfer the blob contents to a stream object that you can then persist to a local file. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L95-L101)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L95-L101)] You can also use the `DownloadToStream` method to download the contents of a blob as a text string. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L103-L106)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L103-L106)] ## Delete blobs To delete a blob, first get a blob reference and then call the `Delete` method on it. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L112-L116)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L112-L116)] ## List blobs in pages asynchronously @@ -166,16 +166,16 @@ This example shows a flat blob listing, but you can also perform a hierarchical Because the sample method calls an asynchronous method, it must be prefaced with the `async` keyword, and it must return a `Task` object. The await keyword specified for the `ListBlobsSegmentedAsync` method suspends execution of the sample method until the listing task completes. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L122-L160)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L122-L160)] We can now use this asynchronous routine as follows. First we upload some dummy data (using the local file created earlier in this tutorial). -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L162-L166)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L162-L166)] Now, call the routine. We use ``Async.RunSynchronously`` to force the execution of the asynchronous operation. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L168)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L168)] ## Writing to an append blob @@ -185,7 +185,7 @@ Each block in an append blob can be a different size, up to a maximum of 4 MB, a The example below creates a new append blob and appends some data to it, simulating a simple logging operation. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L174-L203)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L174-L203)] See [Understanding Block Blobs, Page Blobs, and Append Blobs](https://msdn.microsoft.com/library/azure/ee691964.aspx) for more information about the differences between the three types of blobs. diff --git a/docs/fsharp/using-fsharp-on-azure/file-storage.md b/docs/fsharp/using-fsharp-on-azure/file-storage.md index f22b3f5769976..6319520f5d093 100644 --- a/docs/fsharp/using-fsharp-on-azure/file-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/file-storage.md @@ -35,7 +35,7 @@ Next, use a [package manager](package-management.md) such as Paket or NuGet to i Add the following `open` statements to the top of the `blobs.fsx` file: -[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L5)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L5)] ### Get your connection string @@ -43,13 +43,13 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: -[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L11)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11)] However, this is a **bad idea** 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/blob-storage.fsx#L13-L15)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L13-L15)] Using Azure Configuration Manager is optional. You can also use an API such as the .NET Framework's `ConfigurationManager` type. @@ -57,7 +57,7 @@ Using Azure Configuration Manager is optional. You can also use an API such as t To parse the connection string, use: -[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L21-L22)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L21-L22)] This will return a `CloudStorageAccount`. @@ -65,7 +65,7 @@ This will return a `CloudStorageAccount`. The `CloudFileClient` 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/blob-storage.fsx#L28)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L28)] Now you are ready to write code that reads data from and writes data to Blob storage. @@ -73,19 +73,19 @@ Now you are ready to write code that reads data from and writes data to Blob sto This example shows how to create a file share if it does not already exist: -[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L34-L35)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L34-L35)] ### Access the file share programmatically Here, we get the root directory and get a sub-directory of the root. If the sub-directory exists, we get a file in the sub-directory, and if that exists too, we download the file, appending the contents to a local file. -[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L41-L47)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L41-L47)] ### 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. -[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L53-L63)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L53-L63)] ### Generate a shared access signature for a file or file share @@ -93,7 +93,7 @@ You can generate a shared access signature (SAS) for a file share or for an indi Here, we 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. -[!code-fsharp[FileStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L69-L86)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L69-L86)] For more information about creating and using shared access signatures, see [Using Shared Access Signatures (SAS)](https://azure.microsoft.com/en-gb/documentation/articles/storage-dotnet-shared-access-signature-part-1/) and [Create and use a SAS with Blob storage](https://azure.microsoft.com/en-gb/documentation/articles/storage-dotnet-shared-access-signature-part-2/). @@ -105,13 +105,13 @@ You can copy a file to another file, a file to a blob, or a blob to a file. If y Here, we 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/blob-storage.fsx#L92-L93)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L92-L93)] ### Copy a file to a blob Here, we create a file and copy it to a blob within the same storage account. We 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/blob-storage.fsx#L99-L112)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L99-L112)] 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. @@ -121,7 +121,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/blob-storage.fsx#L118-L131)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L118-L131)] ## Next steps diff --git a/docs/fsharp/using-fsharp-on-azure/queue-storage.md b/docs/fsharp/using-fsharp-on-azure/queue-storage.md index 3393abcc413f5..0255f2846e5e5 100644 --- a/docs/fsharp/using-fsharp-on-azure/queue-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/queue-storage.md @@ -39,7 +39,7 @@ Next, use a [package manager](package-management.md) such as Paket or NuGet to i Add the following `open` statements to the top of the `queues.fsx` file: -[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L3)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L3)] ### Get your connection string @@ -47,13 +47,13 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: -[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L9-L13)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L9-L13)] However, this is a **bad idea** 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[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L13)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L13)] Using Azure Configuration Manager is optional. You can also use an API such as the .NET Framework's `ConfigurationManager` type. @@ -61,7 +61,7 @@ Using Azure Configuration Manager is optional. You can also use an API such as t To parse the connection string, use: -[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L19-L20)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L19-L20)] This will return a `CloudStorageAccount`. @@ -69,7 +69,7 @@ This will return a `CloudStorageAccount`. The `CloudQueueClient` class enables you to retrieve queues stored in Queue storage. Here's one way to create the service client: -[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L26)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L26)] Now you are ready to write code that reads data from and writes data to Queue storage. @@ -77,7 +77,7 @@ Now you are ready to write code that reads data from and writes data to Queue st This example shows how to create a queue if it doesn't already exist: -[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L32-L36)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L32-L36)] ## Insert a message into a queue @@ -86,14 +86,14 @@ To insert a message into an existing queue, first create a new `CloudQueueMessage` can be created from either a string (in UTF-8 format) or a `byte` array, like this: -[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L42-L44)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L42-L44)] ## Peek at the next message You can peek at the message in the front of a queue, without removing it from the queue, by calling the `PeekMessage` method. -[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L50-L52)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L50-L52)] ## Change the contents of a queued message @@ -110,7 +110,7 @@ you would keep a retry count as well, and if the message is retried more than some number of times, you would delete it. This protects against a message that triggers an application error each time it is processed. -[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L58-L62)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L58-L62)] ## De-queue the next message @@ -125,13 +125,13 @@ software failure, another instance of your code can get the same message and try again. Your code calls `DeleteMessage` right after the message has been processed. -[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L68-L69)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L68-L69)] ## Use Async-Await pattern with common Queue storage APIs This example shows how to use an async workflow with common Queue storage APIs. -[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L75-L81)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L75-L81)] ## Additional options for de-queuing messages @@ -145,20 +145,20 @@ each message. Note that the 5 minutes starts for all messages at the same time, so after 5 minutes have passed since the call to `GetMessages`, any messages which have not been deleted will become visible again. -[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L87-L89)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L87-L89)] ## Get the queue length You can get an estimate of the number of messages in a queue. The `FetchAttributes` method asks the Queue service to retrieve the queue attributes, including the message count. The `ApproximateMessageCount` property returns the last value retrieved by the `FetchAttributes` method, without calling the Queue service. -[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L95-L96)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L95-L96)] ## Delete a queue To delete a queue and all the messages contained in it, call the `Delete` method on the queue object. -[!code-fsharp[QueueStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L102-L103)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L102-L103)] ## Next steps diff --git a/docs/fsharp/using-fsharp-on-azure/table-storage.md b/docs/fsharp/using-fsharp-on-azure/table-storage.md index 34afbfe74f22c..3c13bb0c4e2db 100644 --- a/docs/fsharp/using-fsharp-on-azure/table-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -41,7 +41,7 @@ Next, use a [package manager](package-management.md) such as Paket or NuGet to i Add the following `open` statements to the top of the `blobs.fsx` file: -[!code-fsharp[TableStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L5)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L5)] ### Get your connection string @@ -49,13 +49,13 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L11)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11)] However, this is a **bad idea** 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[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L13-L15)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L13-L15)] Using Azure Configuration Manager is optional. You can also use an API such as the .NET Framework's `ConfigurationManager` type. @@ -63,7 +63,7 @@ Using Azure Configuration Manager is optional. You can also use an API such as t To parse the connection string, use: -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L21-L22)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L21-L22)] This will return a `CloudStorageAccount`. @@ -71,7 +71,7 @@ This will return a `CloudStorageAccount`. The `CloudTableClient` class enables you to retrieve tables and entities stored in Table storage. Here's one way to create the service client: -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L28-L29)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L28-L29)] Now you are ready to write code that reads data from and writes data to Table storage. @@ -79,7 +79,7 @@ Now you are ready to write code that reads data from and writes data to Table st This example shows how to create a table if it does not already exist: -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L35-L39)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L35-L39)] ## Add an entity to a table @@ -89,11 +89,11 @@ An entity's partition and row key uniquely identify the entity in the table. Ent Here's an example of a `Customer` that uses the `lastName` as the partition key and the `firstName` as the row key. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L45-L53)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L45-L53)] Now we'll add our `Customer` to the table. To do so, we create a `TableOperation` that we will execute on the table. In this case, we create an `Insert` operation. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L55-L56)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L55-L56)] ## Insert a batch of entities @@ -106,61 +106,61 @@ You can insert a batch of entities into a table using a single write operation. Here's some code that combines two inserts into a batch operation: -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L62-L68)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L62-L68)] ## Retrieve all entities in a partition To query a table for all entities in a partition, use a `TableQuery` object. Here, we filter for entities where "Buster" is the partition key. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L74-L79)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L74-L79)] ## Retrieve a range of entities in a partition If you don't want to query all the entities in a partition, you can specify a range by combining the partition key filter with a row key filter. Here, we use two filters to get all entities in the "Buster" partition where the row key (first name) starts with a letter earlier than "M" in the alphabet. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L85-L94)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L85-L94)] ## Retrieve a single entity You can write a query to retrieve a single, specific entity. Here, we use a `TableOperation` to specify the customer "Larry Buster". Instead of a collection, we get back a `Customer`. Specifying both the partition key and the row key in a query is the fastest way to retrieve a single entity from the Table service. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L100-L101)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L100-L101)] ## Replace an entity To update an entity, retrieve it from the Table service, modify the entity object, and then save the changes back to the Table service using a `Replace` operation. This causes the entity to be fully replaced on the server, unless the entity on the server has changed since it was retrieved, in which case the operation will fail. This failure is to prevent your application from inadvertently overwriting changes from other sources. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L107-L113)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L107-L113)] ## Insert-or-replace an entity Sometimes, you don't know if the entity exists in the table or not. And if it does, the current values stored in it are no longer needed. We can use `InsertOrReplace` to create the entity, or replace it if it exists, regardless of its state. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L119-L124)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L119-L124)] ## Query a subset of entity properties A table query can retrieve just a few properties from an entity instead of all of them. This technique, called projection, can improve query performance, especially for large entities. Here, we return only email addresses using `DynamicTableEntity` and `EntityResolver`. Note that projection is not supported on the local storage emulator, so this code runs only when you're using an account on the Table service. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L130-L141)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L130-L141)] ## Delete an entity You can delete an entity after you have retrieved it. As with updating an entity, this will fail if the entity has changed since you retrieved it. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L147-L148)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L147-L148)] ## Delete a table You can delete a table from a storage account. A table that has been deleted will be unavailable to be re-created for a period of time following the deletion. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L154)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L154)] ## Retrieve entities in pages asynchronously If you are reading a large number of entities, and you want to process them as they are retrieved rather than waiting for them all to return, you can use a segmented query. Here, we return results in pages by using an async workflow so that execution is not blocked while you're waiting for a large set of results to return. -[!code-fsharp[BlobStorage](../../samples/snippets/fsharp/azure/blob-storage.fsx#L160-L174)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L160-L174)] ## Next steps From 6f9069a6a3cff7842d2ad93e92d6b162f6804258 Mon Sep 17 00:00:00 2001 From: Sylvan Clebsch Date: Mon, 26 Sep 2016 16:22:54 +0100 Subject: [PATCH 20/60] Fix Open Publishing warnings and errors --- docs/fsharp/using-fsharp-on-azure/blob-storage.md | 8 ++++---- docs/fsharp/using-fsharp-on-azure/file-storage.md | 6 +++--- docs/fsharp/using-fsharp-on-azure/index.md | 3 ++- docs/fsharp/using-fsharp-on-azure/package-management.md | 2 +- docs/fsharp/using-fsharp-on-azure/queue-storage.md | 4 ++-- docs/fsharp/using-fsharp-on-azure/table-storage.md | 6 +++--- .../using-fsharp-on-azure-service-fabric.md | 3 ++- 7 files changed, 17 insertions(+), 15 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/blob-storage.md b/docs/fsharp/using-fsharp-on-azure/blob-storage.md index 6123ea1cd246d..14939872b1657 100644 --- a/docs/fsharp/using-fsharp-on-azure/blob-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/blob-storage.md @@ -2,7 +2,7 @@ title: Get started with Azure Blob storage using F# description: Store unstructured data in the cloud with Azure Blob storage. keywords: visual f#, f#, functional programming, .NET, .NET Core, Azure -author: syclebsc +author: sylvanc manager: jbronsk ms.date: 09/20/2016 ms.topic: article @@ -47,7 +47,7 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L11)] However, this is a **bad idea** 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. @@ -75,7 +75,7 @@ Before we begin, create some dummy local data in the directory of our script. La The `CloudBlobClient` type enables you to retrieve containers and blobs stored in Blob storage. Here's one way to create the service client: -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L36)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L36-L36)] Now you are ready to write code that reads data from and writes data to Blob storage. @@ -175,7 +175,7 @@ file created earlier in this tutorial). Now, call the routine. We use ``Async.RunSynchronously`` to force the execution of the asynchronous operation. -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L168)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L168-L168)] ## Writing to an append blob diff --git a/docs/fsharp/using-fsharp-on-azure/file-storage.md b/docs/fsharp/using-fsharp-on-azure/file-storage.md index 6319520f5d093..79efb9bd62f46 100644 --- a/docs/fsharp/using-fsharp-on-azure/file-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/file-storage.md @@ -2,7 +2,7 @@ title: Get started with Azure File storage using F# description: Store file data in the cloud with Azure File storage, and mount your cloud file share from an Azure virtual machine (VM) or from an on-premises application running Windows. keywords: visual f#, f#, functional programming, .NET, .NET Core, Azure -author: syclebsc +author: sylvanc manager: jbronsk ms.date: 09/20/2016 ms.topic: article @@ -43,7 +43,7 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: -[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L11)] However, this is a **bad idea** 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. @@ -65,7 +65,7 @@ This will return a `CloudStorageAccount`. The `CloudFileClient` 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/blob-storage.fsx#L28)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L28-L28)] Now you are ready to write code that reads data from and writes data to Blob storage. diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index d8656e4df9d5d..5f9d1f7e39eb8 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -19,7 +19,8 @@ F# is a superb language for cloud programming and is frequently used to write we In the sections below, you will find resources on how to use a range of Azure services with F#. -> [!NOTE] If a particular Azure service doesn't have documentation below, please consult the C# documentation for that service. Some Azure services are entirely language-independent systems services and require no language-specific documentation, and in this case are not listed here. +> [!NOTE] +> If a particular Azure service doesn't have documentation below, please consult the C# documentation for that service. Some Azure services are entirely language-independent systems services and require no language-specific documentation, and in this case are not listed here. ## Using Azure Storage with F# diff --git a/docs/fsharp/using-fsharp-on-azure/package-management.md b/docs/fsharp/using-fsharp-on-azure/package-management.md index 587ed0365021a..256f9145e7594 100644 --- a/docs/fsharp/using-fsharp-on-azure/package-management.md +++ b/docs/fsharp/using-fsharp-on-azure/package-management.md @@ -2,7 +2,7 @@ title: Using Package Management with F# for Azure description: Use Paket or Nuget to manage F# Azure dependencies keywords: visual f#, f#, functional programming, .NET, .NET Core, Azure -author: syclebsc +author: sylvanc manager: jbronsk ms.date: 09/20/2016 ms.topic: article diff --git a/docs/fsharp/using-fsharp-on-azure/queue-storage.md b/docs/fsharp/using-fsharp-on-azure/queue-storage.md index 0255f2846e5e5..1892e9b69115c 100644 --- a/docs/fsharp/using-fsharp-on-azure/queue-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/queue-storage.md @@ -2,7 +2,7 @@ title: Get started with Azure Queue storage using F# description: Azure Queues provide reliable, asynchronous messaging between application components. Cloud messaging enables your application components to scale independently. keywords: visual f#, f#, functional programming, .NET, .NET Core, Azure -author: syclebsc +author: sylvanc manager: jbronsk ms.date: 09/20/2016 ms.topic: article @@ -69,7 +69,7 @@ This will return a `CloudStorageAccount`. The `CloudQueueClient` class enables you to retrieve queues stored in Queue storage. Here's one way to create the service client: -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L26)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L26-L26)] Now you are ready to write code that reads data from and writes data to Queue storage. diff --git a/docs/fsharp/using-fsharp-on-azure/table-storage.md b/docs/fsharp/using-fsharp-on-azure/table-storage.md index 3c13bb0c4e2db..56cf88038501b 100644 --- a/docs/fsharp/using-fsharp-on-azure/table-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -2,7 +2,7 @@ title: Get started with Azure Table storage using F# description: Store structured data in the cloud using Azure Table storage, a NoSQL data store. keywords: visual f#, f#, functional programming, .NET, .NET Core, Azure -author: syclebsc +author: sylvanc manager: jbronsk ms.date: 09/20/2016 ms.topic: article @@ -49,7 +49,7 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L11)] However, this is a **bad idea** 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. @@ -154,7 +154,7 @@ You can delete an entity after you have retrieved it. As with updating an entity You can delete a table from a storage account. A table that has been deleted will be unavailable to be re-created for a period of time following the deletion. -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L154)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L154-L154)] ## Retrieve entities in pages asynchronously diff --git a/docs/fsharp/using-fsharp-on-azure/using-fsharp-on-azure-service-fabric.md b/docs/fsharp/using-fsharp-on-azure/using-fsharp-on-azure-service-fabric.md index 0bb533ef8c1de..1c4b5314ff237 100644 --- a/docs/fsharp/using-fsharp-on-azure/using-fsharp-on-azure-service-fabric.md +++ b/docs/fsharp/using-fsharp-on-azure/using-fsharp-on-azure-service-fabric.md @@ -1,3 +1,4 @@ # Using F# on Azure Service Fabric -> [!NOTE] This is still in progress. \ No newline at end of file +> [!NOTE] +> This is still in progress. From 43c49a7202652982a13dd3561927e293514194d5 Mon Sep 17 00:00:00 2001 From: cartermp Date: Mon, 26 Sep 2016 09:02:56 -0700 Subject: [PATCH 21/60] Add articles to TOC --- docs/fsharp/using-fsharp-on-azure/blob-storage.md | 2 +- docs/fsharp/using-fsharp-on-azure/file-storage.md | 2 +- docs/fsharp/using-fsharp-on-azure/index.md | 4 ++-- docs/fsharp/using-fsharp-on-azure/queue-storage.md | 2 +- docs/fsharp/using-fsharp-on-azure/table-storage.md | 2 +- docs/toc.md | 4 ++++ 6 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/blob-storage.md b/docs/fsharp/using-fsharp-on-azure/blob-storage.md index 14939872b1657..78ad2cf9e8a19 100644 --- a/docs/fsharp/using-fsharp-on-azure/blob-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/blob-storage.md @@ -12,7 +12,7 @@ ms.devlang: dotnet ms.assetid: c5b74a4f-dcd1-4849-930c-904b6c8a04e1 --- -# Get started with Azure Blob storage using F# +# Get started with Azure Blob storage using F# # Azure Blob storage is a service that stores unstructured data in the cloud as objects/blobs. Blob storage can store any type of text or binary data, such as a document, media file, or application installer. Blob storage is also referred to as object storage. diff --git a/docs/fsharp/using-fsharp-on-azure/file-storage.md b/docs/fsharp/using-fsharp-on-azure/file-storage.md index 79efb9bd62f46..78b4c273cf388 100644 --- a/docs/fsharp/using-fsharp-on-azure/file-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/file-storage.md @@ -12,7 +12,7 @@ ms.devlang: dotnet ms.assetid: 5c26a0aa-186e-476c-9f87-e0191754579e --- -# Get started with Azure File storage using F# +# Get started with Azure File storage using F# # Azure File storage is a service that offers file shares in the cloud using the standard [Server Message Block (SMB) Protocol](https://msdn.microsoft.com/library/windows/desktop/aa365233.aspx). Both SMB 2.1 and SMB 3.0 are supported. With Azure File storage, you can migrate legacy applications that rely on file shares to Azure quickly and without costly rewrites. Applications running in Azure virtual machines or cloud services or from on-premises clients can mount a file share in the cloud, just as a desktop application mounts a typical SMB share. Any number of application components can then mount and access the File storage share simultaneously. diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index 5f9d1f7e39eb8..8d6e41ba26707 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -20,9 +20,9 @@ F# is a superb language for cloud programming and is frequently used to write we In the sections below, you will find resources on how to use a range of Azure services with F#. > [!NOTE] -> If a particular Azure service doesn't have documentation below, please consult the C# documentation for that service. Some Azure services are entirely language-independent systems services and require no language-specific documentation, and in this case are not listed here. +> If a particular Azure service isn't in this documentation set, please consult the C# documentation for that service. Some Azure services are entirely language-independent systems services and require no language-specific documentation, and in this case are not listed here. -## Using Azure Storage with F# +## Using Azure Storage with F# # * [Get started with Azure Blob storage using F#](blob-storage.md) * [Get started with Azure File storage using F#](file-storage.md) diff --git a/docs/fsharp/using-fsharp-on-azure/queue-storage.md b/docs/fsharp/using-fsharp-on-azure/queue-storage.md index 1892e9b69115c..132132e189ea7 100644 --- a/docs/fsharp/using-fsharp-on-azure/queue-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/queue-storage.md @@ -12,7 +12,7 @@ ms.devlang: dotnet ms.assetid: 70dc554c-8f4d-42a7-8e2a-6438657d012a --- -# Get started with Azure Queue storage using F# +# Get started with Azure Queue storage using F# # Azure Queue storage provides cloud messaging between application components. In designing applications for scale, application components are often decoupled, so that they can scale independently. Queue storage delivers asynchronous messaging for communication between application components, whether they are running in the cloud, on the desktop, on an on-premises server, or on a mobile device. Queue storage also supports managing asynchronous tasks and building process work flows. diff --git a/docs/fsharp/using-fsharp-on-azure/table-storage.md b/docs/fsharp/using-fsharp-on-azure/table-storage.md index 56cf88038501b..00c308eb4d289 100644 --- a/docs/fsharp/using-fsharp-on-azure/table-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -12,7 +12,7 @@ ms.devlang: dotnet ms.assetid: 9e5d6cea-a98c-461e-a5cc-75f1d154eafd --- -# Get started with Azure Table storage using F# +# Get started with Azure Table storage using F# # Azure Table storage is a service that stores structured NoSQL data in the cloud. Table storage is a key/attribute store with a schemaless design. Because Table storage is schemaless, it's easy to adapt your data as the needs of your application evolve. Access to data is fast and cost-effective for all kinds of applications. Table storage is typically significantly lower in cost than traditional SQL for similar volumes of data. diff --git a/docs/toc.md b/docs/toc.md index 7c475cb2b9c68..e433c438e6170 100644 --- a/docs/toc.md +++ b/docs/toc.md @@ -117,6 +117,10 @@ ### [Targeting Older Versions of .NET](fsharp/using-fsharp-in-visual-studio/targeting-older-versions-of-net.md) ## [Using F# on Azure](fsharp/using-fsharp-on-azure/index.md) +### [Get started with Azure Blob storage using F#](fsharp/using-fsharp-on-azure/blob-storage.md) +### [Get started with Azure File storage using F#](fsharp/using-fsharp-on-azure/file-storage.md) +### [Get started with Azure Queue storage using F#](fsharp/using-fsharp-on-azure/queue-storage.md) +### [Get started with Azure Table storage using F#](fsharp/using-fsharp-on-azure/table-storage.md) ### [Using F# on Azure Service Fabric](fsharp/using-fsharp-on-azure/using-fsharp-on-azure-service-fabric.md) ## [F# Language Reference](fsharp/language-reference/index.md) From 5f29de04570d461333bce430a03659bf8ddcf15c Mon Sep 17 00:00:00 2001 From: cartermp Date: Mon, 26 Sep 2016 09:52:02 -0700 Subject: [PATCH 22/60] Fix code snippet references --- .../using-fsharp-on-azure/file-storage.md | 32 ++++++++-------- .../using-fsharp-on-azure/queue-storage.md | 28 +++++++------- .../using-fsharp-on-azure/table-storage.md | 38 +++++++++---------- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/file-storage.md b/docs/fsharp/using-fsharp-on-azure/file-storage.md index 78b4c273cf388..99be5072d8c75 100644 --- a/docs/fsharp/using-fsharp-on-azure/file-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/file-storage.md @@ -27,15 +27,15 @@ You'll also need your storage access key for this account. ## Create an F# Script and Start F# Interactive -The samples in this article can be used in either an F# application or an F# script. To create an F# script, create a file with the `.fsx` extension, for example `blobs.fsx`, in your F# development environment. +The samples in this article can be used in either an F# application or an F# script. To create an F# script, create a file with the `.fsx` extension, for example `files.fsx`, in your F# development environment. Next, use a [package manager](package-management.md) such as Paket or NuGet to install the `WindowsAzure.Storage` package and reference `WindowsAzure.Storage.dll` in your script using a `#r` directive. ### Add namespace declarations -Add the following `open` statements to the top of the `blobs.fsx` file: +Add the following `open` statements to the top of the `files.fsx` file: -[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L5)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L1-L5)] ### Get your connection string @@ -43,13 +43,13 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: -[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L11)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L11-L11)] However, this is a **bad idea** 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/blob-storage.fsx#L13-L15)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L13-L15)] Using Azure Configuration Manager is optional. You can also use an API such as the .NET Framework's `ConfigurationManager` type. @@ -57,7 +57,7 @@ Using Azure Configuration Manager is optional. You can also use an API such as t To parse the connection string, use: -[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L21-L22)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L21-L22)] This will return a `CloudStorageAccount`. @@ -65,27 +65,27 @@ This will return a `CloudStorageAccount`. The `CloudFileClient` 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/blob-storage.fsx#L28-L28)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L28-L28)] -Now you are ready to write code that reads data from and writes data to Blob storage. +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: +This example shows how to create a file share if it does not already exist:asdasd -[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L34-L35)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L34-L35)] ### Access the file share programmatically Here, we get the root directory and get a sub-directory of the root. If the sub-directory exists, we get a file in the sub-directory, and if that exists too, we download the file, appending the contents to a local file. -[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L41-L47)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L41-L47)] ### 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. -[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L53-L63)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L53-L63)] ### Generate a shared access signature for a file or file share @@ -93,7 +93,7 @@ You can generate a shared access signature (SAS) for a file share or for an indi Here, we 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. -[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L69-L86)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L69-L86)] For more information about creating and using shared access signatures, see [Using Shared Access Signatures (SAS)](https://azure.microsoft.com/en-gb/documentation/articles/storage-dotnet-shared-access-signature-part-1/) and [Create and use a SAS with Blob storage](https://azure.microsoft.com/en-gb/documentation/articles/storage-dotnet-shared-access-signature-part-2/). @@ -105,13 +105,13 @@ You can copy a file to another file, a file to a blob, or a blob to a file. If y Here, we 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/blob-storage.fsx#L92-L93)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L92-L93)] ### Copy a file to a blob Here, we create a file and copy it to a blob within the same storage account. We 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/blob-storage.fsx#L99-L112)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L99-L112)] 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. @@ -121,7 +121,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/blob-storage.fsx#L118-L131)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L118-L131)] ## Next steps diff --git a/docs/fsharp/using-fsharp-on-azure/queue-storage.md b/docs/fsharp/using-fsharp-on-azure/queue-storage.md index 132132e189ea7..441f5b04b733e 100644 --- a/docs/fsharp/using-fsharp-on-azure/queue-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/queue-storage.md @@ -39,7 +39,7 @@ Next, use a [package manager](package-management.md) such as Paket or NuGet to i Add the following `open` statements to the top of the `queues.fsx` file: -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L3)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L1-L3)] ### Get your connection string @@ -47,13 +47,13 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L9-L13)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L9-L13)] However, this is a **bad idea** 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[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L13)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L11-L13)] Using Azure Configuration Manager is optional. You can also use an API such as the .NET Framework's `ConfigurationManager` type. @@ -61,7 +61,7 @@ Using Azure Configuration Manager is optional. You can also use an API such as t To parse the connection string, use: -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L19-L20)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L19-L20)] This will return a `CloudStorageAccount`. @@ -69,7 +69,7 @@ This will return a `CloudStorageAccount`. The `CloudQueueClient` class enables you to retrieve queues stored in Queue storage. Here's one way to create the service client: -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L26-L26)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L26-L26)] Now you are ready to write code that reads data from and writes data to Queue storage. @@ -77,7 +77,7 @@ Now you are ready to write code that reads data from and writes data to Queue st This example shows how to create a queue if it doesn't already exist: -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L32-L36)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L32-L36)] ## Insert a message into a queue @@ -86,14 +86,14 @@ To insert a message into an existing queue, first create a new `CloudQueueMessage` can be created from either a string (in UTF-8 format) or a `byte` array, like this: -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L42-L44)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L42-L44)] ## Peek at the next message You can peek at the message in the front of a queue, without removing it from the queue, by calling the `PeekMessage` method. -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L50-L52)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L50-L52)] ## Change the contents of a queued message @@ -110,7 +110,7 @@ you would keep a retry count as well, and if the message is retried more than some number of times, you would delete it. This protects against a message that triggers an application error each time it is processed. -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L58-L62)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L58-L62)] ## De-queue the next message @@ -125,13 +125,13 @@ software failure, another instance of your code can get the same message and try again. Your code calls `DeleteMessage` right after the message has been processed. -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L68-L69)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L68-L69)] ## Use Async-Await pattern with common Queue storage APIs This example shows how to use an async workflow with common Queue storage APIs. -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L75-L81)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L75-L81)] ## Additional options for de-queuing messages @@ -145,20 +145,20 @@ each message. Note that the 5 minutes starts for all messages at the same time, so after 5 minutes have passed since the call to `GetMessages`, any messages which have not been deleted will become visible again. -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L87-L89)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L87-L89)] ## Get the queue length You can get an estimate of the number of messages in a queue. The `FetchAttributes` method asks the Queue service to retrieve the queue attributes, including the message count. The `ApproximateMessageCount` property returns the last value retrieved by the `FetchAttributes` method, without calling the Queue service. -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L95-L96)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L95-L96)] ## Delete a queue To delete a queue and all the messages contained in it, call the `Delete` method on the queue object. -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L102-L103)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L102-L103)] ## Next steps diff --git a/docs/fsharp/using-fsharp-on-azure/table-storage.md b/docs/fsharp/using-fsharp-on-azure/table-storage.md index 00c308eb4d289..fb18e26628e1b 100644 --- a/docs/fsharp/using-fsharp-on-azure/table-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -39,9 +39,9 @@ Next, use a [package manager](package-management.md) such as Paket or NuGet to i ### Add namespace declarations -Add the following `open` statements to the top of the `blobs.fsx` file: +Add the following `open` statements to the top of the `tables.fsx` file: -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L1-L5)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L1-L5)] ### Get your connection string @@ -49,13 +49,13 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L11)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L11-L11)] However, this is a **bad idea** 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[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L13-L15)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L13-L15)] Using Azure Configuration Manager is optional. You can also use an API such as the .NET Framework's `ConfigurationManager` type. @@ -63,7 +63,7 @@ Using Azure Configuration Manager is optional. You can also use an API such as t To parse the connection string, use: -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L21-L22)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L21-L22)] This will return a `CloudStorageAccount`. @@ -71,7 +71,7 @@ This will return a `CloudStorageAccount`. The `CloudTableClient` class enables you to retrieve tables and entities stored in Table storage. Here's one way to create the service client: -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L28-L29)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L28-L29)] Now you are ready to write code that reads data from and writes data to Table storage. @@ -79,7 +79,7 @@ Now you are ready to write code that reads data from and writes data to Table st This example shows how to create a table if it does not already exist: -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L35-L39)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L35-L39)] ## Add an entity to a table @@ -89,11 +89,11 @@ An entity's partition and row key uniquely identify the entity in the table. Ent Here's an example of a `Customer` that uses the `lastName` as the partition key and the `firstName` as the row key. -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L45-L53)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L45-L53)] Now we'll add our `Customer` to the table. To do so, we create a `TableOperation` that we will execute on the table. In this case, we create an `Insert` operation. -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L55-L56)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L55-L56)] ## Insert a batch of entities @@ -106,61 +106,61 @@ You can insert a batch of entities into a table using a single write operation. Here's some code that combines two inserts into a batch operation: -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L62-L68)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L62-L68)] ## Retrieve all entities in a partition To query a table for all entities in a partition, use a `TableQuery` object. Here, we filter for entities where "Buster" is the partition key. -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L74-L79)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L74-L79)] ## Retrieve a range of entities in a partition If you don't want to query all the entities in a partition, you can specify a range by combining the partition key filter with a row key filter. Here, we use two filters to get all entities in the "Buster" partition where the row key (first name) starts with a letter earlier than "M" in the alphabet. -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L85-L94)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L85-L94)] ## Retrieve a single entity You can write a query to retrieve a single, specific entity. Here, we use a `TableOperation` to specify the customer "Larry Buster". Instead of a collection, we get back a `Customer`. Specifying both the partition key and the row key in a query is the fastest way to retrieve a single entity from the Table service. -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L100-L101)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L100-L101)] ## Replace an entity To update an entity, retrieve it from the Table service, modify the entity object, and then save the changes back to the Table service using a `Replace` operation. This causes the entity to be fully replaced on the server, unless the entity on the server has changed since it was retrieved, in which case the operation will fail. This failure is to prevent your application from inadvertently overwriting changes from other sources. -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L107-L113)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L107-L113)] ## Insert-or-replace an entity Sometimes, you don't know if the entity exists in the table or not. And if it does, the current values stored in it are no longer needed. We can use `InsertOrReplace` to create the entity, or replace it if it exists, regardless of its state. -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L119-L124)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L119-L124)] ## Query a subset of entity properties A table query can retrieve just a few properties from an entity instead of all of them. This technique, called projection, can improve query performance, especially for large entities. Here, we return only email addresses using `DynamicTableEntity` and `EntityResolver`. Note that projection is not supported on the local storage emulator, so this code runs only when you're using an account on the Table service. -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L130-L141)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L130-L141)] ## Delete an entity You can delete an entity after you have retrieved it. As with updating an entity, this will fail if the entity has changed since you retrieved it. -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L147-L148)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L147-L148)] ## Delete a table You can delete a table from a storage account. A table that has been deleted will be unavailable to be re-created for a period of time following the deletion. -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L154-L154)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L154-L154)] ## Retrieve entities in pages asynchronously If you are reading a large number of entities, and you want to process them as they are retrieved rather than waiting for them all to return, you can use a segmented query. Here, we return results in pages by using an async workflow so that execution is not blocked while you're waiting for a large set of results to return. -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L160-L174)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L160-L174)] ## Next steps From 4e55877bceba21164f8ac8fa58d845238a526d02 Mon Sep 17 00:00:00 2001 From: Sylvan Clebsch Date: Tue, 27 Sep 2016 13:06:00 +0100 Subject: [PATCH 23/60] Incorporate comments from @mairaw --- docs/fsharp/using-fsharp-on-azure/blob-storage.md | 15 +++++---------- docs/fsharp/using-fsharp-on-azure/file-storage.md | 2 +- .../fsharp/using-fsharp-on-azure/queue-storage.md | 2 +- .../fsharp/using-fsharp-on-azure/table-storage.md | 2 +- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/blob-storage.md b/docs/fsharp/using-fsharp-on-azure/blob-storage.md index 14939872b1657..9ecbf921d1ff8 100644 --- a/docs/fsharp/using-fsharp-on-azure/blob-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/blob-storage.md @@ -16,18 +16,13 @@ ms.assetid: c5b74a4f-dcd1-4849-930c-904b6c8a04e1 Azure Blob storage is a service that stores unstructured data in the cloud as objects/blobs. Blob storage can store any type of text or binary data, such as a document, media file, or application installer. Blob storage is also referred to as object storage. -### About this tutorial - This article shows you how to perform common tasks using Blob storage. The samples are written using F# using the Azure Storage Client Library for .NET. The tasks covered include how to upload, list, download, and delete blobs. -### Conceptual overview - -For a conceptual overview of blob storage, please see [the .NET guide for blob storage](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-blobs/) +For a conceptual overview of blob storage, see [the .NET guide for blob storage](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-blobs/). -### Create an Azure storage account +## Prerequisites -To use this guide, you must first [create an Azure storage account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/). -You'll also need your storage access key for this account. +To use this guide, you must first [create an Azure storage account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/). You also need your storage access key for this account. ## Create an F# Script and Start F# Interactive @@ -49,7 +44,7 @@ For the tutorial, you'll enter your connection string in your script, like this: [!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L11)] -However, this is a **bad idea** 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. +However, this is a **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: @@ -125,7 +120,7 @@ When you call `ListBlobs` on the 'photos' container (as in the above sample), a Block blob of length 505623: https://.blob.core.windows.net/photos/photo1.jpg -Optionally, you can set the `UseFlatBlobListing` parameter of of the `ListBlobs` method to `true`. In this case, every blob in the container is returned as a `CloudBlockBlob` object. The call to `ListBlobs` to return a flat listing looks like this: +Optionally, you can set the `UseFlatBlobListing` parameter of the `ListBlobs` method to `true`. In this case, every blob in the container is returned as a `CloudBlockBlob` object. The call to `ListBlobs` to return a flat listing looks like this: [!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L82-L89)] diff --git a/docs/fsharp/using-fsharp-on-azure/file-storage.md b/docs/fsharp/using-fsharp-on-azure/file-storage.md index 79efb9bd62f46..9ee39dd06cf62 100644 --- a/docs/fsharp/using-fsharp-on-azure/file-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/file-storage.md @@ -45,7 +45,7 @@ For the tutorial, you'll enter your connection string in your script, like this: [!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L11)] -However, this is a **bad idea** 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. +However, this is a **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: diff --git a/docs/fsharp/using-fsharp-on-azure/queue-storage.md b/docs/fsharp/using-fsharp-on-azure/queue-storage.md index 1892e9b69115c..c4376e83e872b 100644 --- a/docs/fsharp/using-fsharp-on-azure/queue-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/queue-storage.md @@ -49,7 +49,7 @@ For the tutorial, you'll enter your connection string in your script, like this: [!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L9-L13)] -However, this is a **bad idea** 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. +However, this is a **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: diff --git a/docs/fsharp/using-fsharp-on-azure/table-storage.md b/docs/fsharp/using-fsharp-on-azure/table-storage.md index 56cf88038501b..fa0cfc8e36498 100644 --- a/docs/fsharp/using-fsharp-on-azure/table-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -51,7 +51,7 @@ For the tutorial, you'll enter your connection string in your script, like this: [!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L11)] -However, this is a **bad idea** 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. +However, this is a **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: From b24c2204d6bb4d8f1ad8170c5bbc904df9d902cb Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 28 Sep 2016 12:42:18 +0100 Subject: [PATCH 24/60] Adding a small section on Virtual Machines and F# --- docs/fsharp/using-fsharp-on-azure/index.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index 8d6e41ba26707..6f93b00ce9862 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -22,8 +22,17 @@ In the sections below, you will find resources on how to use a range of Azure se > [!NOTE] > If a particular Azure service isn't in this documentation set, please consult the C# documentation for that service. Some Azure services are entirely language-independent systems services and require no language-specific documentation, and in this case are not listed here. +## Using Azure Virtual Machines with F# # + +Azure supports a wide range of virtual machine (VM) configurations, see [Linux and Azure Virtual Machines](https://azure.microsoft.com/en-us/services/virtual-machines/) + +To install F# on a virtual machine for execution, compilation and/or scripting see [Using F# on Linux](http://fsharp.org/use/linux) and +[Using F# on Windows](http://fsharp.org/use/windows). + ## Using Azure Storage with F# # +Azure Storage is a base layer of storage services for modern applications that rely on durability, availability, and scalability to meet the needs of customers. F# programs can interact directy with Azure storage services, using the techinques described in the articles below. + * [Get started with Azure Blob storage using F#](blob-storage.md) * [Get started with Azure File storage using F#](file-storage.md) * [Get started with Azure Queue storage using F#](queue-storage.md) From a13ea7afbf1a26dddab6ddc0b8f948556cd7089b Mon Sep 17 00:00:00 2001 From: Sylvan Clebsch Date: Wed, 28 Sep 2016 13:15:10 +0100 Subject: [PATCH 25/60] Incorporate comments from @mairaw and @badersur --- docs/fsharp/using-fsharp-on-azure/blob-storage.md | 6 +++--- docs/fsharp/using-fsharp-on-azure/file-storage.md | 10 ++++------ docs/fsharp/using-fsharp-on-azure/queue-storage.md | 8 +++----- docs/fsharp/using-fsharp-on-azure/table-storage.md | 8 +++----- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/blob-storage.md b/docs/fsharp/using-fsharp-on-azure/blob-storage.md index b9a5ca62d08c9..a4fefce316052 100644 --- a/docs/fsharp/using-fsharp-on-azure/blob-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/blob-storage.md @@ -28,7 +28,7 @@ To use this guide, you must first [create an Azure storage account](https://azur The samples in this article can be used in either an F# application or an F# script. To create an F# script, create a file with the `.fsx` extension, for example `blobs.fsx`, in your F# development environment. -Next, use a [package manager](package-management.md) such as Paket or NuGet to install the `WindowsAzure.Storage` package and reference `WindowsAzure.Storage.dll` in your script using a `#r` directive. +Next, use a [package manager](package-management.md) such as [Paket](https://fsprojects.github.io/Paket/) or [NuGet](https://www.nuget.org/) to install the `WindowsAzure.Storage` package and reference `WindowsAzure.Storage.dll` in your script using a `#r` directive. ### Add namespace declarations @@ -44,7 +44,7 @@ For the tutorial, you'll enter your connection string in your script, like this: [!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L11)] -However, this is a **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. +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: @@ -225,7 +225,7 @@ For details on how to control access to blob storage, see [the .NET guide for bl Azure Storage supports encrypting blob data both at the client and on the server. -For details on encrypting blob data, see [the .NET guide for blob storage section on enryption](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-blobs/#encrypting-blob-data). +For details on encrypting blob data, see [the .NET guide for blob storage section on encryption](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-blobs/#encrypting-blob-data). ## Next steps diff --git a/docs/fsharp/using-fsharp-on-azure/file-storage.md b/docs/fsharp/using-fsharp-on-azure/file-storage.md index 834f98ce0d349..86d80d836557a 100644 --- a/docs/fsharp/using-fsharp-on-azure/file-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/file-storage.md @@ -16,11 +16,9 @@ ms.assetid: 5c26a0aa-186e-476c-9f87-e0191754579e Azure File storage is a service that offers file shares in the cloud using the standard [Server Message Block (SMB) Protocol](https://msdn.microsoft.com/library/windows/desktop/aa365233.aspx). Both SMB 2.1 and SMB 3.0 are supported. With Azure File storage, you can migrate legacy applications that rely on file shares to Azure quickly and without costly rewrites. Applications running in Azure virtual machines or cloud services or from on-premises clients can mount a file share in the cloud, just as a desktop application mounts a typical SMB share. Any number of application components can then mount and access the File storage share simultaneously. -### Conceptual overview - For a conceptual overview of file storage, please see [the .NET guide for file storage](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-files/). -### Create an Azure storage account +## Prerequisites To use this guide, you must first [create an Azure storage account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/). You'll also need your storage access key for this account. @@ -29,7 +27,7 @@ You'll also need your storage access key for this account. The samples in this article can be used in either an F# application or an F# script. To create an F# script, create a file with the `.fsx` extension, for example `files.fsx`, in your F# development environment. -Next, use a [package manager](package-management.md) such as Paket or NuGet to install the `WindowsAzure.Storage` package and reference `WindowsAzure.Storage.dll` in your script using a `#r` directive. +Next, use a [package manager](package-management.md) such as [Paket](https://fsprojects.github.io/Paket/) or [NuGet](https://www.nuget.org/) to install the `WindowsAzure.Storage` package and reference `WindowsAzure.Storage.dll` in your script using a `#r` directive. ### Add namespace declarations @@ -45,7 +43,7 @@ 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)] -However, this is a **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. +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: @@ -71,7 +69,7 @@ Now you are ready to write code that reads data from and writes data to File sto ## Create a file share -This example shows how to create a file share if it does not already exist:asdasd +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)] diff --git a/docs/fsharp/using-fsharp-on-azure/queue-storage.md b/docs/fsharp/using-fsharp-on-azure/queue-storage.md index 199288b5ff9bf..a227b11818344 100644 --- a/docs/fsharp/using-fsharp-on-azure/queue-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/queue-storage.md @@ -20,11 +20,9 @@ Azure Queue storage provides cloud messaging between application components. In This tutorial shows how to write F# code for some common tasks using Azure Queue storage. Tasks covered include creating and deleting queues and adding, reading, and deleting queue messages. -### Conceptual overview - For a conceptual overview of queue storage, please see [the .NET guide for queue storage](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-queues/). -### Create an Azure storage account +## Prerequisites To use this guide, you must first [create an Azure storage account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/). You'll also need your storage access key for this account. @@ -33,7 +31,7 @@ You'll also need your storage access key for this account. The samples in this article can be used in either an F# application or an F# script. To create an F# script, create a file with the `.fsx` extension, for example `queues.fsx`, in your F# development environment. -Next, use a [package manager](package-management.md) such as Paket or NuGet to install the `WindowsAzure.Storage` package and reference `WindowsAzure.Storage.dll` in your script using a `#r` directive. +Next, use a [package manager](package-management.md) such as [Paket](https://fsprojects.github.io/Paket/) or [NuGet](https://www.nuget.org/) to install the `WindowsAzure.Storage` package and reference `WindowsAzure.Storage.dll` in your script using a `#r` directive. ### Add namespace declarations @@ -49,7 +47,7 @@ For the tutorial, you'll enter your connection string in your script, like this: [!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L9-L13)] -However, this is a **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. +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: diff --git a/docs/fsharp/using-fsharp-on-azure/table-storage.md b/docs/fsharp/using-fsharp-on-azure/table-storage.md index 2c0c26a727d0d..0f11e702fa692 100644 --- a/docs/fsharp/using-fsharp-on-azure/table-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -22,11 +22,9 @@ You can use Table storage to store flexible datasets, such as user data for web This tutorial shows how to write F# code to do some common tasks using Azure Table storage, including creating and deleting a table and inserting, updating, deleting, and querying table data. -### Conceptual overview - For a conceptual overview of table storage, please see [the .NET guide for table storage](https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-tables/) -### Create an Azure storage account +## Prerequisites To use this guide, you must first [create an Azure storage account](https://azure.microsoft.com/en-us/documentation/articles/storage-create-storage-account/). You'll also need your storage access key for this account. @@ -35,7 +33,7 @@ You'll also need your storage access key for this account. The samples in this article can be used in either an F# application or an F# script. To create an F# script, create a file with the `.fsx` extension, for example `tables.fsx`, in your F# development environment. -Next, use a [package manager](package-management.md) such as Paket or NuGet to install the `WindowsAzure.Storage` package and reference `WindowsAzure.Storage.dll` in your script using a `#r` directive. +Next, use a [package manager](package-management.md) such as [Paket](https://fsprojects.github.io/Paket/) or [NuGet](https://www.nuget.org/) to install the `WindowsAzure.Storage` package and reference `WindowsAzure.Storage.dll` in your script using a `#r` directive. ### Add namespace declarations @@ -51,7 +49,7 @@ For the tutorial, you'll enter your connection string in your script, like this: [!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L11-L11)] -However, this is a **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. +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: From 2023392c92e63735c1adaecda459ff732a0b0a26 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 28 Sep 2016 15:07:52 +0100 Subject: [PATCH 26/60] Add information on Azure Functions --- docs/fsharp/using-fsharp-on-azure/index.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index 6f93b00ce9862..de3ada688f521 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -29,15 +29,27 @@ Azure supports a wide range of virtual machine (VM) configurations, see [Linux a To install F# on a virtual machine for execution, compilation and/or scripting see [Using F# on Linux](http://fsharp.org/use/linux) and [Using F# on Windows](http://fsharp.org/use/windows). +## Using Azure Functions with F# # + +[Azure Functions](https://azure.microsoft.com/en-us/services/functions/) is a solution for easily running small pieces of code, or "functions," in the cloud. You can write just the code you need for the problem at hand, without worrying about a whole application or the infrastructure to run it. Your functions are connected to events in Azure storage and other cloud-hosted resource. Data flows into your F# functions via function arguments. You can use your development language of choice, trusting Azure to scale as needed. + +Azure Functions support F# as a first-class language with efficient, reactive, scalable execution of F# code. See the [Azure Functions F# Developer Reference](https://azure.microsoft.com/en-us/documentation/articles/functions-reference-fsharp/) for reference doccumentation on how to use F# with Azure Functions. + +Other resources for using Azure Functions and F#: +* [Scale Up Azure Functions in F# Using Suave](http://blog.tamizhvendan.in/blog/2016/09/19/scale-up-azure-functions-in-f-number-using-suave/) +* [Azure Functions in Practice](https://www.troyhunt.com/azure-functions-in-practice/) + ## Using Azure Storage with F# # -Azure Storage is a base layer of storage services for modern applications that rely on durability, availability, and scalability to meet the needs of customers. F# programs can interact directy with Azure storage services, using the techinques described in the articles below. +Azure Storage is a base layer of storage services for modern applications that rely on durability, availability, and scalability to meet the needs of customers.F# programs can interact directy with Azure storage services, using the techinques described in the articles below. * [Get started with Azure Blob storage using F#](blob-storage.md) * [Get started with Azure File storage using F#](file-storage.md) * [Get started with Azure Queue storage using F#](queue-storage.md) * [Get started with Azure Table storage using F#](table-storage.md) +Azure Storage can also be used in conjunction with Azure Functions through declarative configuration rather than explicit API calls. See the information above on using Azure Functions with F#. + ## Other resources * [Full documentation on all Azure services](https://azure.microsoft.com/en-us/documentation/) From 5356a2525a6385cc681d7e891fd30eef4bc1c43f Mon Sep 17 00:00:00 2001 From: Sylvan Clebsch Date: Wed, 28 Sep 2016 15:44:58 +0100 Subject: [PATCH 27/60] fix minor typos --- docs/fsharp/using-fsharp-on-azure/index.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index de3ada688f521..e7f2aa5cc7dfb 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -24,32 +24,32 @@ In the sections below, you will find resources on how to use a range of Azure se ## Using Azure Virtual Machines with F# # -Azure supports a wide range of virtual machine (VM) configurations, see [Linux and Azure Virtual Machines](https://azure.microsoft.com/en-us/services/virtual-machines/) +Azure supports a wide range of virtual machine (VM) configurations, see [Linux and Azure Virtual Machines](https://azure.microsoft.com/en-us/services/virtual-machines/). -To install F# on a virtual machine for execution, compilation and/or scripting see [Using F# on Linux](http://fsharp.org/use/linux) and -[Using F# on Windows](http://fsharp.org/use/windows). +To install F# on a virtual machine for execution, compilation and/or scripting see [Using F# on Linux](http://fsharp.org/use/linux) and [Using F# on Windows](http://fsharp.org/use/windows). ## Using Azure Functions with F# # -[Azure Functions](https://azure.microsoft.com/en-us/services/functions/) is a solution for easily running small pieces of code, or "functions," in the cloud. You can write just the code you need for the problem at hand, without worrying about a whole application or the infrastructure to run it. Your functions are connected to events in Azure storage and other cloud-hosted resource. Data flows into your F# functions via function arguments. You can use your development language of choice, trusting Azure to scale as needed. +[Azure Functions](https://azure.microsoft.com/en-us/services/functions/) is a solution for easily running small pieces of code, or "functions," in the cloud. You can write just the code you need for the problem at hand, without worrying about a whole application or the infrastructure to run it. Your functions are connected to events in Azure storage and other cloud-hosted resources. Data flows into your F# functions via function arguments. You can use your development language of choice, trusting Azure to scale as needed. -Azure Functions support F# as a first-class language with efficient, reactive, scalable execution of F# code. See the [Azure Functions F# Developer Reference](https://azure.microsoft.com/en-us/documentation/articles/functions-reference-fsharp/) for reference doccumentation on how to use F# with Azure Functions. +Azure Functions support F# as a first-class language with efficient, reactive, scalable execution of F# code. See the [Azure Functions F# Developer Reference](https://azure.microsoft.com/en-us/documentation/articles/functions-reference-fsharp/) for reference doccumentation on how to use F# with Azure Functions. Other resources for using Azure Functions and F#: + * [Scale Up Azure Functions in F# Using Suave](http://blog.tamizhvendan.in/blog/2016/09/19/scale-up-azure-functions-in-f-number-using-suave/) * [Azure Functions in Practice](https://www.troyhunt.com/azure-functions-in-practice/) ## Using Azure Storage with F# # -Azure Storage is a base layer of storage services for modern applications that rely on durability, availability, and scalability to meet the needs of customers.F# programs can interact directy with Azure storage services, using the techinques described in the articles below. +Azure Storage is a base layer of storage services for modern applications that rely on durability, availability, and scalability to meet the needs of customers. F# programs can interact directly with Azure storage services, using the techinques described in the articles below. * [Get started with Azure Blob storage using F#](blob-storage.md) * [Get started with Azure File storage using F#](file-storage.md) * [Get started with Azure Queue storage using F#](queue-storage.md) * [Get started with Azure Table storage using F#](table-storage.md) -Azure Storage can also be used in conjunction with Azure Functions through declarative configuration rather than explicit API calls. See the information above on using Azure Functions with F#. - +Azure Storage can also be used in conjunction with Azure Functions through declarative configuration rather than explicit API calls. See the information above on using Azure Functions with F#. + ## Other resources * [Full documentation on all Azure services](https://azure.microsoft.com/en-us/documentation/) From 5aae493dc6f36bbf9971657fc077a203099bef13 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 28 Sep 2016 18:38:13 +0100 Subject: [PATCH 28/60] Add info on Event Hubs and DocumentDB --- docs/fsharp/using-fsharp-on-azure/index.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index e7f2aa5cc7dfb..2d386484ef85c 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -50,6 +50,24 @@ Azure Storage is a base layer of storage services for modern applications that r Azure Storage can also be used in conjunction with Azure Functions through declarative configuration rather than explicit API calls. See the information above on using Azure Functions with F#. +## Using Azure DocumentDB with F# # + +[Azure DocumentDB](https://azure.microsoft.com/en-us/services/documentdb/) is a NoSQL service for highly available, globally distributed apps. + +Azure DocumentDB can be used with F# in two ways: + +1. Through the creation of F# Azure Functions which react to or cause changes to DocumentDB collections. See [Azure Function triggers for DocumentDB](https://azure.microsoft.com/en-us/documentation/articles/functions-bindings-documentdb/), or +2. By using the [.NET SDK for Azure](https://azure.microsoft.com/en-us/documentation/articles/documentdb-get-started-quickstart/) directly. Note these examples are in C#. + +## Using Azure Event Hubs with F# # + +[Azure Event Hubs](https://azure.microsoft.com/en-us/services/event-hubs/) provide cloud-scale telemetry ingestion from websites, apps, and devices. + +Azure Event Hubs can be used with F# in two ways: + +1. Through the creation of F# Azure Functions which are triggered by events. See [Azure Function triggers for E|vent Hubs](https://azure.microsoft.com/en-us/documentation/articles/functions-bindings-event-hubs/), or +2. By using the [.NET SDK for Azure](https://azure.microsoft.com/en-us/documentation/articles/event-hubs-csharp-ephcs-getstarted/) directly. Note these examples are in C#. + ## Other resources * [Full documentation on all Azure services](https://azure.microsoft.com/en-us/documentation/) From ff550bab492ca756b86263a41f62d1683d773c66 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 28 Sep 2016 19:05:58 +0100 Subject: [PATCH 29/60] Add some more Azure use cases covered by F# for Azure Functions --- docs/fsharp/using-fsharp-on-azure/index.md | 28 +++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index 2d386484ef85c..b174b462cd132 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -57,7 +57,7 @@ Azure Storage can also be used in conjunction with Azure Functions through decla Azure DocumentDB can be used with F# in two ways: 1. Through the creation of F# Azure Functions which react to or cause changes to DocumentDB collections. See [Azure Function triggers for DocumentDB](https://azure.microsoft.com/en-us/documentation/articles/functions-bindings-documentdb/), or -2. By using the [.NET SDK for Azure](https://azure.microsoft.com/en-us/documentation/articles/documentdb-get-started-quickstart/) directly. Note these examples are in C#. +2. By using the [.NET SDK for Azure](https://azure.microsoft.com/en-us/documentation/articles/documentdb-get-started-quickstart/). Note these examples are in C#. ## Using Azure Event Hubs with F# # @@ -65,8 +65,30 @@ Azure DocumentDB can be used with F# in two ways: Azure Event Hubs can be used with F# in two ways: -1. Through the creation of F# Azure Functions which are triggered by events. See [Azure Function triggers for E|vent Hubs](https://azure.microsoft.com/en-us/documentation/articles/functions-bindings-event-hubs/), or -2. By using the [.NET SDK for Azure](https://azure.microsoft.com/en-us/documentation/articles/event-hubs-csharp-ephcs-getstarted/) directly. Note these examples are in C#. +1. Through the creation of F# Azure Functions which are triggered by events. See [Azure Function triggers for Event Hubs](https://azure.microsoft.com/en-us/documentation/articles/functions-bindings-event-hubs/), or +2. By using the [.NET SDK for Azure](https://azure.microsoft.com/en-us/documentation/articles/event-hubs-csharp-ephcs-getstarted/). Note these examples are in C#. + +## Using Azure Notifcation Hubs with F# # + +[Azure Notification Hubs](https://azure.microsoft.com/en-us/documentation/services/notification-hubs/) are multiplatform, scaled-out push infrastructure that enables you to send mobile push notifications from any backend (in the cloud or on-premises) to any mobile platform. + +Azure Notification Hubs can be used with F# in two ways: + +1. Through the creation of F# Azure Functions which send results to a notification hub. See [Azure Function output triggers for Notification Hubs](https://azure.microsoft.com/en-us/documentation/articles/functions-bindings-notification-hubs/), or +2. By using the [.NET SDK for Azure](https://blogs.msdn.microsoft.com/azuremobile/2014/04/08/push-notifications-using-notification-hub-and-net-backend/). Note these examples are in C#. + + +## Implementing WebHooks on Azure with F# # + +A [Webhook](https://en.wikipedia.org/wiki/Webhook) is a callback triggered via a web request. Webhooks are used by sites such as GitHub to signal events. + +Webhooks can be implemented in F# and hosted on Azure via an [Azure Function in F# with a Webhook Binding](https://azure.microsoft.com/en-us/documentation/articles/functions-bindings-http-webhook/). + +## Implementing Timers on Azure with F# # + +Timer triggers call functions based on a schedule, one time or recurring. + +Timers can be implemented in F# and hosted on Azure via an [Azure Function in F# with a Timer Trigger](https://azure.microsoft.com/en-us/documentation/articles/functions-bindings-timer/). ## Other resources From 390161cdbe70e8e2b4833f400c0b26c5e08503c6 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 28 Sep 2016 19:36:02 +0100 Subject: [PATCH 30/60] Add notes about provisioning --- docs/fsharp/using-fsharp-on-azure/index.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index b174b462cd132..b84aba479e889 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -28,6 +28,13 @@ Azure supports a wide range of virtual machine (VM) configurations, see [Linux a To install F# on a virtual machine for execution, compilation and/or scripting see [Using F# on Linux](http://fsharp.org/use/linux) and [Using F# on Windows](http://fsharp.org/use/windows). +## Deploying and Managing Azure Resources with F# Scripts # + +Azure VMs may be programmatically deployed and managed from F# scripts by using the Microsoft.Azure.Management packages and APIs. For example, see [Get Started with the Management Libraries for .NET](https://msdn.microsoft.com/en-us/library/dn722415.aspx). Note that these samples are in C#. + +Likewise, other Azure resources may also be deployed and managed from F# scripts using these components. For example, you can create storage accounts, deploy services, create DocumentDB instances and manage Azure Notifcation Hubs programmatically from F# scripts. + + ## Using Azure Functions with F# # [Azure Functions](https://azure.microsoft.com/en-us/services/functions/) is a solution for easily running small pieces of code, or "functions," in the cloud. You can write just the code you need for the problem at hand, without worrying about a whole application or the infrastructure to run it. Your functions are connected to events in Azure storage and other cloud-hosted resources. Data flows into your F# functions via function arguments. You can use your development language of choice, trusting Azure to scale as needed. @@ -50,6 +57,7 @@ Azure Storage is a base layer of storage services for modern applications that r Azure Storage can also be used in conjunction with Azure Functions through declarative configuration rather than explicit API calls. See the information above on using Azure Functions with F#. + ## Using Azure DocumentDB with F# # [Azure DocumentDB](https://azure.microsoft.com/en-us/services/documentdb/) is a NoSQL service for highly available, globally distributed apps. From a532c143ed535fb0b9091f7dd75ecd7e64e4a032 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 28 Sep 2016 19:39:27 +0100 Subject: [PATCH 31/60] Update index.md --- docs/fsharp/using-fsharp-on-azure/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index b84aba479e889..4c612347a857e 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -30,7 +30,7 @@ To install F# on a virtual machine for execution, compilation and/or scripting s ## Deploying and Managing Azure Resources with F# Scripts # -Azure VMs may be programmatically deployed and managed from F# scripts by using the Microsoft.Azure.Management packages and APIs. For example, see [Get Started with the Management Libraries for .NET](https://msdn.microsoft.com/en-us/library/dn722415.aspx). Note that these samples are in C#. +Azure VMs may be programmatically deployed and managed from F# scripts by using the Microsoft.Azure.Management packages and APIs. For example, see [Get Started with the Management Libraries for .NET](https://msdn.microsoft.com/en-us/library/dn722415.aspx) and [Using Azure Resource Manager](https://azure.microsoft.com/en-us/documentation/articles/resource-manager-deployment-model/). Note that these samples are in C#. Likewise, other Azure resources may also be deployed and managed from F# scripts using these components. For example, you can create storage accounts, deploy services, create DocumentDB instances and manage Azure Notifcation Hubs programmatically from F# scripts. @@ -55,7 +55,7 @@ Azure Storage is a base layer of storage services for modern applications that r * [Get started with Azure Queue storage using F#](queue-storage.md) * [Get started with Azure Table storage using F#](table-storage.md) -Azure Storage can also be used in conjunction with Azure Functions through declarative configuration rather than explicit API calls. See the information above on using Azure Functions with F#. +Azure Storage can also be used in conjunction with Azure Functions through declarative configuration rather than explicit API calls. See [Azure Functions triggers and bindings for Azure Storage](https://azure.microsoft.com/en-us/documentation/articles/functions-bindings-storage/) which includes F# examples. ## Using Azure DocumentDB with F# # From 87b0f071b646cbfc47febfe76d61e650601a342a Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 28 Sep 2016 19:41:29 +0100 Subject: [PATCH 32/60] Update index.md --- docs/fsharp/using-fsharp-on-azure/index.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index 4c612347a857e..18e3c87ec589d 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -28,12 +28,6 @@ Azure supports a wide range of virtual machine (VM) configurations, see [Linux a To install F# on a virtual machine for execution, compilation and/or scripting see [Using F# on Linux](http://fsharp.org/use/linux) and [Using F# on Windows](http://fsharp.org/use/windows). -## Deploying and Managing Azure Resources with F# Scripts # - -Azure VMs may be programmatically deployed and managed from F# scripts by using the Microsoft.Azure.Management packages and APIs. For example, see [Get Started with the Management Libraries for .NET](https://msdn.microsoft.com/en-us/library/dn722415.aspx) and [Using Azure Resource Manager](https://azure.microsoft.com/en-us/documentation/articles/resource-manager-deployment-model/). Note that these samples are in C#. - -Likewise, other Azure resources may also be deployed and managed from F# scripts using these components. For example, you can create storage accounts, deploy services, create DocumentDB instances and manage Azure Notifcation Hubs programmatically from F# scripts. - ## Using Azure Functions with F# # @@ -98,6 +92,12 @@ Timer triggers call functions based on a schedule, one time or recurring. Timers can be implemented in F# and hosted on Azure via an [Azure Function in F# with a Timer Trigger](https://azure.microsoft.com/en-us/documentation/articles/functions-bindings-timer/). +## Deploying and Managing Azure Resources with F# Scripts # + +Azure VMs may be programmatically deployed and managed from F# scripts by using the Microsoft.Azure.Management packages and APIs. For example, see [Get Started with the Management Libraries for .NET](https://msdn.microsoft.com/en-us/library/dn722415.aspx) and [Using Azure Resource Manager](https://azure.microsoft.com/en-us/documentation/articles/resource-manager-deployment-model/). Note that these samples are in C#. + +Likewise, other Azure resources may also be deployed and managed from F# scripts using the same components. For example, you can create storage accounts, deploy Azure Cloud Services, create Azure DocumentDB instances and manage Azure Notifcation Hubs programmatically from F# scripts. + ## Other resources * [Full documentation on all Azure services](https://azure.microsoft.com/en-us/documentation/) From a86736d5cfb2d6c1bd431c529902777292ddbe51 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 28 Sep 2016 20:06:01 +0100 Subject: [PATCH 33/60] Update index.md --- docs/fsharp/using-fsharp-on-azure/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index 18e3c87ec589d..7681ca09f279d 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -20,7 +20,7 @@ F# is a superb language for cloud programming and is frequently used to write we In the sections below, you will find resources on how to use a range of Azure services with F#. > [!NOTE] -> If a particular Azure service isn't in this documentation set, please consult the C# documentation for that service. Some Azure services are entirely language-independent systems services and require no language-specific documentation, and in this case are not listed here. +> If a particular Azure service isn't in this documentation set, please consult either the Azure Functions or .NET documentation for that service. Some Azure services are entirely language-independent systems services and require no language-specific documentation, and in this case are not listed here. ## Using Azure Virtual Machines with F# # From 6a15ef6802246319618bd50082f9ee21671a3818 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 12:09:40 +0100 Subject: [PATCH 34/60] file share names must be lower case --- samples/snippets/fsharp/azure/file-storage.fsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/fsharp/azure/file-storage.fsx b/samples/snippets/fsharp/azure/file-storage.fsx index 6ea0f3119d8a6..cb61b89cdcde4 100644 --- a/samples/snippets/fsharp/azure/file-storage.fsx +++ b/samples/snippets/fsharp/azure/file-storage.fsx @@ -31,7 +31,7 @@ let fileClient = storageAccount.CreateCloudFileClient() // Create a file share. // -let share = fileClient.GetShareReference("myFiles") +let share = fileClient.GetShareReference("myfiles") share.CreateIfNotExists() // From 0ac5a6af3727a7aeb7e3898ee496e114488aa080 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 12:14:01 +0100 Subject: [PATCH 35/60] Update file-storage.fsx --- samples/snippets/fsharp/azure/file-storage.fsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/samples/snippets/fsharp/azure/file-storage.fsx b/samples/snippets/fsharp/azure/file-storage.fsx index cb61b89cdcde4..bfb27f3b24a99 100644 --- a/samples/snippets/fsharp/azure/file-storage.fsx +++ b/samples/snippets/fsharp/azure/file-storage.fsx @@ -67,11 +67,11 @@ share.SetProperties() // // Create a 24 hour read/write policy. -let policy = SharedAccessFilePolicy() -policy.SharedAccessExpiryTime <- - DateTimeOffset.UtcNow.AddHours(24.) |> Nullable -policy.Permissions <- - SharedAccessFilePermissions.Read ||| SharedAccessFilePermissions.Write +let policy = + SharedAccessFilePolicy( + SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddHours(24.) |> Nullable, + Permissions = SharedAccessFilePermissions.Read ||| SharedAccessFilePermissions.Write + ) // Set the policy on the share. let permissions = share.GetPermissions() @@ -102,10 +102,10 @@ let container = blobClient.GetContainerReference("myContainer") container.CreateIfNotExists() let destBlob = container.GetBlockBlobReference("log_blob.txt") -let filePolicy = SharedAccessFilePolicy() -filePolicy.Permissions <- SharedAccessFilePermissions.Read -filePolicy.SharedAccessExpiryTime <- - DateTimeOffset.UtcNow.AddHours(24.) |> Nullable +let filePolicy = + SharedAccessFilePolicy + (Permissions = SharedAccessFilePermissions.Read, + SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddHours(24.) |> Nullable) let fileSas2 = file.GetSharedAccessSignature(filePolicy) let sasUri2 = Uri(file.StorageUri.PrimaryUri.ToString() + fileSas2) From 4b1d831b82287ada70a1d79eb12c1a6d6b3bf708 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 12:15:22 +0100 Subject: [PATCH 36/60] Update file-storage.fsx --- samples/snippets/fsharp/azure/file-storage.fsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/snippets/fsharp/azure/file-storage.fsx b/samples/snippets/fsharp/azure/file-storage.fsx index bfb27f3b24a99..6ffeb260b2493 100644 --- a/samples/snippets/fsharp/azure/file-storage.fsx +++ b/samples/snippets/fsharp/azure/file-storage.fsx @@ -69,8 +69,8 @@ share.SetProperties() // Create a 24 hour read/write policy. let policy = SharedAccessFilePolicy( - SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddHours(24.) |> Nullable, - Permissions = SharedAccessFilePermissions.Read ||| SharedAccessFilePermissions.Write + SharedAccessExpiryTime = (DateTimeOffset.UtcNow.AddHours(24.) |> Nullable), + Permissions = (SharedAccessFilePermissions.Read ||| SharedAccessFilePermissions.Write) ) // Set the policy on the share. From 7e8a641f854ea07ce261946d48fe8ebfc596d4e9 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 12:15:56 +0100 Subject: [PATCH 37/60] Update file-storage.fsx --- samples/snippets/fsharp/azure/file-storage.fsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/fsharp/azure/file-storage.fsx b/samples/snippets/fsharp/azure/file-storage.fsx index 6ffeb260b2493..f8defad0fc13d 100644 --- a/samples/snippets/fsharp/azure/file-storage.fsx +++ b/samples/snippets/fsharp/azure/file-storage.fsx @@ -105,7 +105,7 @@ let destBlob = container.GetBlockBlobReference("log_blob.txt") let filePolicy = SharedAccessFilePolicy (Permissions = SharedAccessFilePermissions.Read, - SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddHours(24.) |> Nullable) + SharedAccessExpiryTime = (DateTimeOffset.UtcNow.AddHours(24.) |> Nullable)) let fileSas2 = file.GetSharedAccessSignature(filePolicy) let sasUri2 = Uri(file.StorageUri.PrimaryUri.ToString() + fileSas2) From 074b8e2b52dbef017a58f0c2ded302c8a84cec40 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 12:26:45 +0100 Subject: [PATCH 38/60] Adjust file storage to show upload of file --- .../snippets/fsharp/azure/file-storage.fsx | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/samples/snippets/fsharp/azure/file-storage.fsx b/samples/snippets/fsharp/azure/file-storage.fsx index f8defad0fc13d..4b2cdb448495a 100644 --- a/samples/snippets/fsharp/azure/file-storage.fsx +++ b/samples/snippets/fsharp/azure/file-storage.fsx @@ -35,16 +35,25 @@ let share = fileClient.GetShareReference("myfiles") share.CreateIfNotExists() // -// Access the file share programmatically. +// Create a root directory and a subdirectory // let rootDir = share.GetRootDirectoryReference() let subDir = rootDir.GetDirectoryReference("myLogs") +subDir.CreateIfNotExists() -if subDir.Exists() then - let file = subDir.GetFileReference("log.txt") - if file.Exists() then - file.DownloadToFile("log.txt", FileMode.Append) +// +// Upload a file to a subdirectory +// + +let file = subDir.GetFileReference("log.txt") +file.UploadText("This is the content of the log file") + +// +// Download a file to a local fie +// + +file.DownloadToFile("log.txt", FileMode.Append) // // Set the maximum size for a file share. @@ -78,7 +87,6 @@ let permissions = share.GetPermissions() permissions.SharedAccessPolicies.Add("policyName", policy) share.SetPermissions(permissions) -let file = subDir.GetFileReference("log.txt") let sasToken = file.GetSharedAccessSignature(policy) let sasUri = Uri(file.StorageUri.PrimaryUri.ToString() + sasToken) From b3274f6ac446b3097710eadef621e1effb6c7953 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 12:26:57 +0100 Subject: [PATCH 39/60] Adjust references to script --- .../using-fsharp-on-azure/file-storage.md | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/file-storage.md b/docs/fsharp/using-fsharp-on-azure/file-storage.md index 86d80d836557a..e022bdafccb0b 100644 --- a/docs/fsharp/using-fsharp-on-azure/file-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/file-storage.md @@ -73,17 +73,29 @@ 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)] -### Access the file share programmatically +## Create a root directory and a subdirectory -Here, we get the root directory and get a sub-directory of the root. If the sub-directory exists, we get a file in the sub-directory, and if that exists too, we download the file, appending the contents to a local file. +Here, you get the root directory and get a sub-directory of the root. We create both if they don't already exist. -[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L41-L47)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L41-L43)] + +## Upload text as a file + +This example shows how to upload text as a file. + +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L49-L50)] + +### Download a file to a local copy of the 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)] ### 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. -[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L53-L63)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L62-L72)] ### Generate a shared access signature for a file or file share @@ -91,7 +103,7 @@ You can generate a shared access signature (SAS) for a file share or for an indi Here, we 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. -[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L69-L86)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L78-L94)] For more information about creating and using shared access signatures, see [Using Shared Access Signatures (SAS)](https://azure.microsoft.com/en-gb/documentation/articles/storage-dotnet-shared-access-signature-part-1/) and [Create and use a SAS with Blob storage](https://azure.microsoft.com/en-gb/documentation/articles/storage-dotnet-shared-access-signature-part-2/). @@ -103,13 +115,13 @@ You can copy a file to another file, a file to a blob, or a blob to a file. If y Here, we 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#L92-L93)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L100-L101)] ### Copy a file to a blob Here, we create a file and copy it to a blob within the same storage account. We 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#L99-L112)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L107-L120)] 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. @@ -119,7 +131,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#L118-L131)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L126-L139)] ## Next steps From a1237c56b137bd8fc7e529b29cd28c11c5960b46 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 12:51:42 +0100 Subject: [PATCH 40/60] Update queue-storage.fsx --- .../snippets/fsharp/azure/queue-storage.fsx | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/samples/snippets/fsharp/azure/queue-storage.fsx b/samples/snippets/fsharp/azure/queue-storage.fsx index 25eb9adeb59f6..855caab616141 100644 --- a/samples/snippets/fsharp/azure/queue-storage.fsx +++ b/samples/snippets/fsharp/azure/queue-storage.fsx @@ -52,21 +52,28 @@ let peekedMessage = queue.PeekMessage() let msgAsString = peekedMessage.AsString // -// Change the contents of a queued message. +// Get the next message. +// + +// Get the next message. Successful processing must be indicated via DeleteMessage later. +let retrieved = queue.GetMessage() + +// +// Change the contents of a retrieved message. // // Update the message contents and set a new timeout. -message.SetMessageContent("Updated contents.") -queue.UpdateMessage(message, +retrieved.SetMessageContent("Updated contents.") +queue.UpdateMessage(retrieved, TimeSpan.FromSeconds(60.0), MessageUpdateFields.Content ||| MessageUpdateFields.Visibility) // -// De-queue the next message. +// De-queue the next message, indicating successful processing // // Process the message in less than 30 seconds, and then delete the message. -queue.DeleteMessage(message) +queue.DeleteMessage(retrieved) // // Use Async-Await pattern with common Queue storage APIs. @@ -74,10 +81,13 @@ queue.DeleteMessage(message) async { let! exists = queue.CreateIfNotExistsAsync() |> Async.AwaitTask - let msg = new CloudQueueMessage("My message") - queue.AddMessageAsync(msg) |> Async.AwaitTask + let! retrieved = queue.GetMessageAsync() |> Async.AwaitTask - queue.DeleteMessageAsync(retrieved) |> Async.AwaitTask + + // ... process the message here ... + + // Now indicate successful processing: + do! queue.DeleteMessageAsync(retrieved) |> Async.AwaitTask } // From 9e3d508a7bfdf137be97521d278fb556c809e1d0 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 12:51:47 +0100 Subject: [PATCH 41/60] Update queue-storage.md --- .../using-fsharp-on-azure/queue-storage.md | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/queue-storage.md b/docs/fsharp/using-fsharp-on-azure/queue-storage.md index a227b11818344..9889a0e60aa46 100644 --- a/docs/fsharp/using-fsharp-on-azure/queue-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/queue-storage.md @@ -93,9 +93,17 @@ from the queue, by calling the `PeekMessage` method. [!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L50-L52)] +## Get the next message for processing + +You can retrieve the message at the front of a queue for processing by calling the `GetMessage` method. + +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L58-L59)] + +You later indicate successful processing of the message by using `DeleteMessage`. + ## Change the contents of a queued message -You can change the contents of a message in-place in the queue. If the +You can change the contents of a retrieved message in-place in the queue. If the message represents a work task, you could use this feature to update the status of the work task. The following code updates the queue message with new contents, and sets the visibility timeout to extend another 60 @@ -108,7 +116,7 @@ you would keep a retry count as well, and if the message is retried more than some number of times, you would delete it. This protects against a message that triggers an application error each time it is processed. -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L58-L62)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L65-L69)] ## De-queue the next message @@ -123,13 +131,13 @@ software failure, another instance of your code can get the same message and try again. Your code calls `DeleteMessage` right after the message has been processed. -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L68-L69)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L75-L76)] ## Use Async-Await pattern with common Queue storage APIs This example shows how to use an async workflow with common Queue storage APIs. -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L75-L81)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L82-L91)] ## Additional options for de-queuing messages @@ -143,20 +151,20 @@ each message. Note that the 5 minutes starts for all messages at the same time, so after 5 minutes have passed since the call to `GetMessages`, any messages which have not been deleted will become visible again. -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L87-L89)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L97-L99)] ## Get the queue length You can get an estimate of the number of messages in a queue. The `FetchAttributes` method asks the Queue service to retrieve the queue attributes, including the message count. The `ApproximateMessageCount` property returns the last value retrieved by the `FetchAttributes` method, without calling the Queue service. -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L95-L96)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L105-L106)] ## Delete a queue To delete a queue and all the messages contained in it, call the `Delete` method on the queue object. -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L102-L103)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L112-L113)] ## Next steps @@ -164,6 +172,7 @@ Now that you've learned the basics of Queue storage, follow these links to learn about more complex storage tasks. - [Storage Client Library for .NET reference](http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409) +- [Azure Storage Type Provider](https://github.com/fsprojects/AzureStorageTypeProvider) - [Azure Storage Team Blog](http://blogs.msdn.com/b/windowsazurestorage/) - [Configuring Connection Strings](http://msdn.microsoft.com/library/azure/ee758697.aspx) - [REST API reference](http://msdn.microsoft.com/library/azure/dd179355) From e3b0c86935dcb897c6d5985ee815711b37dcc60a Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 14:01:56 +0100 Subject: [PATCH 42/60] Updates to make tables script run end-to-end --- .../using-fsharp-on-azure/table-storage.md | 61 +++++++++++-------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/table-storage.md b/docs/fsharp/using-fsharp-on-azure/table-storage.md index 0f11e702fa692..6b1b2c19e8183 100644 --- a/docs/fsharp/using-fsharp-on-azure/table-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -87,11 +87,11 @@ An entity's partition and row key uniquely identify the entity in the table. Ent Here's an example of a `Customer` that uses the `lastName` as the partition key and the `firstName` as the row key. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L45-L53)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L45-L52)] -Now we'll add our `Customer` to the table. To do so, we create a `TableOperation` that we will execute on the table. In this case, we create an `Insert` operation. +Now we'll add our `Customer` to the table. To do so, you create a `TableOperation` that will execute on the table. In this case, you create an `Insert` operation. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L55-L56)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L54-L55)] ## Insert a batch of entities @@ -104,61 +104,74 @@ You can insert a batch of entities into a table using a single write operation. Here's some code that combines two inserts into a batch operation: -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L62-L68)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L62-L71)] ## Retrieve all entities in a partition -To query a table for all entities in a partition, use a `TableQuery` object. Here, we filter for entities where "Buster" is the partition key. +To query a table for all entities in a partition, use a `TableQuery` object. Here, you filter for entities where "Buster" is the partition key. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L74-L79)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L77-L85)] ## Retrieve a range of entities in a partition -If you don't want to query all the entities in a partition, you can specify a range by combining the partition key filter with a row key filter. Here, we use two filters to get all entities in the "Buster" partition where the row key (first name) starts with a letter earlier than "M" in the alphabet. +If you don't want to query all the entities in a partition, you can specify a range by combining the partition key filter with a row key filter. Here, you use two filters to get all entities in the "Buster" partition where the row key (first name) starts with a letter earlier than "M" in the alphabet. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L85-L94)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L91-L98)] + +We now execute the query and print the results: + +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L100-L103)] ## Retrieve a single entity -You can write a query to retrieve a single, specific entity. Here, we use a `TableOperation` to specify the customer "Larry Buster". Instead of a collection, we get back a `Customer`. Specifying both the partition key and the row key in a query is the fastest way to retrieve a single entity from the Table service. +You can write a query to retrieve a single, specific entity. Here, you use a `TableOperation` to specify the customer "Larry Buster". Instead of a collection, you get back a `Customer`. Specifying both the partition key and the row key in a query is the fastest way to retrieve a single entity from the Table service. + +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L109-L109)] + +We now execute the query and print the results: + +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L111-L114)] -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L100-L101)] ## Replace an entity To update an entity, retrieve it from the Table service, modify the entity object, and then save the changes back to the Table service using a `Replace` operation. This causes the entity to be fully replaced on the server, unless the entity on the server has changed since it was retrieved, in which case the operation will fail. This failure is to prevent your application from inadvertently overwriting changes from other sources. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L107-L113)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L120-L127)] ## Insert-or-replace an entity -Sometimes, you don't know if the entity exists in the table or not. And if it does, the current values stored in it are no longer needed. We can use `InsertOrReplace` to create the entity, or replace it if it exists, regardless of its state. +Sometimes, you don't know if the entity exists in the table or not. And if it does, the current values stored in it are no longer needed. You can use `InsertOrReplace` to create the entity, or replace it if it exists, regardless of its state. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L119-L124)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L133-L139)] ## Query a subset of entity properties -A table query can retrieve just a few properties from an entity instead of all of them. This technique, called projection, can improve query performance, especially for large entities. Here, we return only email addresses using `DynamicTableEntity` and `EntityResolver`. Note that projection is not supported on the local storage emulator, so this code runs only when you're using an account on the Table service. +A table query can retrieve just a few properties from an entity instead of all of them. This technique, called projection, can improve query performance, especially for large entities. Here, you return only email addresses using `DynamicTableEntity` and `EntityResolver`. Note that projection is not supported on the local storage emulator, so this code runs only when you're using an account on the Table service. + +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L145-L156)] + +## Retrieve entities in pages asynchronously -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L130-L141)] +If you are reading a large number of entities, and you want to process them as they are retrieved rather than waiting for them all to return, you can use a segmented query. Here, you return results in pages by using an async workflow so that execution is not blocked while you're waiting for a large set of results to return. + +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L162-L174)] + +You now execute this computation synchronously: + +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L176-L176)] ## Delete an entity You can delete an entity after you have retrieved it. As with updating an entity, this will fail if the entity has changed since you retrieved it. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L147-L148)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L182-L183)] ## Delete a table You can delete a table from a storage account. A table that has been deleted will be unavailable to be re-created for a period of time following the deletion. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L154-L154)] - -## Retrieve entities in pages asynchronously - -If you are reading a large number of entities, and you want to process them as they are retrieved rather than waiting for them all to return, you can use a segmented query. Here, we return results in pages by using an async workflow so that execution is not blocked while you're waiting for a large set of results to return. - -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L160-L174)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L189-L189)] ## Next steps @@ -166,7 +179,7 @@ Now that you've learned the basics of Table storage, follow these links to learn about more complex storage tasks: - [Storage Client Library for .NET reference](http://go.microsoft.com/fwlink/?LinkID=390731&clcid=0x409) +- [Azure Storage Type Provider](http://fsprojects.github.io/AzureStorageTypeProvider/) - [Azure Storage Team Blog](http://blogs.msdn.com/b/windowsazurestorage/) - [Configuring Connection Strings](http://msdn.microsoft.com/library/azure/ee758697.aspx) -- [REST API reference](http://msdn.microsoft.com/library/azure/dd179355) - [Getting Started with Azure Table Storage in .NET](https://azure.microsoft.com/documentation/samples/storage-table-dotnet-getting-started/) From 10a1cae3511278a854c6f3af1d93a9571241150e Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 14:02:04 +0100 Subject: [PATCH 43/60] Update table-storage.fsx --- .../snippets/fsharp/azure/table-storage.fsx | 78 +++++++++++-------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/samples/snippets/fsharp/azure/table-storage.fsx b/samples/snippets/fsharp/azure/table-storage.fsx index 5a2567698dbf3..09775b414c36a 100644 --- a/samples/snippets/fsharp/azure/table-storage.fsx +++ b/samples/snippets/fsharp/azure/table-storage.fsx @@ -9,11 +9,11 @@ open Microsoft.WindowsAzure.Storage.Table // Namespace for Table storage types // let storageConnString = "..." // fill this in from your storage account - +(* // Parse the connection string and return a reference to the storage account. let storageConnString = CloudConfigurationManager.GetSetting("StorageConnectionString") - +*) // // Parse the connection string. // @@ -39,31 +39,34 @@ let table = tableClient.GetTableReference("people") table.CreateIfNotExists() // -// Add an entity to a table. +// Add an entity to a table. The last name is used as a partition key. // -type Customer - (firstName, lastName, email: string, phone: string) = - inherit TableEntity(lastName, firstName) +type Customer(firstName, lastName, email: string, phone: string) = + inherit TableEntity(partitionKey=lastName, rowKey=firstName) new() = Customer(null, null, null, null) member val Email = email with get, set member val PhoneNumber = phone with get, set let customer = - Customer("Larry", "Buster", "larry@example.com", "425-555-0101") + Customer("Larry", "Boomer", "larry@example.com", "425-555-0101") let insertOp = TableOperation.Insert(customer) table.Execute(insertOp) + // -// Insert a batch of entities. +// Insert a batch of entities. All must have the same partition key. // +let customer1 = + Customer("Bob", "Buster", "bob@example.com", "425-555-0102") + let customer2 = - Customer("Bob", "Boomer", "bob@example.com", "425-555-0102") + Customer("Jenny", "Buster", "jenny@example.com", "425-555-0102") let batchOp = TableBatchOperation() -batchOp.Insert(customer) +batchOp.Insert(customer1) batchOp.Insert(customer2) table.ExecuteBatch(batchOp) @@ -78,6 +81,9 @@ let query = let result = table.ExecuteQuery(query) +for customer in result do + printfn "customer: %A %A" customer.RowKey customer.PartitionKey + // // Retrieve a range of entities in a partition. // @@ -93,12 +99,19 @@ let range = let rangeResult = table.ExecuteQuery(query) +for customer in rangeResult do + printfn "customer: %A %A" customer.RowKey customer.PartitionKey + // // Retrieve a single entity. // let retrieveOp = TableOperation.Retrieve("Buster", "Larry") + +// Execute the query and show the result let retrieveResult = table.Execute(retrieveOp) +let retrieveCustomer = retrieveResult.Result :?> Customer +printfn "customer: %A %A" retrieveCustomer.RowKey retrieveCustomer.PartitionKey // // Replace an entity. @@ -109,6 +122,7 @@ try customer.PhoneNumber <- "425-555-0103" let replaceOp = TableOperation.Replace(customer) table.Execute(replaceOp) |> ignore + Console.WriteLine("Update succeeeded") with e -> Console.WriteLine("Update failed") @@ -120,6 +134,7 @@ try customer.PhoneNumber <- "425-555-0104" let replaceOp = TableOperation.InsertOrReplace(customer) table.Execute(replaceOp) |> ignore + Console.WriteLine("Update succeeeded") with e -> Console.WriteLine("Update failed") @@ -128,7 +143,7 @@ with e -> // // Define the query, and select only the Email property. -let projectionQ = TableQuery().Select([|"Email"|]) +let projectionQ = TableQuery().Select [|"Email"|] // Define an entity resolver to work with the entity after retrieval. let resolver = EntityResolver(fun pk rk ts props etag -> @@ -138,7 +153,27 @@ let resolver = EntityResolver(fun pk rk ts props etag -> null ) -table.ExecuteQuery(projectionQ, resolver, null, null) +let resolvedResults = table.ExecuteQuery(projectionQ, resolver, null, null) + +// +// Retrieve entities in pages asynchronously. +// + +let tableQ = TableQuery() + +let asyncQuery = + let rec loop (cont: TableContinuationToken) = async { + let! ct = Async.CancellationToken + let! result = table.ExecuteQuerySegmentedAsync(tableQ, cont, ct) |> Async.AwaitTask + + // Process the result here. + match result.ContinuationToken with + | null -> () + | cont -> return! loop cont + } + loop null + +let asyncResults = asyncQuery |> Async.RunSynchronously // // Delete an entity. @@ -153,22 +188,3 @@ table.Execute(deleteOp) table.DeleteIfExists() -// -// Retrieve entities in pages asynchronously. -// - -let tableQ = TableQuery() - -async { - let rec q (cont: TableContinuationToken) = async { - let! result = - table.ExecuteQuerySegmentedAsync(tableQ, cont) - |> Async.AwaitTask - - // Process the result here. - match result.ContinuationToken with - | null -> return () - | cont -> q cont |> Async.RunSynchronously - } - q null |> Async.RunSynchronously -} |> Async.RunSynchronously From 55b78432a6786a0ca44fa4821b90c83181d08b4e Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 14:05:04 +0100 Subject: [PATCH 44/60] Update blob-storage.fsx --- samples/snippets/fsharp/azure/blob-storage.fsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/snippets/fsharp/azure/blob-storage.fsx b/samples/snippets/fsharp/azure/blob-storage.fsx index 2032bc761a8c3..5f649c54a9f12 100644 --- a/samples/snippets/fsharp/azure/blob-storage.fsx +++ b/samples/snippets/fsharp/azure/blob-storage.fsx @@ -9,11 +9,11 @@ open Microsoft.WindowsAzure.Storage.Blob // Namespace for Blob storage types // let storageConnString = "..." // fill this in from your storage account - +(* // Parse the connection string and return a reference to the storage account. let storageConnString = CloudConfigurationManager.GetSetting("StorageConnectionString") - +*) // // Parse the connection string. // From e6bc93113578f12eb8848f6997b2f77e7d85f1ff Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 14:05:20 +0100 Subject: [PATCH 45/60] Update file-storage.fsx --- samples/snippets/fsharp/azure/file-storage.fsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/snippets/fsharp/azure/file-storage.fsx b/samples/snippets/fsharp/azure/file-storage.fsx index 4b2cdb448495a..8896c8ee52040 100644 --- a/samples/snippets/fsharp/azure/file-storage.fsx +++ b/samples/snippets/fsharp/azure/file-storage.fsx @@ -9,11 +9,11 @@ open Microsoft.WindowsAzure.Storage.File // Namespace for File storage types // let storageConnString = "..." // fill this in from your storage account - +(* // Parse the connection string and return a reference to the storage account. let storageConnString = CloudConfigurationManager.GetSetting("StorageConnectionString") - +*) // // Parse the connection string. // From d8cde3c5e07d71989a70a7e6c350244c64e3b548 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 14:05:43 +0100 Subject: [PATCH 46/60] Update queue-storage.fsx --- samples/snippets/fsharp/azure/queue-storage.fsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/snippets/fsharp/azure/queue-storage.fsx b/samples/snippets/fsharp/azure/queue-storage.fsx index 855caab616141..0d03a91eca959 100644 --- a/samples/snippets/fsharp/azure/queue-storage.fsx +++ b/samples/snippets/fsharp/azure/queue-storage.fsx @@ -7,11 +7,11 @@ open Microsoft.WindowsAzure.Storage.Queue // Namespace for Queue storage types // let storageConnString = "..." // fill this in from your storage account - +(* // Parse the connection string and return a reference to the storage account. let storageConnString = CloudConfigurationManager.GetSetting("StorageConnectionString") - +*) // // Parse the connection string. // From 4c986ae336413b3015bc684bf6c3bf015c7fa51c Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 14:06:33 +0100 Subject: [PATCH 47/60] Update blob-storage.md --- docs/fsharp/using-fsharp-on-azure/blob-storage.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/blob-storage.md b/docs/fsharp/using-fsharp-on-azure/blob-storage.md index a4fefce316052..3fac5ca98c394 100644 --- a/docs/fsharp/using-fsharp-on-azure/blob-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/blob-storage.md @@ -62,7 +62,7 @@ This will return a `CloudStorageAccount`. ### Create some local dummy data -Before we begin, create some dummy local data in the directory of our script. Later you will upload this data. +Before you begin, create some dummy local data in the directory of our script. Later you will upload this data. [!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L28-L30)] @@ -163,12 +163,12 @@ Because the sample method calls an asynchronous method, it must be prefaced with [!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L122-L160)] -We can now use this asynchronous routine as follows. First we upload some dummy data (using the local +We can now use this asynchronous routine as follows. First you upload some dummy data (using the local file created earlier in this tutorial). [!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L162-L166)] -Now, call the routine. We use ``Async.RunSynchronously`` to force the execution of the asynchronous operation. +Now, call the routine. You use ``Async.RunSynchronously`` to force the execution of the asynchronous operation. [!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L168-L168)] From cb7b77bde1340a5d3539d66f50b8004afab31f89 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 14:07:18 +0100 Subject: [PATCH 48/60] Update file-storage.md --- docs/fsharp/using-fsharp-on-azure/file-storage.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/file-storage.md b/docs/fsharp/using-fsharp-on-azure/file-storage.md index e022bdafccb0b..1a68aee811f39 100644 --- a/docs/fsharp/using-fsharp-on-azure/file-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/file-storage.md @@ -75,7 +75,7 @@ This example shows how to create a file share if it does not already exist: ## Create a root directory and a subdirectory -Here, you get the root directory and get a sub-directory of the root. We create both if they don't already exist. +Here, you get the root directory and get a sub-directory of the root. You create both if they don't already exist. [!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L41-L43)] @@ -101,7 +101,7 @@ The example below shows how to check the current usage for a share and how to se 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. -Here, we 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 policy on a share, and then use that policy 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)] @@ -113,13 +113,13 @@ You can copy a file to another file, a file to a blob, or a blob to a file. If y ### Copy a file to another file -Here, we 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. +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)] ### Copy a file to a blob -Here, we create a file and copy it to a blob within the same storage account. We create a SAS for the source file, which the service uses to authenticate access to the source file during the copy operation. +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)] From e75e8ca161e0d257ff2b8bebe426029c034cb300 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 14:08:34 +0100 Subject: [PATCH 49/60] Update blob-storage.fsx --- samples/snippets/fsharp/azure/blob-storage.fsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/fsharp/azure/blob-storage.fsx b/samples/snippets/fsharp/azure/blob-storage.fsx index 5f649c54a9f12..8d5c42a5d283a 100644 --- a/samples/snippets/fsharp/azure/blob-storage.fsx +++ b/samples/snippets/fsharp/azure/blob-storage.fsx @@ -25,7 +25,7 @@ let storageAccount = CloudStorageAccount.Parse(storageConnString) // Create some local dummy data. // -// Create a dummy file in a local subdirectory to upload +// Create a dummy file to upload let localFile = __SOURCE_DIRECTORY__ + "/myfile.txt" File.WriteAllText(localFile, "some data") From cd85cc66251aecd9210cce01488b395daa79a641 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 14:09:51 +0100 Subject: [PATCH 50/60] Update index.md --- docs/fsharp/using-fsharp-on-azure/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index 7681ca09f279d..eb25869a55d50 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -2,7 +2,7 @@ title: Using F# on Azure description: Guide to using Azure services with F# keywords: Azure, cloud, visual f#, f#, functional programming, .NET, .NET Core -author: dsyme +author: sylvanc manager: jbronsk ms.date: 09/22/2016 ms.topic: article From 5d05fc01fa7bf4bf20eec66901d2c2eac4e9fe11 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 14:15:32 +0100 Subject: [PATCH 51/60] Update table-storage.fsx --- samples/snippets/fsharp/azure/table-storage.fsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/samples/snippets/fsharp/azure/table-storage.fsx b/samples/snippets/fsharp/azure/table-storage.fsx index 09775b414c36a..a9cc766ee3bab 100644 --- a/samples/snippets/fsharp/azure/table-storage.fsx +++ b/samples/snippets/fsharp/azure/table-storage.fsx @@ -108,8 +108,9 @@ for customer in rangeResult do let retrieveOp = TableOperation.Retrieve("Buster", "Larry") -// Execute the query and show the result let retrieveResult = table.Execute(retrieveOp) + +// Show the result let retrieveCustomer = retrieveResult.Result :?> Customer printfn "customer: %A %A" retrieveCustomer.RowKey retrieveCustomer.PartitionKey @@ -166,7 +167,9 @@ let asyncQuery = let! ct = Async.CancellationToken let! result = table.ExecuteQuerySegmentedAsync(tableQ, cont, ct) |> Async.AwaitTask - // Process the result here. + // ...process the result here... + + // Continue to the next segment match result.ContinuationToken with | null -> () | cont -> return! loop cont From 21b3b30b11814fd390bcd513e2bc3fc334ca15cd Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 14:15:36 +0100 Subject: [PATCH 52/60] Update table-storage.md --- .../using-fsharp-on-azure/table-storage.md | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/table-storage.md b/docs/fsharp/using-fsharp-on-azure/table-storage.md index 6b1b2c19e8183..8c22d26c23765 100644 --- a/docs/fsharp/using-fsharp-on-azure/table-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -110,27 +110,32 @@ Here's some code that combines two inserts into a batch operation: To query a table for all entities in a partition, use a `TableQuery` object. Here, you filter for entities where "Buster" is the partition key. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L77-L85)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L77-L80)] + +You now print the results: + +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L84-L85)] + ## Retrieve a range of entities in a partition If you don't want to query all the entities in a partition, you can specify a range by combining the partition key filter with a row key filter. Here, you use two filters to get all entities in the "Buster" partition where the row key (first name) starts with a letter earlier than "M" in the alphabet. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L91-L98)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L91-L100)] -We now execute the query and print the results: +You now print the results: -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L100-L103)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L102-L103)] ## Retrieve a single entity You can write a query to retrieve a single, specific entity. Here, you use a `TableOperation` to specify the customer "Larry Buster". Instead of a collection, you get back a `Customer`. Specifying both the partition key and the row key in a query is the fastest way to retrieve a single entity from the Table service. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L109-L109)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L109-L111)] -We now execute the query and print the results: +You now print the results: -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L111-L114)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L113-L115)] ## Replace an entity @@ -155,23 +160,23 @@ A table query can retrieve just a few properties from an entity instead of all o If you are reading a large number of entities, and you want to process them as they are retrieved rather than waiting for them all to return, you can use a segmented query. Here, you return results in pages by using an async workflow so that execution is not blocked while you're waiting for a large set of results to return. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L162-L174)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L165-L177)] You now execute this computation synchronously: -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L176-L176)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L179-L179)] ## Delete an entity You can delete an entity after you have retrieved it. As with updating an entity, this will fail if the entity has changed since you retrieved it. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L182-L183)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L185-L186)] ## Delete a table You can delete a table from a storage account. A table that has been deleted will be unavailable to be re-created for a period of time following the deletion. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L189-L189)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L192-L192)] ## Next steps From 68488daeb509329f5d79b5f2f5abb8bf2e96d500 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 14:16:23 +0100 Subject: [PATCH 53/60] Update table-storage.md --- docs/fsharp/using-fsharp-on-azure/table-storage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fsharp/using-fsharp-on-azure/table-storage.md b/docs/fsharp/using-fsharp-on-azure/table-storage.md index 8c22d26c23765..304696efe9a5f 100644 --- a/docs/fsharp/using-fsharp-on-azure/table-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -160,7 +160,7 @@ A table query can retrieve just a few properties from an entity instead of all o If you are reading a large number of entities, and you want to process them as they are retrieved rather than waiting for them all to return, you can use a segmented query. Here, you return results in pages by using an async workflow so that execution is not blocked while you're waiting for a large set of results to return. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L165-L177)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L163-L177)] You now execute this computation synchronously: From ceb974720188115fe1ad6b3135683a2c384d5ded Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 29 Sep 2016 14:17:53 +0100 Subject: [PATCH 54/60] Update index.md --- docs/fsharp/using-fsharp-on-azure/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index eb25869a55d50..478d21dd6aa71 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -33,7 +33,7 @@ To install F# on a virtual machine for execution, compilation and/or scripting s [Azure Functions](https://azure.microsoft.com/en-us/services/functions/) is a solution for easily running small pieces of code, or "functions," in the cloud. You can write just the code you need for the problem at hand, without worrying about a whole application or the infrastructure to run it. Your functions are connected to events in Azure storage and other cloud-hosted resources. Data flows into your F# functions via function arguments. You can use your development language of choice, trusting Azure to scale as needed. -Azure Functions support F# as a first-class language with efficient, reactive, scalable execution of F# code. See the [Azure Functions F# Developer Reference](https://azure.microsoft.com/en-us/documentation/articles/functions-reference-fsharp/) for reference doccumentation on how to use F# with Azure Functions. +Azure Functions support F# as a first-class language with efficient, reactive, scalable execution of F# code. See the [Azure Functions F# Developer Reference](https://azure.microsoft.com/en-us/documentation/articles/functions-reference-fsharp/) for reference documentation on how to use F# with Azure Functions. Other resources for using Azure Functions and F#: From 7e3e03e79d9103e1ae506f603e3041c56033048e Mon Sep 17 00:00:00 2001 From: Don Syme Date: Fri, 30 Sep 2016 12:32:09 +0100 Subject: [PATCH 55/60] Minor updates --- docs/fsharp/using-fsharp-on-azure/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index 478d21dd6aa71..0ce5ad95fa01a 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -20,7 +20,7 @@ F# is a superb language for cloud programming and is frequently used to write we In the sections below, you will find resources on how to use a range of Azure services with F#. > [!NOTE] -> If a particular Azure service isn't in this documentation set, please consult either the Azure Functions or .NET documentation for that service. Some Azure services are entirely language-independent systems services and require no language-specific documentation, and in this case are not listed here. +> If a particular Azure service isn't in this documentation set, please consult either the Azure Functions or .NET documentation for that service. Some Azure services are language-independent and require no language-specific documentation and are not listed here. ## Using Azure Virtual Machines with F# # @@ -72,7 +72,7 @@ Azure Event Hubs can be used with F# in two ways: ## Using Azure Notifcation Hubs with F# # -[Azure Notification Hubs](https://azure.microsoft.com/en-us/documentation/services/notification-hubs/) are multiplatform, scaled-out push infrastructure that enables you to send mobile push notifications from any backend (in the cloud or on-premises) to any mobile platform. +[Azure Notification Hubs](https://azure.microsoft.com/en-us/documentation/services/notification-hubs/) are multiplatform, scaled-out push infrastructure that enable you to send mobile push notifications from any backend (in the cloud or on-premises) to any mobile platform. Azure Notification Hubs can be used with F# in two ways: From 2bef36e434b0f46ba99f3b570343e924b63f35a4 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Fri, 30 Sep 2016 16:49:16 +0100 Subject: [PATCH 56/60] Update index.md --- docs/fsharp/using-fsharp-on-azure/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index 0ce5ad95fa01a..0631808580579 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -94,10 +94,12 @@ Timers can be implemented in F# and hosted on Azure via an [Azure Function in F# ## Deploying and Managing Azure Resources with F# Scripts # -Azure VMs may be programmatically deployed and managed from F# scripts by using the Microsoft.Azure.Management packages and APIs. For example, see [Get Started with the Management Libraries for .NET](https://msdn.microsoft.com/en-us/library/dn722415.aspx) and [Using Azure Resource Manager](https://azure.microsoft.com/en-us/documentation/articles/resource-manager-deployment-model/). Note that these samples are in C#. +Azure VMs may be programmatically deployed and managed from F# scripts by using the Microsoft.Azure.Management packages and APIs. For example, see [Get Started with the Management Libraries for .NET](https://msdn.microsoft.com/en-us/library/dn722415.aspx) and [Using Azure Resource Manager](https://azure.microsoft.com/en-us/documentation/articles/resource-manager-deployment-model/). Likewise, other Azure resources may also be deployed and managed from F# scripts using the same components. For example, you can create storage accounts, deploy Azure Cloud Services, create Azure DocumentDB instances and manage Azure Notifcation Hubs programmatically from F# scripts. +Using F# scripts to deploy and manage resources is not normally necessary. For example, Azure resources may also be deployed directy from JSON template descriptions, which can be parameterized. See [Azure Resource Manager Templates](https://azure.microsoft.com/en-us/documentation/articles/resource-manager-template-best-practices/) including examples such as the [Azure Quickstart Templates](Azure Quickstart Templates). + ## Other resources * [Full documentation on all Azure services](https://azure.microsoft.com/en-us/documentation/) From 4bf98214ef0808dd366a8eb0eef488f019add338 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Fri, 7 Oct 2016 18:10:09 +0100 Subject: [PATCH 57/60] updates from review --- .../using-fsharp-on-azure/blob-storage.md | 36 ++++++++++--------- .../using-fsharp-on-azure/file-storage.md | 10 +++--- docs/fsharp/using-fsharp-on-azure/index.md | 5 ++- .../using-fsharp-on-azure/queue-storage.md | 8 ++--- .../using-fsharp-on-azure/table-storage.md | 10 +++--- .../snippets/fsharp/azure/blob-storage.fsx | 12 +++---- .../snippets/fsharp/azure/file-storage.fsx | 29 +++++++-------- .../snippets/fsharp/azure/table-storage.fsx | 12 +++---- 8 files changed, 63 insertions(+), 59 deletions(-) diff --git a/docs/fsharp/using-fsharp-on-azure/blob-storage.md b/docs/fsharp/using-fsharp-on-azure/blob-storage.md index 3fac5ca98c394..28e5a11173a2c 100644 --- a/docs/fsharp/using-fsharp-on-azure/blob-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/blob-storage.md @@ -6,8 +6,8 @@ author: sylvanc manager: jbronsk ms.date: 09/20/2016 ms.topic: article -ms.prod: .net-core -ms.technology: .net-core-technologies +ms.prod: visual-studio-dev14 +ms.technology: devlang-fsharp ms.devlang: dotnet ms.assetid: c5b74a4f-dcd1-4849-930c-904b6c8a04e1 --- @@ -38,9 +38,9 @@ Add the following `open` statements to the top of the `blobs.fsx` file: ### 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](https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/). +You need an Azure Storage connection string for this tutorial. For more information about connection strings, see [Configure Storage Connection Strings](https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/). -For the tutorial, you'll enter your connection string in your script, like this: +For the tutorial, you enter your connection string in your script, like this: [!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L11)] @@ -58,11 +58,11 @@ To parse the connection string, use: [!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L21-L22)] -This will return a `CloudStorageAccount`. +This returns a `CloudStorageAccount`. ### Create some local dummy data -Before you begin, create some dummy local data in the directory of our script. Later you will upload this data. +Before you begin, create some dummy local data in the directory of our script. Later you upload this data. [!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L28-L30)] @@ -88,11 +88,11 @@ Anyone on the Internet can see blobs in a public container, but you can modify o ## Upload a blob into a container -Azure Blob Storage supports block blobs and page blobs. In the majority of cases, a block blob is the recommended type to use. +Azure Blob Storage supports block blobs and page blobs. In most cases, a block blob is the recommended type to use. -To upload a file to a block blob, get a container reference and use it to get a block blob reference. Once you have a blob reference, you can upload any stream of data to it by calling the `UploadFromStream` method. This operation will create the blob if it didn't previously exist, or overwrite it if it does exist. +To upload a file to a block blob, get a container reference and use it to get a block blob reference. Once you have a blob reference, you can upload any stream of data to it by calling the `UploadFromFile` method. This operation creates the blob if it didn't previously exist, or overwrite it if it does exist. -[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L55-L61)] +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L55-L59)] ## List the blobs in a container @@ -100,10 +100,11 @@ To list the blobs in a container, first get a container reference. You can then [!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L67-L80)] -As shown above, you can name blobs with path information in their names. This creates a virtual directory structure that you can organize and traverse as you would a traditional file system. Note that the directory structure is virtual only - the only resources available in Blob storage are containers and blobs. However, the storage client library offers a `CloudBlobDirectory` object to refer to a virtual directory and simplify the process of working with blobs that are organized in this way. +You can also name blobs with path information in their names. This creates a virtual directory structure that you can organize and traverse as you would a traditional file system. Note that the directory structure is virtual only - the only resources available in Blob storage are containers and blobs. However, the storage client library offers a `CloudBlobDirectory` object to refer to a virtual directory and simplify the process of working with blobs that are organized in this way. For example, consider the following set of block blobs in a container named `photos`: +```none photo1.jpg 2015/architecture/description.txt 2015/architecture/photo3.jpg @@ -112,13 +113,15 @@ For example, consider the following set of block blobs in a container named `pho 2016/architecture/photo6.jpg 2016/architecture/description.txt 2016/photo7.jpg +``` -When you call `ListBlobs` on the 'photos' container (as in the above sample), a hierarchical listing is returned. It contains both `CloudBlobDirectory` and `CloudBlockBlob` objects, representing the directories and blobs in the container, respectively. The resulting output looks like: +When you call `ListBlobs` on a container (as in the above sample), a hierarchical listing is returned. If it contains both `CloudBlobDirectory` and `CloudBlockBlob` objects, representing the directories and blobs in the container, respectively, then the resulting output looks similar to this: +```none Directory: https://.blob.core.windows.net/photos/2015/ Directory: https://.blob.core.windows.net/photos/2016/ Block blob of length 505623: https://.blob.core.windows.net/photos/photo1.jpg - +``` Optionally, you can set the `UseFlatBlobListing` parameter of the `ListBlobs` method to `true`. In this case, every blob in the container is returned as a `CloudBlockBlob` object. The call to `ListBlobs` to return a flat listing looks like this: @@ -126,6 +129,7 @@ Optionally, you can set the `UseFlatBlobListing` parameter of the `ListBlobs` me and, depending on the current contents of your container, the results look like this: +```none Block blob of length 4: https://.blob.core.windows.net/photos/2015/architecture/description.txt Block blob of length 314618: https://.blob.core.windows.net/photos/2015/architecture/photo3.jpg Block blob of length 522713: https://.blob.core.windows.net/photos/2015/architecture/photo4.jpg @@ -134,7 +138,7 @@ and, depending on the current contents of your container, the results look like Block blob of length 506388: https://.blob.core.windows.net/photos/2016/architecture/photo6.jpg Block blob of length 399751: https://.blob.core.windows.net/photos/2016/photo7.jpg Block blob of length 505623: https://.blob.core.windows.net/photos/photo1.jpg - +``` ## Download blobs @@ -159,7 +163,7 @@ If you are listing a large number of blobs, or you want to control the number of This example shows a flat blob listing, but you can also perform a hierarchical listing, by setting the `useFlatBlobListing` parameter of the `ListBlobsSegmentedAsync` method to `false`. -Because the sample method calls an asynchronous method, it must be prefaced with the `async` keyword, and it must return a `Task` object. The await keyword specified for the `ListBlobsSegmentedAsync` method suspends execution of the sample method until the listing task completes. +The sample defines an asynchronous method, using an `async` block. The ``let!`` keyword suspends execution of the sample method until the listing task completes. [!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L122-L160)] @@ -178,7 +182,7 @@ An append blob is optimized for append operations, such as logging. Like a block Each block in an append blob can be a different size, up to a maximum of 4 MB, and an append blob can include a maximum of 50,000 blocks. The maximum size of an append blob is therefore slightly more than 195 GB (4 MB X 50,000 blocks). -The example below creates a new append blob and appends some data to it, simulating a simple logging operation. +The following example creates a new append blob and appends some data to it, simulating a simple logging operation. [!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L174-L203)] @@ -192,7 +196,7 @@ To support concurrent access to a blob from multiple clients or multiple process * **Lease** - provides a way to obtain exclusive, renewable, write or delete access to a blob for a period of time -For further information see [Managing Concurrency in Microsoft Azure Storage](https://azure.microsoft.com/en-us/blog/managing-concurrency-in-microsoft-azure-storage-2/). +For more information, see [Managing Concurrency in Microsoft Azure Storage](https://azure.microsoft.com/en-us/blog/managing-concurrency-in-microsoft-azure-storage-2/). ## Naming containers diff --git a/docs/fsharp/using-fsharp-on-azure/file-storage.md b/docs/fsharp/using-fsharp-on-azure/file-storage.md index 1a68aee811f39..12ecc816b2a8a 100644 --- a/docs/fsharp/using-fsharp-on-azure/file-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/file-storage.md @@ -6,8 +6,8 @@ author: sylvanc manager: jbronsk ms.date: 09/20/2016 ms.topic: article -ms.prod: .net-core -ms.technology: .net-core-technologies +ms.prod: visual-studio-dev14 +ms.technology: devlang-fsharp ms.devlang: dotnet ms.assetid: 5c26a0aa-186e-476c-9f87-e0191754579e --- @@ -109,7 +109,7 @@ For more information about creating and using shared access signatures, see [Usi ### Copy files -You can copy a file to another file, a file to a blob, or a blob to a file. If you are copying a blob to a file, or a file to a blob, you *must* use a shared access signature (SAS) to authenticate the source object, even if you are copying within the same storage account. +You can copy a file to another file or to a blob, or a blob to a file. If you are copying a blob to a file, or a file to a blob, you *must* use a shared access signature (SAS) to authenticate the source object, even if you are copying within the same storage account. ### Copy a file to another file @@ -131,7 +131,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-L139)] +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L126-L140)] ## Next steps @@ -150,7 +150,7 @@ See these links for more information about Azure File storage. ### Reference -- [Storage Client Library for .NET reference](https://msdn.microsoft.com/library/azure/dn261237.aspx) +- [Storage Client Library for .NET reference](https://msdn.microsoft.com/library/azure/mt347887.aspx) - [File Service REST API reference](http://msdn.microsoft.com/library/azure/dn167006.aspx) ### Blog posts diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index 0631808580579..bd71b86615173 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -17,7 +17,7 @@ ms.assetid: FAD4D11E-703A-42D4-9F72-893D9E0F569B F# is a superb language for cloud programming and is frequently used to write web applications, cloud services, cloud-hosted microservices, and for scalable data processing. -In the sections below, you will find resources on how to use a range of Azure services with F#. +In the following sections, you will find resources on how to use a range of Azure services with F#. > [!NOTE] > If a particular Azure service isn't in this documentation set, please consult either the Azure Functions or .NET documentation for that service. Some Azure services are language-independent and require no language-specific documentation and are not listed here. @@ -38,11 +38,10 @@ Azure Functions support F# as a first-class language with efficient, reactive, s Other resources for using Azure Functions and F#: * [Scale Up Azure Functions in F# Using Suave](http://blog.tamizhvendan.in/blog/2016/09/19/scale-up-azure-functions-in-f-number-using-suave/) -* [Azure Functions in Practice](https://www.troyhunt.com/azure-functions-in-practice/) ## Using Azure Storage with F# # -Azure Storage is a base layer of storage services for modern applications that rely on durability, availability, and scalability to meet the needs of customers. F# programs can interact directly with Azure storage services, using the techinques described in the articles below. +Azure Storage is a base layer of storage services for modern applications that rely on durability, availability, and scalability to meet the needs of customers. F# programs can interact directly with Azure storage services, using the techinques described in the following articles. * [Get started with Azure Blob storage using F#](blob-storage.md) * [Get started with Azure File storage using F#](file-storage.md) diff --git a/docs/fsharp/using-fsharp-on-azure/queue-storage.md b/docs/fsharp/using-fsharp-on-azure/queue-storage.md index 9889a0e60aa46..6c45bc3bf9fb7 100644 --- a/docs/fsharp/using-fsharp-on-azure/queue-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/queue-storage.md @@ -6,8 +6,8 @@ author: sylvanc manager: jbronsk ms.date: 09/20/2016 ms.topic: article -ms.prod: .net-core -ms.technology: .net-core-technologies +ms.prod: visual-studio-dev14 +ms.technology: devlang-fsharp ms.devlang: dotnet ms.assetid: 70dc554c-8f4d-42a7-8e2a-6438657d012a --- @@ -45,7 +45,7 @@ You'll need an Azure Storage connection string for this tutorial. For more infor For the tutorial, you'll enter your connection string in your script, like this: -[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L9-L13)] +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L9-L9)] 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. @@ -133,7 +133,7 @@ has been processed. [!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L75-L76)] -## Use Async-Await pattern with common Queue storage APIs +## Use Async workflows with common Queue storage APIs This example shows how to use an async workflow with common Queue storage APIs. diff --git a/docs/fsharp/using-fsharp-on-azure/table-storage.md b/docs/fsharp/using-fsharp-on-azure/table-storage.md index 304696efe9a5f..8365c864856ce 100644 --- a/docs/fsharp/using-fsharp-on-azure/table-storage.md +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -6,8 +6,8 @@ author: sylvanc manager: jbronsk ms.date: 09/20/2016 ms.topic: article -ms.prod: .net-core -ms.technology: .net-core-technologies +ms.prod: visual-studio-dev14 +ms.technology: devlang-fsharp ms.devlang: dotnet ms.assetid: 9e5d6cea-a98c-461e-a5cc-75f1d154eafd --- @@ -142,19 +142,19 @@ You now print the results: To update an entity, retrieve it from the Table service, modify the entity object, and then save the changes back to the Table service using a `Replace` operation. This causes the entity to be fully replaced on the server, unless the entity on the server has changed since it was retrieved, in which case the operation will fail. This failure is to prevent your application from inadvertently overwriting changes from other sources. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L120-L127)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L121-L128)] ## Insert-or-replace an entity Sometimes, you don't know if the entity exists in the table or not. And if it does, the current values stored in it are no longer needed. You can use `InsertOrReplace` to create the entity, or replace it if it exists, regardless of its state. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L133-L139)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L134-L140)] ## Query a subset of entity properties A table query can retrieve just a few properties from an entity instead of all of them. This technique, called projection, can improve query performance, especially for large entities. Here, you return only email addresses using `DynamicTableEntity` and `EntityResolver`. Note that projection is not supported on the local storage emulator, so this code runs only when you're using an account on the Table service. -[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L145-L156)] +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L146-L157)] ## Retrieve entities in pages asynchronously diff --git a/samples/snippets/fsharp/azure/blob-storage.fsx b/samples/snippets/fsharp/azure/blob-storage.fsx index 8d5c42a5d283a..ebf47769cfe23 100644 --- a/samples/snippets/fsharp/azure/blob-storage.fsx +++ b/samples/snippets/fsharp/azure/blob-storage.fsx @@ -56,9 +56,9 @@ container.SetPermissions(permissions) let blockBlob = container.GetBlockBlobReference("myblob.txt") // Create or overwrite the "myblob.txt" blob with contents from the local file. -do - use fileStream = File.OpenRead localFile - blockBlob.UploadFromStream(fileStream) +do blockBlob.UploadFromFile(localFile) + + // // List the blobs in a container. @@ -132,10 +132,10 @@ let ListBlobsSegmentedInFlatListing(container:CloudBlobContainer) = let rec loop continuationToken (i:int) = async { + let! ct = Async.CancellationToken // This overload allows control of the page size. You can return // all remaining results by passing null for the maxResults // parameter, or by calling a different overload. - let! ct = Async.CancellationToken let! resultSegment = container.ListBlobsSegmentedAsync( "", true, BlobListingDetails.All, Nullable 10, @@ -159,11 +159,11 @@ let ListBlobsSegmentedInFlatListing(container:CloudBlobContainer) = do! loop null 1 } -// Create some dummy data by upoading the same file over andd over again +// Create some dummy data by uploading the same file over and over again for i in 1 .. 100 do let blob = container.GetBlockBlobReference("myblob" + string i + ".txt") use fileStream = System.IO.File.OpenRead(localFile) - blob.UploadFromStream fileStream + blob.UploadFromFile(localFile) ListBlobsSegmentedInFlatListing container |> Async.RunSynchronously diff --git a/samples/snippets/fsharp/azure/file-storage.fsx b/samples/snippets/fsharp/azure/file-storage.fsx index 8896c8ee52040..bd7fc5a591b9a 100644 --- a/samples/snippets/fsharp/azure/file-storage.fsx +++ b/samples/snippets/fsharp/azure/file-storage.fsx @@ -75,12 +75,12 @@ share.SetProperties() // Generate a shared access signature for a file or file share. // -// Create a 24 hour read/write policy. +// Create a 24-hour read/write policy. let policy = - SharedAccessFilePolicy( - SharedAccessExpiryTime = (DateTimeOffset.UtcNow.AddHours(24.) |> Nullable), - Permissions = (SharedAccessFilePermissions.Read ||| SharedAccessFilePermissions.Write) - ) + SharedAccessFilePolicy + (SharedAccessExpiryTime = (DateTimeOffset.UtcNow.AddHours(24.) |> Nullable), + Permissions = (SharedAccessFilePermissions.Read ||| SharedAccessFilePermissions.Write)) + // Set the policy on the share. let permissions = share.GetPermissions() @@ -126,14 +126,15 @@ destBlob.StartCopy(sasUri2) open Microsoft.WindowsAzure.Storage.File.Protocol open Microsoft.WindowsAzure.Storage.Shared.Protocol -let props = FileServiceProperties() -props.HourMetrics <- MetricsProperties() -props.HourMetrics.MetricsLevel <- MetricsLevel.ServiceAndApi -props.HourMetrics.RetentionDays <- 14 |> Nullable -props.HourMetrics.Version <- "1.0" -props.MinuteMetrics <- MetricsProperties() -props.MinuteMetrics.MetricsLevel <- MetricsLevel.ServiceAndApi -props.MinuteMetrics.RetentionDays <- 7 |> Nullable -props.MinuteMetrics.Version <- "1.0" +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")) fileClient.SetServiceProperties(props) diff --git a/samples/snippets/fsharp/azure/table-storage.fsx b/samples/snippets/fsharp/azure/table-storage.fsx index a9cc766ee3bab..37dfff57b077d 100644 --- a/samples/snippets/fsharp/azure/table-storage.fsx +++ b/samples/snippets/fsharp/azure/table-storage.fsx @@ -49,7 +49,7 @@ type Customer(firstName, lastName, email: string, phone: string) = member val PhoneNumber = phone with get, set let customer = - Customer("Larry", "Boomer", "larry@example.com", "425-555-0101") + Customer("Walter", "Harp", "Walter@contoso.com", "425-555-0101") let insertOp = TableOperation.Insert(customer) table.Execute(insertOp) @@ -60,10 +60,10 @@ table.Execute(insertOp) // let customer1 = - Customer("Bob", "Buster", "bob@example.com", "425-555-0102") + Customer("Jeff", "Smith", "Jeff@contoso.com", "425-555-0102") let customer2 = - Customer("Jenny", "Buster", "jenny@example.com", "425-555-0102") + Customer("Ben", "Smith", "Ben@contoso.com", "425-555-0103") let batchOp = TableBatchOperation() batchOp.Insert(customer1) @@ -77,7 +77,7 @@ table.ExecuteBatch(batchOp) let query = TableQuery().Where( TableQuery.GenerateFilterCondition( - "PartitionKey", QueryComparisons.Equal, "Buster")) + "PartitionKey", QueryComparisons.Equal, "Smith")) let result = table.ExecuteQuery(query) @@ -92,7 +92,7 @@ let range = TableQuery().Where( TableQuery.CombineFilters( TableQuery.GenerateFilterCondition( - "PartitionKey", QueryComparisons.Equal, "Buster"), + "PartitionKey", QueryComparisons.Equal, "Smith"), TableOperators.And, TableQuery.GenerateFilterCondition( "RowKey", QueryComparisons.LessThan, "M"))) @@ -106,7 +106,7 @@ for customer in rangeResult do // Retrieve a single entity. // -let retrieveOp = TableOperation.Retrieve("Buster", "Larry") +let retrieveOp = TableOperation.Retrieve("Smith", "Ben") let retrieveResult = table.Execute(retrieveOp) From d1df8151f1705064b4ff12fb135aa19f3f21588b Mon Sep 17 00:00:00 2001 From: cartermp Date: Tue, 11 Oct 2016 10:41:32 -0700 Subject: [PATCH 58/60] Fix link? --- docs/fsharp/using-fsharp-on-azure/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index bd71b86615173..ecaa147c88204 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -97,7 +97,7 @@ Azure VMs may be programmatically deployed and managed from F# scripts by using Likewise, other Azure resources may also be deployed and managed from F# scripts using the same components. For example, you can create storage accounts, deploy Azure Cloud Services, create Azure DocumentDB instances and manage Azure Notifcation Hubs programmatically from F# scripts. -Using F# scripts to deploy and manage resources is not normally necessary. For example, Azure resources may also be deployed directy from JSON template descriptions, which can be parameterized. See [Azure Resource Manager Templates](https://azure.microsoft.com/en-us/documentation/articles/resource-manager-template-best-practices/) including examples such as the [Azure Quickstart Templates](Azure Quickstart Templates). +Using F# scripts to deploy and manage resources is not normally necessary. For example, Azure resources may also be deployed directy from JSON template descriptions, which can be parameterized. See [Azure Resource Manager Templates](https://azure.microsoft.com/en-us/documentation/articles/resource-manager-template-best-practices/) including examples such as the [Azure Quickstart Templates](https://azure.microsoft.com/en-us/documentation/templates/). ## Other resources From b1464999492522f7f195e2d3d202d6237ab3a7c0 Mon Sep 17 00:00:00 2001 From: cartermp Date: Tue, 11 Oct 2016 15:00:56 -0700 Subject: [PATCH 59/60] Fix header --- docs/fsharp/using-fsharp-on-azure/package-management.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fsharp/using-fsharp-on-azure/package-management.md b/docs/fsharp/using-fsharp-on-azure/package-management.md index 256f9145e7594..25b1d1f3fad8e 100644 --- a/docs/fsharp/using-fsharp-on-azure/package-management.md +++ b/docs/fsharp/using-fsharp-on-azure/package-management.md @@ -68,7 +68,7 @@ Or, for Mono development: > mono nuget.exe update -# Referencing Assemblies +## Referencing Assemblies In order to use your packages in your F# script, you need to reference the assemblies included in the packages using a `#r` directive. For example: From 21eb23cf94be2fd9265a39eb8988b9b8b1587177 Mon Sep 17 00:00:00 2001 From: cartermp Date: Tue, 11 Oct 2016 17:24:18 -0700 Subject: [PATCH 60/60] Link package management doc into TOC --- docs/toc.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/toc.md b/docs/toc.md index d6ca60e5c26b4..ee66b350ecece 100644 --- a/docs/toc.md +++ b/docs/toc.md @@ -130,6 +130,7 @@ ### [Get started with Azure Queue storage using F#](fsharp/using-fsharp-on-azure/queue-storage.md) ### [Get started with Azure Table storage using F#](fsharp/using-fsharp-on-azure/table-storage.md) ### [Using F# on Azure Service Fabric](fsharp/using-fsharp-on-azure/using-fsharp-on-azure-service-fabric.md) +### [Package Management for F# Azure Dependencies](fsharp/using-fsharp-on-azure/package-management.md) ## [F# Language Reference](fsharp/language-reference/index.md) ### [Keyword Reference](fsharp/language-reference/keyword-reference.md)