{"id":1155,"date":"2021-05-28T13:00:44","date_gmt":"2021-05-28T20:00:44","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sdk\/?p=1155"},"modified":"2021-10-28T11:24:24","modified_gmt":"2021-10-28T18:24:24","slug":"introducing-the-new-azure-function-extension-libraries-beta","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sdk\/introducing-the-new-azure-function-extension-libraries-beta\/","title":{"rendered":"Introducing the new Azure Function Extension Libraries **Beta**"},"content":{"rendered":"<p><span style=\"font-size: 14pt;\"><strong>10\/28\/21 Update &#8211; We are pleased to announce that the libraries discussed below are now GA!<\/strong><\/span><\/p>\n<p>We are pleased to announce the release of beta versions for <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.Azure.WebJobs.Extensions.Storage\/5.0.0-beta.4\">Storage<\/a>, <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.Azure.WebJobs.Extensions.EventHubs\/5.0.0-beta.5\">Event Hubs<\/a>, <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.Azure.WebJobs.Extensions.ServiceBus\/5.0.0-beta.3\">Service Bus<\/a>, and <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.Azure.WebJobs.Extensions.EventGrid\/3.0.0-beta.2\">Event Grid<\/a> Functions extensions, following the new <a href=\"https:\/\/github.com\/Azure\/azure-sdk\/blob\/master\/README.md\">Azure SDK guidelines<\/a>. This post will highlight a few new features of the libraries. We encourage you to try out the libraries and provide feedback before they go GA!<\/p>\n<h2>New Features<\/h2>\n<h2>Secretless configuration<\/h2>\n<p>Storage, Event Hubs, and Service Bus extensions now support secretless configuration via Azure Active Directory. This allows your function app to authenticate with these services without providing a connection string as part of your function config. Here is how the configuration works for each library in the Application settings section of your function app in the portal. More details on configuring application settings for Functions apps can be found <a href=\"https:\/\/docs.microsoft.com\/azure\/azure-functions\/functions-how-to-use-azure-function-app-settings?tabs=portal\">here<\/a>.<\/p>\n<p><em>Similar configuration is possible when running locally by modifying the <a href=\"https:\/\/docs.microsoft.com\/azure\/azure-functions\/functions-run-local?tabs=windows%2Ccsharp%2Cbash#local-settings-file\">local.settings.json file<\/a>. In the local experience, you may run into a warning about missing connection strings in your <code>local.settings.json<\/code> file when using secretless configuration. This will be fixed prior to the GA of the extensions.<\/em><\/p>\n<h3>General setup<\/h3>\n<p>For all of the extensions being discussed, you will need to set the <code>AzureWebJobsStorage<\/code> setting to use a general-purpose storage account as this is required by the Functions runtime.<\/p>\n<table>\n<thead>\n<tr>\n<th>Name<\/th>\n<th>Value<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>AzureWebJobsStorage__accountName<\/td>\n<td>{account name}<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><em>For local development, you can still use <a href=\"https:\/\/docs.microsoft.com\/azure\/storage\/common\/storage-use-azurite\">Azurite<\/a> by setting the value of <code>AzureWebJobsStorage<\/code> to <code>UseDevelopmentStorage=true<\/code>.<\/em><\/p>\n<p>Unless otherwise specified, each of the configurations is powered by the <a href=\"https:\/\/docs.microsoft.com\/dotnet\/api\/overview\/azure\/identity-readme#defaultazurecredential\">DefaultAzureCredential<\/a> type. This implies that your functions app (or your local environment when running locally) would need to be able to authenticate with the corresponding Storage account, Event Hubs namespace, or Service Bus namespace using at least one of the authentication mechanisms used by the <code>DefaultAzureCredential<\/code>.<\/p>\n<h3>Storage<\/h3>\n<h4>Blobs<\/h4>\n<table>\n<thead>\n<tr>\n<th>Name<\/th>\n<th>Value<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>MyConnection__blobServiceUri<\/td>\n<td>https:\/\/{account name}.blob.core.windows.net<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Here is a simple function that will run whenever the specified blob is modified:<\/p>\n<pre><code class=\"language-cs\">[FunctionName(\"BlobTriggerFunction\")]\r\npublic static void Run(\r\n    [BlobTrigger(\"sample-container\/sample-blob\", Connection = \"MyConnection\")]\r\n    Stream blobStream,\r\n    ILogger logger)\r\n{\r\n    using var blobStreamReader = new StreamReader(blobStream);\r\n    logger.LogInformation($\"Blob sample-container\/sample-blob has been updated with content: {blobStreamReader.ReadToEnd()}\");\r\n}<\/code><\/pre>\n<h4>Queues<\/h4>\n<table>\n<thead>\n<tr>\n<th>Name<\/th>\n<th>Value<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>MyConnection__queueServiceUri<\/td>\n<td>https:\/\/{account name}.queue.core.windows.net<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Here is a simple function that will run whenever a message is delivered to the specified queue:<\/p>\n<pre><code class=\"language-cs\">[FunctionName(\"QueueTriggerFunction\")]\r\npublic static void Run(\r\n    [QueueTrigger(\"sample-queue\", Connection = \"MyConnection\")] \r\n    string message,\r\n    ILogger logger)\r\n    {\r\n        logger.LogInformation($\"Received message from sample-queue, content={message}\");\r\n    }<\/code><\/pre>\n<h3>Event Hubs<\/h3>\n<table>\n<thead>\n<tr>\n<th>Name<\/th>\n<th>Value<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>MyConnection__fullyQualifiedNamespace<\/td>\n<td>{namespace name}.servicebus.windows.net<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Here is a simple function that will run whenever an event is delivered to the specified event hub:<\/p>\n<pre><code class=\"language-cs\">[FunctionName(\"EventHubTriggerFunction\")]\r\npublic static void Run(\r\n    [EventHubTrigger(\"&lt;event_hub_name&gt;\", Connection = \"MyConnection\")]\r\n    EventData eventData,\r\n    ILogger logger)\r\n{\r\n    logger.LogInformation($\"C# function triggered to process a message: {eventData.EventBody}\");\r\n    logger.LogInformation($\"EnqueuedTime={eventData.EnqueuedTime}\");\r\n}<\/code><\/pre>\n<h3>Service Bus<\/h3>\n<table>\n<thead>\n<tr>\n<th>Name<\/th>\n<th>Value<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>MyConnection__fullyQualifiedNamespace<\/td>\n<td>{namespace name}.servicebus.windows.net<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Here is a simple function that will run whenever a message is delivered to the specified queue:<\/p>\n<pre><code class=\"language-cs\">[FunctionName(\"ServiceBusTriggerFunction\")]\r\npublic static void Run(\r\n    [ServiceBusTrigger(\"&lt;queue_name&gt;\", Connection = \"MyConnection\")]\r\n    ServiceBusReceivedMessage message,\r\n    ILogger logger)\r\n{\r\n    logger.LogInformation($\"C# function triggered to process a message: {message.Body}\");\r\n    logger.LogInformation($\"EnqueuedTime={message.EnqueuedTime}\");\r\n}<\/code><\/pre>\n<h3>Advanced Configuration<\/h3>\n<p>In each of the preceding examples, the <a href=\"https:\/\/docs.microsoft.com\/dotnet\/api\/overview\/azure\/identity-readme#defaultazurecredential\">DefaultAzureCredential<\/a> type would be used by the extensions to attempt to authenticate with the service. It&#8217;s also possible to configure more fine-grained authentication. We will use Blob Storage as an example, but the same settings are available for Storage Queues, Event Hubs, and Service Bus. To configure using Managed Identity, which uses the <a href=\"https:\/\/docs.microsoft.com\/dotnet\/api\/azure.identity.managedidentitycredential?view=azure-dotnet\">ManagedIdentityCredential<\/a> type:<\/p>\n<table>\n<thead>\n<tr>\n<th>Name<\/th>\n<th>Value<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>MyConnection__blobServiceUri<\/td>\n<td>https:\/\/{account name}.blob.core.windows.net<\/td>\n<\/tr>\n<tr>\n<td>MyConnection__credential<\/td>\n<td>managedIdentity<\/td>\n<\/tr>\n<tr>\n<td>MyConnection__clientId<\/td>\n<td>{myClientId}<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>To configure using a client secret credential, which uses the <a href=\"https:\/\/docs.microsoft.com\/dotnet\/api\/azure.identity.clientsecretcredential?view=azure-dotnet\">ClientSecretCredential<\/a> type:<\/p>\n<table>\n<thead>\n<tr>\n<th>Name<\/th>\n<th>Value<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>MyConnection__blobServiceUri<\/td>\n<td>https:\/\/{account name}.blob.core.windows.net<\/td>\n<\/tr>\n<tr>\n<td>MyConnection__tenantId<\/td>\n<td>{myTenantId}<\/td>\n<\/tr>\n<tr>\n<td>MyConnection__clientId<\/td>\n<td>{myClientId}<\/td>\n<\/tr>\n<tr>\n<td>MyConnection__clientSecret<\/td>\n<td>{myClientSecret}<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>And finally, to configure using a client certificate, which uses the <a href=\"https:\/\/docs.microsoft.com\/dotnet\/api\/azure.identity.clientcertificatecredential?view=azure-dotnet\">ClientCertificateCredential<\/a> type:<\/p>\n<table>\n<thead>\n<tr>\n<th>Name<\/th>\n<th>Value<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>MyConnection__blobServiceUri<\/td>\n<td>https:\/\/{account name}.blob.core.windows.net<\/td>\n<\/tr>\n<tr>\n<td>MyConnection__tenantId<\/td>\n<td>{myTenantId}<\/td>\n<\/tr>\n<tr>\n<td>MyConnection__clientId<\/td>\n<td>{myClientId}<\/td>\n<\/tr>\n<tr>\n<td>MyConnection__certificate<\/td>\n<td>{myCertificate}<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>CloudEvent Binding<\/h2>\n<p>When writing a C# function, it is now possible to use the new <a href=\"https:\/\/docs.microsoft.com\/dotnet\/api\/azure.messaging.cloudevent?view=azure-dotnet\">CloudEvent<\/a> type which conforms to the <a href=\"https:\/\/github.com\/cloudevents\/spec\/blob\/v1.0.1\/spec.md\">CloudEvents V1 schema<\/a> for output functions:<\/p>\n<p>Output:<\/p>\n<pre><code class=\"language-cs\">[FunctionName(\"CloudEventBindingFunction\")]\r\npublic static async Task&lt;IActionResult&gt; RunAsync(\r\n    [HttpTrigger(AuthorizationLevel.Anonymous, \"get\", \"post\", Route = null)]\r\n    HttpRequest req,\r\n    [EventGrid(TopicEndpointUri = \"EventGridEndpoint\", TopicKeySetting = \"EventGridKey\")]\r\n    IAsyncCollector&lt;CloudEvent&gt; eventCollector)\r\n{\r\n    CloudEvent e = new CloudEvent(\"IncomingRequest\", \"IncomingRequest\", await req.ReadAsStringAsync());\r\n    await eventCollector.AddAsync(e);\r\n    return new OkResult();\r\n}<\/code><\/pre>\n<p>Trigger functions are not yet supported as an Event subscription can currently only be created using the EventGridSchema from Azure Functions.<\/p>\n<h2>Conclusion<\/h2>\n<p>Azure Functions is one of Azure&#8217;s core serverless offerings, that can greatly simplify your application. The latest set of packages are our effort to make integrating with Azure functions quick and painless, allowing you to quickly jumpstart your applications and get running.<\/p>\n<p>For more information about each of the extensions from this article please see the following README files:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-net\/blob\/master\/sdk\/storage\/Microsoft.Azure.WebJobs.Extensions.Storage\/README.md\">Storage<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-net\/blob\/master\/sdk\/eventhub\/Microsoft.Azure.WebJobs.Extensions.EventHubs\/README.md\">Event Hubs<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-net\/blob\/master\/sdk\/servicebus\/Microsoft.Azure.WebJobs.Extensions.ServiceBus\/README.md\">Service Bus<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-net\/blob\/master\/sdk\/eventgrid\/Microsoft.Azure.WebJobs.Extensions.EventGrid\/README.md\">Event Grid<\/a><\/li>\n<\/ul>\n<h2>Azure SDK Blog Contributions<\/h2>\n<p>Thank you for reading this Azure SDK blog post! We hope that you learned something new and welcome you to share this post. We are open to Azure SDK blog contributions. Please contact us at <a href=\"mailto:azsdkblog@microsoft.com\">azsdkblog@microsoft.com<\/a> with your topic and we&#8217;ll get you set up as a guest blogger.<\/p>\n<h2>Azure SDK Links<\/h2>\n<ul>\n<li>Azure SDK Website: <a href=\"https:\/\/aka.ms\/azsdk\">aka.ms\/azsdk<\/a><\/li>\n<li>Azure SDK Intro (3 minute video): <a href=\"https:\/\/aka.ms\/azsdk\/intro\">aka.ms\/azsdk\/intro<\/a><\/li>\n<li>Azure SDK Intro Deck (PowerPoint deck): <a href=\"https:\/\/aka.ms\/azsdk\/intro\/deck\">aka.ms\/azsdk\/intro\/deck<\/a><\/li>\n<li>Azure SDK Releases: <a href=\"https:\/\/aka.ms\/azsdk\/releases\">aka.ms\/azsdk\/releases<\/a><\/li>\n<li>Azure SDK Blog: <a href=\"https:\/\/aka.ms\/azsdk\/blog\">aka.ms\/azsdk\/blog<\/a><\/li>\n<li>Azure SDK Twitter: <a href=\"https:\/\/twitter.com\/AzureSDK\">twitter.com\/AzureSDK<\/a><\/li>\n<li>Azure SDK Design Guidelines: <a href=\"https:\/\/aka.ms\/azsdk\/guide\">aka.ms\/azsdk\/guide<\/a><\/li>\n<li>Azure SDKs &amp; Tools: <a href=\"https:\/\/azure.microsoft.com\/downloads\">azure.microsoft.com\/downloads<\/a><\/li>\n<li>Azure SDK Central Repository: <a href=\"https:\/\/github.com\/azure\/azure-sdk#azure-sdk\">github.com\/azure\/azure-sdk<\/a><\/li>\n<li>Azure SDK for .NET: <a href=\"https:\/\/github.com\/azure\/azure-sdk-for-net\">github.com\/azure\/azure-sdk-for-net<\/a><\/li>\n<li>Azure SDK for Java: <a href=\"https:\/\/github.com\/azure\/azure-sdk-for-java\">github.com\/azure\/azure-sdk-for-java<\/a><\/li>\n<li>Azure SDK for Python: <a href=\"https:\/\/github.com\/azure\/azure-sdk-for-python\">github.com\/azure\/azure-sdk-for-python<\/a><\/li>\n<li>Azure SDK for JavaScript\/TypeScript: <a href=\"https:\/\/github.com\/azure\/azure-sdk-for-js\">github.com\/azure\/azure-sdk-for-js<\/a><\/li>\n<li>Azure SDK for Android: <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-android\">github.com\/Azure\/azure-sdk-for-android<\/a><\/li>\n<li>Azure SDK for iOS: <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-ios\">github.com\/Azure\/azure-sdk-for-ios<\/a><\/li>\n<li>Azure SDK for Go: <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-go\">github.com\/Azure\/azure-sdk-for-go<\/a><\/li>\n<li>Azure SDK for C: <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-c\">github.com\/Azure\/azure-sdk-for-c<\/a><\/li>\n<li>Azure SDK for C++: <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-cpp\">github.com\/Azure\/azure-sdk-for-cpp<\/a><\/li>\n<\/ul>\n<p><!-- FOOTER: DO NOT EDIT OR REMOVE --><\/p>\n","protected":false},"excerpt":{"rendered":"<p>New Beta release of the Azure Function Extension for Storage, Event Hubs, Service Bus, and Event Grid.<\/p>\n","protected":false},"author":55909,"featured_media":1158,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[765,802,748,785,779],"class_list":["post-1155","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-sdk","tag-azure-functions","tag-blob-storage","tag-event-grid","tag-event-hubs","tag-service-bus"],"acf":[],"blog_post_summary":"<p>New Beta release of the Azure Function Extension for Storage, Event Hubs, Service Bus, and Event Grid.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/1155","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/users\/55909"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/comments?post=1155"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/1155\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media\/1158"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media?parent=1155"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/categories?post=1155"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/tags?post=1155"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}