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..28e5a11173a2c --- /dev/null +++ b/docs/fsharp/using-fsharp-on-azure/blob-storage.md @@ -0,0 +1,253 @@ +--- +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: sylvanc +manager: jbronsk +ms.date: 09/20/2016 +ms.topic: article +ms.prod: visual-studio-dev14 +ms.technology: devlang-fsharp +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. + +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. + +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/). + +## 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 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](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 + +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)] + +### Get your 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 enter your connection string in your script, like this: + +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L11-L11)] + +However, this is **not recommended** for real projects. Your storage account key is similar to the root password for your storage account. Always be careful to protect your storage account key. Avoid distributing it to other users, hard-coding it, or saving it in a plain-text file that is accessible to others. You can regenerate your key using the Azure Portal if you believe it may have been compromised. + +For real applications, the best way to maintain your storage connection string is in a configuration file. To fetch the connection string from a configuration file, you can do this: + +[!code-fsharp[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. + +### Parse the connection string + +To parse the connection string, use: + +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L21-L22)] + +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 upload this 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: + +[!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. + +## Create a container + +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)] + +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)] + +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 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 `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-L59)] + +## 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)] + +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 + 2015/architecture/photo4.jpg + 2016/architecture/photo5.jpg + 2016/architecture/photo6.jpg + 2016/architecture/description.txt + 2016/photo7.jpg +``` + +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: + +[!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: + +```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 + 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. + +[!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)] + +## 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)] + +## 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`. + +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)] + +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. You use ``Async.RunSynchronously`` to force the execution of the asynchronous operation. + +[!code-fsharp[BlobStorage](../../../samples/snippets/fsharp/azure/blob-storage.fsx#L168-L168)] + +## 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 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)] + +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 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 + +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/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: + +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 encryption](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. + +### 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 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) + +### 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/) +- [Configuring Connection Strings](http://msdn.microsoft.com/library/azure/ee758697.aspx) +- [Azure Storage Team Blog](http://blogs.msdn.com/b/windowsazurestorage/) 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..12ecc816b2a8a --- /dev/null +++ b/docs/fsharp/using-fsharp-on-azure/file-storage.md @@ -0,0 +1,161 @@ +--- +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: sylvanc +manager: jbronsk +ms.date: 09/20/2016 +ms.topic: article +ms.prod: visual-studio-dev14 +ms.technology: devlang-fsharp +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. + +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/). + +## 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. + +## 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 `files.fsx`, in your F# development environment. + +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 + +Add the following `open` statements to the top of the `files.fsx` file: + +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L1-L5)] + +### 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: + +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L11-L11)] + +However, this is **not recommended** for real projects. Your storage account key is similar to the root password for your storage account. Always be careful to protect your storage account key. Avoid distributing it to other users, hard-coding it, or saving it in a plain-text file that is accessible to others. You can regenerate your key using the Azure Portal if you believe it may have been compromised. + +For real applications, the best way to maintain your storage connection string is in a configuration file. To fetch the connection string from a configuration file, you can do this: + +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L13-L15)] + +Using Azure Configuration Manager is optional. You can also use an API such as the .NET Framework's `ConfigurationManager` type. + +### Parse the connection string + +To parse the connection string, use: + +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L21-L22)] + +This will return a `CloudStorageAccount`. + +### Create the File service client + +The `CloudFileClient` type enables you to programmatically use files stored in File storage. Here's one way to create the service client: + +[!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 File storage. + +## Create a file share + +This example shows how to create a file share if it does not already exist: + +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L34-L35)] + +## Create a root directory and a subdirectory + +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)] + +## 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#L62-L72)] + +### 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, 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)] + +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 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 + +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, 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)] + +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: + +[!code-fsharp[FileStorage](../../../samples/snippets/fsharp/azure/file-storage.fsx#L126-L140)] + +## 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/mt347887.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) diff --git a/docs/fsharp/using-fsharp-on-azure/index.md b/docs/fsharp/using-fsharp-on-azure/index.md index f72151f1f6740..ecaa147c88204 100644 --- a/docs/fsharp/using-fsharp-on-azure/index.md +++ b/docs/fsharp/using-fsharp-on-azure/index.md @@ -1,4 +1,104 @@ +--- +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: sylvanc +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. + +In the following sections, you will find resources on how to use a range of Azure services with F#. + > [!NOTE] -This is still in progress. \ No newline at end of file +> 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# # + +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 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. + +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#: + +* [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/) + +## 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 following articles. + +* [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 [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# # + +[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/). 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 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 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: + +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/). + +## 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/). + +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](https://azure.microsoft.com/en-us/documentation/templates/). + +## Other resources + +* [Full documentation on all Azure services](https://azure.microsoft.com/en-us/documentation/) 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..25b1d1f3fad8e --- /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: sylvanc +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. 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..6c45bc3bf9fb7 --- /dev/null +++ b/docs/fsharp/using-fsharp-on-azure/queue-storage.md @@ -0,0 +1,178 @@ +--- +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: sylvanc +manager: jbronsk +ms.date: 09/20/2016 +ms.topic: article +ms.prod: visual-studio-dev14 +ms.technology: devlang-fsharp +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. + +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/). + +## 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. + +## 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](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 + +Add the following `open` statements to the top of the `queues.fsx` file: + +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L1-L3)] + +### 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: + +[!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. + +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/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. + +### Parse the connection string + +To parse the connection string, use: + +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L19-L20)] + +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: + +[!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. + +## Create a queue + +This example shows how to create a queue if it doesn't already exist: + +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L32-L36)] + +## 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: + +[!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/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 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 +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. + +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L65-L69)] + +## 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. + +[!code-fsharp[QueueStorage](../../../samples/snippets/fsharp/azure/queue-storage.fsx#L75-L76)] + +## Use Async workflows 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#L82-L91)] + +## 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. + +[!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#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#L112-L113)] + +## 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 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) 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..8365c864856ce --- /dev/null +++ b/docs/fsharp/using-fsharp-on-azure/table-storage.md @@ -0,0 +1,190 @@ +--- +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: sylvanc +manager: jbronsk +ms.date: 09/20/2016 +ms.topic: article +ms.prod: visual-studio-dev14 +ms.technology: devlang-fsharp +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. + +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/) + +## 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. + +## 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](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 + +Add the following `open` statements to the top of the `tables.fsx` file: + +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L1-L5)] + +### 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: + +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L11-L11)] + +However, this is **not recommended** for real projects. Your storage account key is similar to the root password for your storage account. Always be careful to protect your storage account key. Avoid distributing it to other users, hard-coding it, or saving it in a plain-text file that is accessible to others. You can regenerate your key using the Azure Portal if you believe it may have been compromised. + +For real applications, the best way to maintain your storage connection string is in a configuration file. To fetch the connection string from a configuration file, you can do this: + +[!code-fsharp[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. + +### Parse the connection string + +To parse the connection string, use: + +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L21-L22)] + +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: + +[!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. + +## Create a table + +This example shows how to create a table if it does not already exist: + +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L35-L39)] + +## 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. + +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L45-L52)] + +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#L54-L55)] + +## 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: + +[!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, you filter for entities where "Buster" is the partition key. + +[!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-L100)] + +You now print the results: + +[!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-L111)] + +You now print the results: + +[!code-fsharp[TableStorage](../../../samples/snippets/fsharp/azure/table-storage.fsx#L113-L115)] + + +## 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#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#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#L146-L157)] + +## 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, 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#L163-L177)] + +You now execute this computation synchronously: + +[!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#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#L192-L192)] + +## Next steps + +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) +- [Getting Started with Azure Table Storage in .NET](https://azure.microsoft.com/documentation/samples/storage-table-dotnet-getting-started/) 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..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,4 +1,4 @@ # Using F# on Azure Service Fabric > [!NOTE] -This is still in progress. \ No newline at end of file +> This is still in progress. diff --git a/docs/toc.md b/docs/toc.md index 7e771e52d8178..ee66b350ecece 100644 --- a/docs/toc.md +++ b/docs/toc.md @@ -125,7 +125,12 @@ ### [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) +### [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) diff --git a/samples/snippets/fsharp/azure/blob-storage.fsx b/samples/snippets/fsharp/azure/blob-storage.fsx new file mode 100644 index 0000000000000..ebf47769cfe23 --- /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 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 blockBlob.UploadFromFile(localFile) + + + +// +// 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 { + 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! 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 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.UploadFromFile(localFile) + +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 diff --git a/samples/snippets/fsharp/azure/file-storage.fsx b/samples/snippets/fsharp/azure/file-storage.fsx new file mode 100644 index 0000000000000..bd7fc5a591b9a --- /dev/null +++ b/samples/snippets/fsharp/azure/file-storage.fsx @@ -0,0 +1,140 @@ +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() + +// +// Create a root directory and a subdirectory +// + +let rootDir = share.GetRootDirectoryReference() +let subDir = rootDir.GetDirectoryReference("myLogs") +subDir.CreateIfNotExists() + +// +// 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. +// + +// 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 + (SharedAccessExpiryTime = (DateTimeOffset.UtcNow.AddHours(24.) |> Nullable), + Permissions = (SharedAccessFilePermissions.Read ||| SharedAccessFilePermissions.Write)) + + +// Set the policy on the share. +let permissions = share.GetPermissions() +permissions.SharedAccessPolicies.Add("policyName", policy) +share.SetPermissions(permissions) + +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 + (Permissions = SharedAccessFilePermissions.Read, + 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( + (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/queue-storage.fsx b/samples/snippets/fsharp/azure/queue-storage.fsx new file mode 100644 index 0000000000000..0d03a91eca959 --- /dev/null +++ b/samples/snippets/fsharp/azure/queue-storage.fsx @@ -0,0 +1,113 @@ +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 + +// +// 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. +retrieved.SetMessageContent("Updated contents.") +queue.UpdateMessage(retrieved, + TimeSpan.FromSeconds(60.0), + MessageUpdateFields.Content ||| MessageUpdateFields.Visibility) + +// +// De-queue the next message, indicating successful processing +// + +// Process the message in less than 30 seconds, and then delete the message. +queue.DeleteMessage(retrieved) + +// +// Use Async-Await pattern with common Queue storage APIs. +// + +async { + let! exists = queue.CreateIfNotExistsAsync() |> Async.AwaitTask + + let! retrieved = queue.GetMessageAsync() |> Async.AwaitTask + + // ... process the message here ... + + // Now indicate successful processing: + do! 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..37dfff57b077d --- /dev/null +++ b/samples/snippets/fsharp/azure/table-storage.fsx @@ -0,0 +1,193 @@ +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. The last name is used as a partition key. +// + +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("Walter", "Harp", "Walter@contoso.com", "425-555-0101") + +let insertOp = TableOperation.Insert(customer) +table.Execute(insertOp) + + +// +// Insert a batch of entities. All must have the same partition key. +// + +let customer1 = + Customer("Jeff", "Smith", "Jeff@contoso.com", "425-555-0102") + +let customer2 = + Customer("Ben", "Smith", "Ben@contoso.com", "425-555-0103") + +let batchOp = TableBatchOperation() +batchOp.Insert(customer1) +batchOp.Insert(customer2) +table.ExecuteBatch(batchOp) + +// +// Retreive all entities in a partition. +// + +let query = + TableQuery().Where( + TableQuery.GenerateFilterCondition( + "PartitionKey", QueryComparisons.Equal, "Smith")) + +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. +// + +let range = + TableQuery().Where( + TableQuery.CombineFilters( + TableQuery.GenerateFilterCondition( + "PartitionKey", QueryComparisons.Equal, "Smith"), + TableOperators.And, + TableQuery.GenerateFilterCondition( + "RowKey", QueryComparisons.LessThan, "M"))) + +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("Smith", "Ben") + +let retrieveResult = table.Execute(retrieveOp) + +// Show the result +let retrieveCustomer = retrieveResult.Result :?> Customer +printfn "customer: %A %A" retrieveCustomer.RowKey retrieveCustomer.PartitionKey + +// +// Replace an entity. +// + +try + let customer = retrieveResult.Result :?> Customer + customer.PhoneNumber <- "425-555-0103" + let replaceOp = TableOperation.Replace(customer) + table.Execute(replaceOp) |> ignore + Console.WriteLine("Update succeeeded") +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 + Console.WriteLine("Update succeeeded") +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 + ) + +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... + + // Continue to the next segment + match result.ContinuationToken with + | null -> () + | cont -> return! loop cont + } + loop null + +let asyncResults = asyncQuery |> Async.RunSynchronously + +// +// Delete an entity. +// + +let deleteOp = TableOperation.Delete(customer) +table.Execute(deleteOp) + +// +// Delete a table. +// + +table.DeleteIfExists() +