Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Azure Functions isolated worker model extension #35

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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/workflows/cd-azure-functions-worker-extensions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Lib.Azure.Functions.Worker.Extensions.WebPush - CD
on:
push:
tags:
- "azure-functions-worker-extensions-v[0-9]+.[0-9]+.[0-9]+"
jobs:
deployment:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Extract VERSION
run: echo "VERSION=${GITHUB_REF/refs\/tags\/azure-functions-worker-extensions-v/}" >> $GITHUB_ENV
shell: bash
- name: Setup .NET Core 3.1 SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: '3.1.x'
- name: Setup .NET 5.0 SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: '5.0.x'
- name: Setup .NET 6.0 SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: '6.0.x'
- name: Setup .NET 8.0 SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Restore
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --configuration Release --no-build
- name: Pack
run: dotnet pack --configuration Release --no-build
- name: NuGet Push Lib.Azure.Functions.Worker.Extensions.WebPush
run: dotnet nuget push src/Lib.Azure.Functions.Worker.Extensions.WebPush/bin/Release/Lib.Azure.Functions.Worker.Extensions.WebPush.${VERSION}.nupkg --source https://api.nuget.org/v3/index.json --api-key ${NUGET_API_KEY}
shell: bash
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ name: Lib.Azure.WebJobs.Extensions.WebPush - CD
on:
push:
tags:
- "azure-extensions-v[0-9]+.[0-9]+.[0-9]+"
- "azure-webjobs-extensions-v[0-9]+.[0-9]+.[0-9]+"
jobs:
deployment:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Extract VERSION
run: echo "VERSION=${GITHUB_REF/refs\/tags\/azure-extensions-v/}" >> $GITHUB_ENV
run: echo "VERSION=${GITHUB_REF/refs\/tags\/azure-webjobs-extensions-v/}" >> $GITHUB_ENV
shell: bash
- name: Setup .NET Core 3.1 SDK
uses: actions/setup-dotnet@v4
Expand Down
7 changes: 7 additions & 0 deletions Lib.Net.Http.WebPush.sln
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lib.Azure.Functions.Worker.Extensions.WebPush", "src\Lib.Azure.Functions.Worker.Extensions.WebPush\Lib.Azure.Functions.Worker.Extensions.WebPush.csproj", "{FF54B26A-8E32-4D2F-B91E-C8BAAFE9148D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -59,6 +61,10 @@ Global
{E0746BE4-61F3-4366-8C7E-99C2350A0DD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0746BE4-61F3-4366-8C7E-99C2350A0DD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0746BE4-61F3-4366-8C7E-99C2350A0DD3}.Release|Any CPU.Build.0 = Release|Any CPU
{FF54B26A-8E32-4D2F-B91E-C8BAAFE9148D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FF54B26A-8E32-4D2F-B91E-C8BAAFE9148D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF54B26A-8E32-4D2F-B91E-C8BAAFE9148D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FF54B26A-8E32-4D2F-B91E-C8BAAFE9148D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -70,6 +76,7 @@ Global
{001A4013-EE58-428A-BD6C-49AC3A0CA6F9} = {0441724F-48F7-4863-BBA6-586E10182605}
{D9CF3828-E0F8-4A92-97D3-4B79E9C38F58} = {0441724F-48F7-4863-BBA6-586E10182605}
{E0746BE4-61F3-4366-8C7E-99C2350A0DD3} = {AFD9AC51-E923-49DF-B000-721816ABDE37}
{FF54B26A-8E32-4D2F-B91E-C8BAAFE9148D} = {0441724F-48F7-4863-BBA6-586E10182605}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {88535C7E-5564-4AC1-A41B-18DD05637943}
Expand Down
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@
[![NuGet Version](https://img.shields.io/nuget/v/Lib.Azure.WebJobs.Extensions.WebPush?label=Lib.Azure.WebJobs.Extensions.WebPush&logo=nuget)](https://www.nuget.org/packages/Lib.Azure.WebJobs.Extensions.WebPush)
[![NuGet Downloads](https://img.shields.io/nuget/dt/Lib.Azure.WebJobs.Extensions.WebPush?label=⭳)](https://www.nuget.org/packages/Lib.Azure.WebJobs.Extensions.WebPush)

[![NuGet Version](https://img.shields.io/nuget/v/Lib.Azure.Functions.Worker.Extensions.WebPush?label=Lib.Azure.Functions.Worker.Extensions.WebPush&logo=nuget)](https://www.nuget.org/packages/Lib.Azure.Functions.Worker.Extensions.WebPush)
[![NuGet Downloads](https://img.shields.io/nuget/dt/Lib.Azure.Functions.Worker.Extensions.WebPush?label=⭳)](https://www.nuget.org/packages/Lib.Azure.Functions.Worker.Extensions.WebPush)

Lib.Net.Http.WebPush is a library which provides a [Web Push Protocol](https://tools.ietf.org/html/rfc8030) based client for Push Service. It provides support for [Voluntary Application Server Identification (VAPID) for Web Push](https://tools.ietf.org/html/rfc8292) and [Message Encryption for Web Push](https://tools.ietf.org/html/rfc8291).

Lib.AspNetCore.WebPush is a library which provides ASP.NET Core extensions for Web Push Protocol based client for Push Service.

Lib.Azure.WebJobs.Extensions.WebPush is a library which provides [Azure Functions](https://functions.azure.com/) and [Azure WebJobs](https://docs.microsoft.com/en-us/azure/app-service/web-sites-create-web-jobs) binding extensions for Web Push Protocol based client for Push Service.
Lib.Azure.WebJobs.Extensions.WebPush is a library which provides [Azure Functions](https://functions.azure.com/) in-process model and [Azure WebJobs](https://docs.microsoft.com/en-us/azure/app-service/web-sites-create-web-jobs) binding extensions for Web Push Protocol based client for Push Service.

Lib.Azure.Functions.Worker.Extensions.WebPush is a library which provides [Azure Functions](https://functions.azure.com/) isolated worker model extensions for Web Push Protocol based client for Push Service.

## Installation

You can install [Lib.Net.Http.WebPush](https://www.nuget.org/packages/Lib.Net.Http.WebPush), [Lib.AspNetCore.WebPush](https://www.nuget.org/packages/Lib.AspNetCore.WebPush), and [Lib.Azure.WebJobs.Extensions.WebPush](https://www.nuget.org/packages/Lib.Azure.WebJobs.Extensions.WebPush) from NuGet.
You can install [Lib.Net.Http.WebPush](https://www.nuget.org/packages/Lib.Net.Http.WebPush), [Lib.AspNetCore.WebPush](https://www.nuget.org/packages/Lib.AspNetCore.WebPush), [Lib.Azure.WebJobs.Extensions.WebPush](https://www.nuget.org/packages/Lib.Azure.WebJobs.Extensions.WebPush), and [Lib.Azure.Functions.Worker.Extensions.WebPush](https://www.nuget.org/packages/Lib.Azure.Functions.Worker.Extensions.WebPush) from NuGet.

```
PM> Install-Package Lib.Net.Http.WebPush
Expand All @@ -31,6 +36,10 @@ PM> Install-Package Lib.AspNetCore.WebPush
PM> Install-Package Lib.Azure.WebJobs.Extensions.WebPush
```

```
PM> Install-Package Lib.Azure.Functions.Worker.Extensions.WebPush
```

## Documentation

The documentation is available [here](https://tpeczek.github.io/Lib.Net.Http.WebPush/).
Expand Down
2 changes: 1 addition & 1 deletion docs/DocFx.Net.Http.WebPush/DocFx.Net.Http.WebPush.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="docfx.console" Version="2.59.0">
<PackageReference Include="docfx.console" Version="2.59.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
Expand Down
152 changes: 118 additions & 34 deletions docs/DocFx.Net.Http.WebPush/articles/azure-functions-integration.md
Original file line number Diff line number Diff line change
@@ -1,80 +1,165 @@
# PushServiceClient bindings for Azure Functions

The [`PushServiceClient`](../api/Lib.Net.Http.WebPush.PushServiceClient.html) bindings for Azure Functions supports input binding.
The [`PushServiceClient`](../api/Lib.Net.Http.WebPush.PushServiceClient.html) extensions for Azure Functions supports input binding.

## Packages

The [`PushServiceClient`](../api/Lib.Net.Http.WebPush.PushServiceClient.html) bindings for Azure Functions are provided in the [Lib.Azure.WebJobs.Extensions.WebPush](https://www.nuget.org/packages/Lib.Azure.WebJobs.Extensions.WebPush) NuGet package.
The [`PushServiceClient`](../api/Lib.Net.Http.WebPush.PushServiceClient.html) extensions for Azure Functions are provided in the [Lib.Azure.WebJobs.Extensions.WebPush](https://www.nuget.org/packages/Lib.Azure.WebJobs.Extensions.WebPush) (in-process model) and [Lib.Azure.Functions.Worker.Extensions.WebPush](https://www.nuget.org/packages/Lib.Azure.Functions.Worker.Extensions.WebPush) (isolated worker model) NuGet packages.

```
PM> Install-Package Lib.Azure.WebJobs.Extensions.WebPush
```

```
PM> Install-Package Lib.Azure.Functions.Worker.Extensions.WebPush
```

## Input

The [`PushServiceClient`](../api/Lib.Net.Http.WebPush.PushServiceClient.html) input binding uses `HttpClientFactory` to retrieve [`PushServiceClient`](../api/Lib.Net.Http.WebPush.PushServiceClient.html) instance and passes it to the input parameter of the function.

### Input - language-specific examples

#### Input - C# examples
In [C# class libraries](https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-class-library), use the [`PushService`](../api/Lib.Azure.WebJobs.Extensions.WebPush.Bindings.PushServiceAttribute.html) attribute.

##### Isolated Worker Model
In [the isolated worker model functions](https://learn.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide?tabs=windows), use the [`PushServiceInput`](../api/Lib.Azure.Functions.Worker.Extensions.WebPush.PushServiceInputAttribute.html) attribute.

The attribute's constructor takes the application server public key and application server private key. For information about those settings and other properties that you can configure, see [Input - configuration](#input---configuration).

This section contains the following examples:
- [Azure Cosmos DB trigger, subscriptions from Azure Cosmos DB](#azure-cosmos-db-trigger-subscriptions-from-azure-cosmos-db)
###### Azure Cosmos DB trigger, subscriptions from Azure Cosmos DB
The following example shows a [C# function](https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-class-library) that broadcasts a notification to all known subscriptions. The function is triggered by a change in Azure Cosmos DB collection and retrieves subscriptions also from Azure Cosmos DB.

```cs
...

namespace Demo.Azure.Functions.Worker.PushNotifications
{
public class SendNotificationFunction
{
private readonly ILogger _logger;

public SendNotificationFunction(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<SendNotificationFunction>();
}

##### Azure Cosmos DB trigger, subscriptions from Azure Cosmos DB
[Function("SendNotificationFunction")]
public async Task Run([CosmosDBTrigger(
databaseName: "PushNotifications",
containerName: "Notifications",
Connection = "CosmosDBConnection",
LeaseContainerName = "NotificationsLeaseCollection",
CreateLeaseContainerIfNotExists = true)] IReadOnlyList<Notification> notifications,
[CosmosDBInput(
databaseName: "PushNotifications",
containerName: "Subscriptions",
Connection = "CosmosDBConnection")] CosmosClient cosmosClient,
[PushServiceInput(
PublicKeySetting = "ApplicationServerPublicKey",
PrivateKeySetting = "ApplicationServerPrivateKey",
SubjectSetting = "ApplicationServerSubject")] PushServiceClient pushServiceClient)
{
if (notifications != null)
{
Container subscriptionsContainer = cosmosClient.GetDatabase("PushNotifications").GetContainer("Subscriptions");
using (FeedIterator<PushSubscription> subscriptionsIterator = subscriptionsContainer.GetItemQueryIterator<PushSubscription>())
{
while (subscriptionsIterator.HasMoreResults)
{
foreach (PushSubscription subscription in await subscriptionsIterator.ReadNextAsync())
{
foreach (Notification notification in notifications)
{
// Fire-and-forget
pushServiceClient.RequestPushMessageDeliveryAsync(subscription, new PushMessage(notification.Content)
{
Topic = notification.Topic,
TimeToLive = notification.TimeToLive,
Urgency = notification.Urgency
});
}
}
}
}
}
}
}

public class Notification
{
public string? Topic { get; set; }

public string Content { get; set; } = String.Empty;

public int? TimeToLive { get; set; }

public PushMessageUrgency Urgency { get; set; }
}
}
```

##### In-process Model
In [C# class libraries](https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-class-library), use the [`PushService`](../api/Lib.Azure.WebJobs.Extensions.WebPush.Bindings.PushServiceAttribute.html) attribute.

The attribute's constructor takes the application server public key and application server private key. For information about those settings and other properties that you can configure, see [Input - configuration](#input---configuration).

###### Azure Cosmos DB trigger, subscriptions from Azure Cosmos DB
The following example shows a [C# function](https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-class-library) that broadcasts a notification to all known subscriptions. The function is triggered by a change in Azure Cosmos DB collection and retrieves subscriptions also from Azure Cosmos DB.

```cs
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.Documents.Linq;
using Microsoft.Azure.Documents.Client;
using Lib.Net.Http.WebPush;
using Lib.Azure.WebJobs.Extensions.WebPush.Bindings;
...

namespace Demo.Azure.Funtions.PushNotifications
{
public static class SendNotificationFunction
public class Notification
{
private static readonly Uri _subscriptionsCollectionUri = UriFactory.CreateDocumentCollectionUri("PushNotifications", "SubscriptionsCollection");
public string Topic { get; set; }

public string Content { get; set; }

public int? TimeToLive { get; set; }

public PushMessageUrgency Urgency { get; set; }
}

public static class SendNotificationFunction
{
[FunctionName("SendNotification")]
public static async Task Run([CosmosDBTrigger(
databaseName: "PushNotifications",
collectionName: "NotificationsCollection",
ConnectionStringSetting = "CosmosDBConnection",
LeaseCollectionName = "NotificationsLeaseCollection",
CreateLeaseCollectionIfNotExists = true)]IReadOnlyList<PushMessage> notifications,
containerName: "Notifications",
Connection = "CosmosDBConnection",
LeaseContainerName = "NotificationsLeaseCollection",
CreateLeaseContainerIfNotExists = true)]IReadOnlyList<Notification> notifications,
[CosmosDB(
databaseName: "PushNotifications",
collectionName: "SubscriptionsCollection",
ConnectionStringSetting = "CosmosDBConnection")]DocumentClient cosmosDbClient,
containerName: "Subscriptions",
Connection = "CosmosDBConnection")]CosmosClient cosmosClient,
[PushService(
PublicKeySetting = "ApplicationServerPublicKey",
PrivateKeySetting = "ApplicationServerPrivateKey",
SubjectSetting = "ApplicationServerSubject")]PushServiceClient pushServiceClient)
{
if (notifications != null)
{
IDocumentQuery<PushSubscription> subscriptionQuery = cosmosDbClient.CreateDocumentQuery<PushSubscription>(_subscriptionsCollectionUri, new FeedOptions
Container subscriptionsContainer = cosmosClient.GetDatabase("PushNotifications").GetContainer("Subscriptions");
using (FeedIterator<PushSubscription> subscriptionsIterator = subscriptionsContainer.GetItemQueryIterator<PushSubscription>())
{
EnableCrossPartitionQuery = true,
MaxItemCount = -1
}).AsDocumentQuery();

while (subscriptionQuery.HasMoreResults)
{
foreach (PushSubscription subscription in await subscriptionQuery.ExecuteNextAsync())
while (subscriptionsIterator.HasMoreResults)
{
foreach (PushMessage notification in notifications)
foreach (PushSubscription subscription in await subscriptionsIterator.ReadNextAsync())
{
// Fire-and-forget
pushServiceClient.RequestPushMessageDeliveryAsync(subscription, notification);
foreach (Notification notification in notifications)
{
// Fire-and-forget
pushServiceClient.RequestPushMessageDeliveryAsync(subscription, new PushMessage(notification.Content)
{
Topic = notification.Topic,
TimeToLive = notification.TimeToLive,
Urgency = notification.Urgency
});
}
}
}
}
Expand All @@ -84,7 +169,6 @@ namespace Demo.Azure.Funtions.PushNotifications
}
```


### Input - configuration

The following table explains the binding configuration properties that you set in the *function.json* file and the [`PushService`](../api/Lib.Azure.WebJobs.Extensions.WebPush.Bindings.PushServiceAttribute.html) attribute.
Expand Down
5 changes: 3 additions & 2 deletions docs/DocFx.Net.Http.WebPush/docfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
"files": [
"src/Lib.Net.Http.WebPush/Lib.Net.Http.WebPush.csproj",
"src/Lib.AspNetCore.WebPush/Lib.AspNetCore.WebPush.csproj",
"src/Lib.Azure.WebJobs.Extensions.WebPush/Lib.Azure.WebJobs.Extensions.WebPush.csproj"
"src/Lib.Azure.WebJobs.Extensions.WebPush/Lib.Azure.WebJobs.Extensions.WebPush.csproj",
"src/Lib.Azure.Functions.Worker.Extensions.WebPush/Lib.Azure.Functions.Worker.Extensions.WebPush.csproj"
],
"exclude": [ "**/bin/**", "**/obj/**" ],
"src": "../.."
}
],
"dest": "api",
"properties": {
"TargetFramework": "netstandard2.0"
"TargetFramework": "net6.0"
}
}
],
Expand Down
Loading
Loading