diff --git a/eng/Packages.Data.props b/eng/Packages.Data.props
index 487e44e538adb..92d69ceb0cd06 100644
--- a/eng/Packages.Data.props
+++ b/eng/Packages.Data.props
@@ -151,6 +151,7 @@
+
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/CHANGELOG.md b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/CHANGELOG.md
new file mode 100644
index 0000000000000..2ebb6a5ce5854
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/CHANGELOG.md
@@ -0,0 +1,11 @@
+# Release History
+
+## 1.5.0-beta.1 (Unreleased)
+
+### Features Added
+
+### Breaking Changes
+
+### Bugs Fixed
+
+### Other Changes
\ No newline at end of file
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/Directory.Build.props b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/Directory.Build.props
new file mode 100644
index 0000000000000..63bd836ad44b7
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/Directory.Build.props
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub.sln b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub.sln
new file mode 100644
index 0000000000000..b45ced91ac508
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.4.33213.308
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Azure.Functions.Worker.Extensions.WebPubSub", "src\Microsoft.Azure.Functions.Worker.Extensions.WebPubSub.csproj", "{8FD378FF-7228-4A8D-AB9B-65D60A386E94}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8FD378FF-7228-4A8D-AB9B-65D60A386E94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8FD378FF-7228-4A8D-AB9B-65D60A386E94}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8FD378FF-7228-4A8D-AB9B-65D60A386E94}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8FD378FF-7228-4A8D-AB9B-65D60A386E94}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {6A1FF741-58C3-4C13-A0D5-54902BE0CC44}
+ EndGlobalSection
+EndGlobal
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/README.md b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/README.md
new file mode 100644
index 0000000000000..39f35c4809aea
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/README.md
@@ -0,0 +1,178 @@
+# Azure Web PubSub extension of isolated-process Azure Functions client library for .NET
+
+This extension defines the binding types and triggers in the .NET isolated worker process for Azure Functions, allowing you to write functions that respond to any event published to Web PubSub.
+
+[Source code][source] |
+Package |
+API reference documentation |
+[Product documentation](https://aka.ms/awps/doc) |
+[Samples]
+
+## Getting started
+
+### Install the package
+
+Install the client library from [NuGet]:
+
+```dotnetcli
+dotnet add package Microsoft.Azure.Functions.Worker.Extensions.WebPubSub
+```
+
+### Prerequisites
+
+You must have an [Azure subscription][free_subs] and an Azure resource group with a Web PubSub resource. Follow this [step-by-step tutorial][tutorial] to create an Azure Web PubSub instance.
+
+### Authenticate the client
+
+In order to let the extension work with Azure Web PubSub service, you will need to provide a valid `ConnectionString`.
+
+You can find the **Keys** for you Azure Web PubSub service in the [Azure Portal][portal].
+
+The `AzureWebJobsStorage` connection string is used to preserve the processing checkpoint information as required refer to [Storage considerations][storage]
+
+For the local development use the `local.settings.json` file to store the connection string, `` can be set to `WebPubSubConnectionString` as default supported in the extension, or you can set customized names by mapping it with `Connection = ` in function binding attributes:
+
+```json
+{
+ "Values": {
+ "AzureWebJobsStorage": "UseDevelopmentStorage=true",
+ "": "Endpoint=https://.webpubsub.azure.com;AccessKey=;Version=1.0;"
+ }
+}
+```
+When deployed use the [application settings][app_setting] to set the connection string.
+
+## Key concepts
+
+### Using Web PubSub input binding
+
+Please follow the [input binding tutorial](#functions-that-uses-web-pubsub-input-binding) to learn about using this extension for building `WebPubSubConnection` to create Websockets connection to service with input binding.
+
+### Using Web PubSub output binding
+
+Please follow the [output binding tutorial](#functions-that-uses-web-pubsub-output-binding) to learn about using this extension for publishing Web PubSub messages.
+
+### Using Web PubSub trigger
+
+Please follow the [trigger binding tutorial](#functions-that-uses-web-pubsub-trigger) to learn about triggering an Azure Function when an event is sent from service upstream.
+
+In `Connect` and `UserEvent` events, function will respect return values to send back service. Then service will depend on the response to proceed the request or else. The responses and events are paired. For example, `Connect` will only respect `ConnectEventResponse` or `EventErrorResponse`, and ignore other returns. When `EventErrorResponse` is returned, service will drop client connection.
+
+## Examples
+
+### Functions that uses Web PubSub input binding
+
+Use `WebPubSubConnectionInput` to build the client negotiate URL.
+
+```C# Snippet:WebPubSubConnectionInputFunction
+[Function("Negotiate")]
+public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequestData req,
+[WebPubSubConnectionInput(Hub = "", Connection = "")] WebPubSubConnection connectionInfo)
+{
+ var response = req.CreateResponse(HttpStatusCode.OK);
+ response.WriteAsJsonAsync(connectionInfo);
+ return response;
+}
+```
+
+Use `WebPubSubContextInput` to read Web PubSub request under `HttpTrigger`. This is useful when work with Static Web Apps which supports `HttpTrigger` functions only.
+
+```C# Snippet:WebPubSubContextInputFunction
+// validate method when upstream set as http:///api/{event}
+[Function("validate")]
+public static HttpResponseData Validate(
+ [HttpTrigger(AuthorizationLevel.Anonymous, "options")] HttpRequestData req,
+ [WebPubSubContextInput] WebPubSubContext wpsReq)
+{
+ return BuildHttpResponseData(req, wpsReq.Response);
+}
+
+// Respond AbuseProtection to put header correctly.
+private static HttpResponseData BuildHttpResponseData(HttpRequestData request, SimpleResponse wpsResponse)
+{
+ var response = request.CreateResponse();
+ response.StatusCode = (HttpStatusCode)wpsResponse.Status;
+ response.Body = response.Body;
+ foreach (var header in wpsResponse.Headers)
+ {
+ response.Headers.Add(header.Key, header.Value);
+ }
+ return response;
+}
+```
+
+### Functions that uses Web PubSub output binding
+
+```C# Snippet:WebPubSubOutputFunction
+[Function("Notification")]
+[WebPubSubOutput(Hub = "", Connection = "")]
+public static WebPubSubAction Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
+{
+ return new SendToAllAction
+ {
+ Data = BinaryData.FromString($"Hello SendToAll."),
+ DataType = WebPubSubDataType.Text
+ };
+}
+```
+
+### Functions that uses Web PubSub trigger
+
+```C# Snippet:WebPubSubTriggerUserEventFunction
+[Function("Broadcast")]
+public static UserEventResponse Run(
+[WebPubSubTrigger("", WebPubSubEventType.User, "message")] UserEventRequest request)
+{
+ return new UserEventResponse("[SYSTEM ACK] Received.");
+}
+```
+
+For more details see the [samples README][samples].
+
+## Troubleshooting
+
+Please refer to [Monitor Azure Functions][monitor] for troubleshooting guidance.
+
+## Next steps
+
+Read the [introduction to Azure Function][func_intro] or [creating an Azure Function guide][create].
+
+## Contributing
+
+See our [CONTRIBUTING.md][contrib] for details on building,
+testing, and contributing to this library.
+
+This project welcomes contributions and suggestions. Most contributions require
+you to agree to a Contributor License Agreement (CLA) declaring that you have
+the right to, and actually do, grant us the rights to use your contribution. For
+details, visit [cla.microsoft.com][cla].
+
+This project has adopted the [Microsoft Open Source Code of Conduct][coc].
+For more information see the [Code of Conduct FAQ][coc_faq]
+or contact [opencode@microsoft.com][coc_contact] with any
+additional questions or comments.
+
+![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net%2Fsdk%2Fsearch%2FMicrosoft.Azure.Functions.Worker.Extensions.WebPubSub%2FREADME.png)
+
+
+
+[source]: https://github.com/JialinXin/azure-sdk-for-net/tree/awps/isolated-func/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src
+
+
+
+[samples]: https://github.com/JialinXin/azure-sdk-for-net/tree/awps/isolated-func/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples
+[nuget]: https://www.nuget.org/
+[free_subs]: https://azure.microsoft.com/free/dotnet/
+[portal]: https://portal.azure.com/
+[tutorial]: https://learn.microsoft.com/azure/azure-web-pubsub/howto-develop-create-instance
+[storage]: https://learn.microsoft.com/azure/azure-functions/storage-considerations#storage-account-requirements
+[app_setting]: https://learn.microsoft.com/azure/azure-functions/functions-how-to-use-azure-function-app-settings
+[monitor]: https://learn.microsoft.com/azure/azure-functions/functions-monitoring
+[func_intro]: https://learn.microsoft.com/azure/azure-functions/functions-overview
+[create]: https://learn.microsoft.com/azure/azure-functions/functions-overview
+
+[contrib]: https://github.com/Azure/azure-sdk-for-net/tree/main/CONTRIBUTING.md
+[cla]: https://cla.microsoft.com
+[coc]: https://opensource.microsoft.com/codeofconduct/
+[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/
+[coc_contact]: mailto:opencode@microsoft.com
\ No newline at end of file
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/api/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub.netstandard2.0.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/api/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub.netstandard2.0.cs
new file mode 100644
index 0000000000000..ee553b8d299cd
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/api/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub.netstandard2.0.cs
@@ -0,0 +1,313 @@
+namespace Microsoft.Azure.Functions.Worker
+{
+ public sealed partial class AddConnectionToGroupAction : Microsoft.Azure.Functions.Worker.WebPubSubAction
+ {
+ public AddConnectionToGroupAction() { }
+ public string ConnectionId { get { throw null; } set { } }
+ public string Group { get { throw null; } set { } }
+ }
+ public sealed partial class AddUserToGroupAction : Microsoft.Azure.Functions.Worker.WebPubSubAction
+ {
+ public AddUserToGroupAction() { }
+ public string Group { get { throw null; } set { } }
+ public string UserId { get { throw null; } set { } }
+ }
+ public sealed partial class CloseAllConnectionsAction : Microsoft.Azure.Functions.Worker.WebPubSubAction
+ {
+ public CloseAllConnectionsAction() { }
+ public System.Collections.Generic.IList Excluded { get { throw null; } set { } }
+ public string Reason { get { throw null; } set { } }
+ }
+ public sealed partial class CloseClientConnectionAction : Microsoft.Azure.Functions.Worker.WebPubSubAction
+ {
+ public CloseClientConnectionAction() { }
+ public string ConnectionId { get { throw null; } set { } }
+ public string Reason { get { throw null; } set { } }
+ }
+ public sealed partial class CloseGroupConnectionsAction : Microsoft.Azure.Functions.Worker.WebPubSubAction
+ {
+ public CloseGroupConnectionsAction() { }
+ public System.Collections.Generic.IList Excluded { get { throw null; } set { } }
+ public string Group { get { throw null; } set { } }
+ public string Reason { get { throw null; } set { } }
+ }
+ public sealed partial class ConnectedEventRequest : Microsoft.Azure.Functions.Worker.WebPubSubEventRequest
+ {
+ public ConnectedEventRequest() { }
+ }
+ public sealed partial class ConnectEventRequest : Microsoft.Azure.Functions.Worker.WebPubSubEventRequest
+ {
+ public ConnectEventRequest() { }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("claims")]
+ public System.Collections.Generic.IReadOnlyDictionary Claims { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("clientCertificates")]
+ public System.Collections.Generic.IReadOnlyList ClientCertificates { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("headers")]
+ public System.Collections.Generic.IReadOnlyDictionary Headers { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("query")]
+ public System.Collections.Generic.IReadOnlyDictionary Query { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("subprotocols")]
+ public System.Collections.Generic.IReadOnlyList Subprotocols { get { throw null; } set { } }
+ public static Microsoft.Azure.Functions.Worker.EventErrorResponse CreateErrorResponse(Microsoft.Azure.Functions.Worker.WebPubSubErrorCode code, string message) { throw null; }
+ public static Microsoft.Azure.Functions.Worker.ConnectEventResponse CreateResponse(string userId, System.Collections.Generic.IEnumerable groups, string subprotocol, System.Collections.Generic.IEnumerable roles) { throw null; }
+ }
+ public partial class ConnectEventResponse : Microsoft.Azure.Functions.Worker.WebPubSubEventResponse
+ {
+ public ConnectEventResponse() { }
+ public ConnectEventResponse(string userId, System.Collections.Generic.IEnumerable groups, string subprotocol, System.Collections.Generic.IEnumerable roles) { }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("states")]
+ public System.Collections.Generic.IReadOnlyDictionary ConnectionStates { get { throw null; } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("groups")]
+ public string[] Groups { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("roles")]
+ public string[] Roles { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("subprotocol")]
+ public string Subprotocol { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("userId")]
+ public string UserId { get { throw null; } set { } }
+ public void ClearStates() { }
+ public void SetState(string key, System.BinaryData value) { }
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
+ public void SetState(string key, object value) { }
+ }
+ public sealed partial class DisconnectedEventRequest : Microsoft.Azure.Functions.Worker.WebPubSubEventRequest
+ {
+ public DisconnectedEventRequest() { }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("reason")]
+ public string Reason { get { throw null; } set { } }
+ }
+ public partial class EventErrorResponse : Microsoft.Azure.Functions.Worker.WebPubSubEventResponse
+ {
+ public EventErrorResponse() { }
+ public EventErrorResponse(Microsoft.Azure.Functions.Worker.WebPubSubErrorCode code, string message = null) { }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("code")]
+ public Microsoft.Azure.Functions.Worker.WebPubSubErrorCode Code { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("errorMessage")]
+ public string ErrorMessage { get { throw null; } set { } }
+ }
+ public sealed partial class GrantPermissionAction : Microsoft.Azure.Functions.Worker.WebPubSubAction
+ {
+ public GrantPermissionAction() { }
+ public string ConnectionId { get { throw null; } set { } }
+ public Microsoft.Azure.Functions.Worker.WebPubSubPermission Permission { get { throw null; } set { } }
+ public string TargetName { get { throw null; } set { } }
+ }
+ public sealed partial class PreflightRequest : Microsoft.Azure.Functions.Worker.WebPubSubEventRequest
+ {
+ public PreflightRequest() { }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("isValid")]
+ public bool IsValid { get { throw null; } set { } }
+ }
+ public sealed partial class RemoveConnectionFromGroupAction : Microsoft.Azure.Functions.Worker.WebPubSubAction
+ {
+ public RemoveConnectionFromGroupAction() { }
+ public string ConnectionId { get { throw null; } set { } }
+ public string Group { get { throw null; } set { } }
+ }
+ public sealed partial class RemoveUserFromAllGroupsAction : Microsoft.Azure.Functions.Worker.WebPubSubAction
+ {
+ public RemoveUserFromAllGroupsAction() { }
+ public string UserId { get { throw null; } set { } }
+ }
+ public sealed partial class RemoveUserFromGroupAction : Microsoft.Azure.Functions.Worker.WebPubSubAction
+ {
+ public RemoveUserFromGroupAction() { }
+ public string Group { get { throw null; } set { } }
+ public string UserId { get { throw null; } set { } }
+ }
+ public sealed partial class RevokePermissionAction : Microsoft.Azure.Functions.Worker.WebPubSubAction
+ {
+ public RevokePermissionAction() { }
+ public string ConnectionId { get { throw null; } set { } }
+ public Microsoft.Azure.Functions.Worker.WebPubSubPermission Permission { get { throw null; } set { } }
+ public string TargetName { get { throw null; } set { } }
+ }
+ public sealed partial class SendToAllAction : Microsoft.Azure.Functions.Worker.WebPubSubAction
+ {
+ public SendToAllAction() { }
+ public System.BinaryData Data { get { throw null; } set { } }
+ public Microsoft.Azure.Functions.Worker.WebPubSubDataType DataType { get { throw null; } set { } }
+ public System.Collections.Generic.IList Excluded { get { throw null; } set { } }
+ }
+ public partial class SendToConnectionAction : Microsoft.Azure.Functions.Worker.WebPubSubAction
+ {
+ public SendToConnectionAction() { }
+ public string ConnectionId { get { throw null; } set { } }
+ public System.BinaryData Data { get { throw null; } set { } }
+ public Microsoft.Azure.Functions.Worker.WebPubSubDataType DataType { get { throw null; } set { } }
+ }
+ public partial class SendToGroupAction : Microsoft.Azure.Functions.Worker.WebPubSubAction
+ {
+ public SendToGroupAction() { }
+ public System.BinaryData Data { get { throw null; } set { } }
+ public Microsoft.Azure.Functions.Worker.WebPubSubDataType DataType { get { throw null; } set { } }
+ public System.Collections.Generic.IList Excluded { get { throw null; } set { } }
+ public string Group { get { throw null; } set { } }
+ }
+ public sealed partial class SendToUserAction : Microsoft.Azure.Functions.Worker.WebPubSubAction
+ {
+ public SendToUserAction() { }
+ public System.BinaryData Data { get { throw null; } set { } }
+ public Microsoft.Azure.Functions.Worker.WebPubSubDataType DataType { get { throw null; } set { } }
+ public string UserId { get { throw null; } set { } }
+ }
+ public sealed partial class UserEventRequest : Microsoft.Azure.Functions.Worker.WebPubSubEventRequest
+ {
+ public UserEventRequest() { }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("data")]
+ public System.BinaryData Data { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("dataType")]
+ public Microsoft.Azure.Functions.Worker.WebPubSubDataType DataType { get { throw null; } set { } }
+ public static Microsoft.Azure.Functions.Worker.EventErrorResponse CreateErrorResponse(Microsoft.Azure.Functions.Worker.WebPubSubErrorCode code, string message) { throw null; }
+ public static Microsoft.Azure.Functions.Worker.UserEventResponse CreateResponse(System.BinaryData data, Microsoft.Azure.Functions.Worker.WebPubSubDataType dataType) { throw null; }
+ public static Microsoft.Azure.Functions.Worker.UserEventResponse CreateResponse(string data, Microsoft.Azure.Functions.Worker.WebPubSubDataType dataType = Microsoft.Azure.Functions.Worker.WebPubSubDataType.Text) { throw null; }
+ }
+ [System.Runtime.Serialization.DataContractAttribute]
+ public partial class UserEventResponse : Microsoft.Azure.Functions.Worker.WebPubSubEventResponse
+ {
+ public UserEventResponse() { }
+ public UserEventResponse(System.BinaryData data, Microsoft.Azure.Functions.Worker.WebPubSubDataType dataType) { }
+ public UserEventResponse(string data, Microsoft.Azure.Functions.Worker.WebPubSubDataType dataType = Microsoft.Azure.Functions.Worker.WebPubSubDataType.Text) { }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("states")]
+ public System.Collections.Generic.IReadOnlyDictionary ConnectionStates { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("data")]
+ public System.BinaryData Data { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("dataType")]
+ public Microsoft.Azure.Functions.Worker.WebPubSubDataType DataType { get { throw null; } set { } }
+ public void ClearStates() { }
+ public void SetState(string key, System.BinaryData value) { }
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
+ public void SetState(string key, object value) { }
+ }
+ public abstract partial class WebPubSubAction
+ {
+ protected WebPubSubAction() { }
+ public string ActionName { get { throw null; } }
+ }
+ public sealed partial class WebPubSubClientCertificate
+ {
+ public WebPubSubClientCertificate() { }
+ public string Thumbprint { get { throw null; } set { } }
+ }
+ public sealed partial class WebPubSubConnection
+ {
+ public WebPubSubConnection() { }
+ public string AccessToken { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("baseUrl")]
+ public System.Uri BaseUri { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("url")]
+ public System.Uri Uri { get { throw null; } set { } }
+ }
+ public sealed partial class WebPubSubConnectionContext
+ {
+ public WebPubSubConnectionContext() { }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("connectionId")]
+ public string ConnectionId { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("states")]
+ public System.Collections.Generic.IReadOnlyDictionary ConnectionStates { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("eventName")]
+ public string EventName { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("eventType")]
+ public Microsoft.Azure.Functions.Worker.WebPubSubEventType EventType { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("headers")]
+ public System.Collections.Generic.IReadOnlyDictionary Headers { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("hub")]
+ public string Hub { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("origin")]
+ public string Origin { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("signature")]
+ public string Signature { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("userId")]
+ public string UserId { get { throw null; } set { } }
+ }
+ public sealed partial class WebPubSubConnectionInputAttribute : Microsoft.Azure.Functions.Worker.Extensions.Abstractions.InputBindingAttribute
+ {
+ public WebPubSubConnectionInputAttribute() { }
+ public string Connection { get { throw null; } set { } }
+ public string Hub { get { throw null; } set { } }
+ public string UserId { get { throw null; } set { } }
+ }
+ public sealed partial class WebPubSubContext
+ {
+ public WebPubSubContext() { }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("errorMessage")]
+ public string ErrorMessage { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("hasError")]
+ public bool HasError { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("isPreflight")]
+ public bool IsPreflight { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("request")]
+ public Microsoft.Azure.Functions.Worker.WebPubSubEventRequest Request { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("response")]
+ public Microsoft.Azure.Functions.Worker.WebPubSubSimpleResponse Response { get { throw null; } set { } }
+ }
+ public sealed partial class WebPubSubContextInputAttribute : Microsoft.Azure.Functions.Worker.Extensions.Abstractions.InputBindingAttribute
+ {
+ public WebPubSubContextInputAttribute() { }
+ public WebPubSubContextInputAttribute(params string[] connections) { }
+ public string[] Connections { get { throw null; } set { } }
+ }
+ [System.Text.Json.Serialization.JsonConverterAttribute(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))]
+ public enum WebPubSubDataType
+ {
+ Binary = 0,
+ Json = 1,
+ Text = 2,
+ }
+ [System.Text.Json.Serialization.JsonConverterAttribute(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))]
+ public enum WebPubSubErrorCode
+ {
+ Unauthorized = 0,
+ UserError = 1,
+ ServerError = 2,
+ }
+ public abstract partial class WebPubSubEventRequest
+ {
+ protected WebPubSubEventRequest() { }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("connectionContext")]
+ public Microsoft.Azure.Functions.Worker.WebPubSubConnectionContext ConnectionContext { get { throw null; } set { } }
+ }
+ public abstract partial class WebPubSubEventResponse
+ {
+ protected WebPubSubEventResponse() { }
+ }
+ [System.Text.Json.Serialization.JsonConverterAttribute(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))]
+ public enum WebPubSubEventType
+ {
+ System = 0,
+ User = 1,
+ }
+ public sealed partial class WebPubSubOutputAttribute : Microsoft.Azure.Functions.Worker.Extensions.Abstractions.OutputBindingAttribute
+ {
+ public WebPubSubOutputAttribute() { }
+ public string Connection { get { throw null; } set { } }
+ public string Hub { get { throw null; } set { } }
+ }
+ [System.Text.Json.Serialization.JsonConverterAttribute(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))]
+ public enum WebPubSubPermission
+ {
+ SendToGroup = 1,
+ JoinLeaveGroup = 2,
+ }
+ public sealed partial class WebPubSubSimpleResponse
+ {
+ public WebPubSubSimpleResponse() { }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("body")]
+ public string Body { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("headers")]
+ public System.Collections.Generic.Dictionary Headers { get { throw null; } set { } }
+ [System.Text.Json.Serialization.JsonPropertyNameAttribute("status")]
+ public int Status { get { throw null; } set { } }
+ }
+ public sealed partial class WebPubSubTriggerAttribute : Microsoft.Azure.Functions.Worker.Extensions.Abstractions.TriggerBindingAttribute
+ {
+ public WebPubSubTriggerAttribute(Microsoft.Azure.Functions.Worker.WebPubSubEventType eventType, string eventName) { }
+ public WebPubSubTriggerAttribute(Microsoft.Azure.Functions.Worker.WebPubSubEventType eventType, string eventName, params string[] connections) { }
+ public WebPubSubTriggerAttribute(string hub, Microsoft.Azure.Functions.Worker.WebPubSubEventType eventType, string eventName) { }
+ public WebPubSubTriggerAttribute(string hub, Microsoft.Azure.Functions.Worker.WebPubSubEventType eventType, string eventName, params string[] connections) { }
+ public string[] Connections { get { throw null; } }
+ public string EventName { get { throw null; } }
+ public Microsoft.Azure.Functions.Worker.WebPubSubEventType EventType { get { throw null; } }
+ public string Hub { get { throw null; } }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/README.md b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/README.md
new file mode 100644
index 0000000000000..35a044af774c1
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/README.md
@@ -0,0 +1,18 @@
+---
+page_type: sample
+languages:
+- csharp
+products:
+- azure
+- azure-web-pubsub
+name: Microsoft.Azure.Functions.Worker.Extensions.WebPubSub samples for .NET
+description: Samples for the Microsoft.Azure.Functions.Worker.Extensions.WebPubSub client library
+---
+
+# Azure Web PubSub isolated worker process client SDK samples
+
+
+ - [Negotiate](https://github.com/JialinXin/azure-sdk-for-net/blob/awps/isolated-func/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample1_Negotiate.md)
+ - [SendMessage](https://github.com/JialinXin/azure-sdk-for-net/blob/awps/isolated-func/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample2_SendMessage.md)
+ - [EventNotification](https://github.com/JialinXin/azure-sdk-for-net/blob/awps/isolated-func/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample3_EventNotification.md)
+ - [Input Binding under `HttpTrigger`](https://github.com/JialinXin/azure-sdk-for-net/blob/awps/isolated-func/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample4_HttpTriggerInputBinding.md)
\ No newline at end of file
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample1_Negotiate.md b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample1_Negotiate.md
new file mode 100644
index 0000000000000..9088123dfbdea
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample1_Negotiate.md
@@ -0,0 +1,14 @@
+# Use `WebPubSubConnectionInput` to build negotiate URL for the client
+
+This sample demonstrates how to work with `WebPubSubConnectionInput` binding to build the negotiate client URL. You can get the Web PubSub connection string from Azure Portal and set it in the `local.settings.json` with a preferred `web_pubsub_connection_name`. Then replace it with the `Connection` parameter in the binding attribute. Then when this function is triggered by clients, it will get a response with the Web PubSub service negotiate URL to start a new client connection.
+
+```C# Snippet:WebPubSubConnectionInputFunction
+[Function("Negotiate")]
+public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequestData req,
+[WebPubSubConnectionInput(Hub = "", Connection = "")] WebPubSubConnection connectionInfo)
+{
+ var response = req.CreateResponse(HttpStatusCode.OK);
+ response.WriteAsJsonAsync(connectionInfo);
+ return response;
+}
+```
\ No newline at end of file
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample2_SendMessage.md b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample2_SendMessage.md
new file mode 100644
index 0000000000000..0f62640c7ec26
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample2_SendMessage.md
@@ -0,0 +1,42 @@
+# Use `WebPubSubOutput` to invoke service to do actions
+
+This sample demonstrates how to work with `WebPubSubOutput` to invoke service do operations including send messages and manage clients. You can get the Web PubSub connection string from Azure Portal and set it in the `local.settings.json` with a preferred `web_pubsub_connection_name`. Then replace it with the `Connection` parameter in the binding attribute. Then when this function is triggered, it will leverage data plane REST APIs to operate required actions.
+
+## Single output
+
+```C# Snippet:WebPubSubOutputFunction
+[Function("Notification")]
+[WebPubSubOutput(Hub = "", Connection = "")]
+public static WebPubSubAction Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
+{
+ return new SendToAllAction
+ {
+ Data = BinaryData.FromString($"Hello SendToAll."),
+ DataType = WebPubSubDataType.Text
+ };
+}
+```
+
+## Multiple outputs
+
+```C# Snippet:WebPubSubOutputFunction_Multiple
+// multiple output
+[Function("Notification1")]
+[WebPubSubOutput(Hub = "", Connection = "")]
+public static WebPubSubAction[] MultipleActions([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
+{
+ return new WebPubSubAction[]
+ {
+ new SendToAllAction
+ {
+ Data = BinaryData.FromString($"Hello SendToAll."),
+ DataType = WebPubSubDataType.Text
+ },
+ new AddUserToGroupAction
+ {
+ UserId = "user A",
+ Group = "group A"
+ }
+ };
+}
+```
\ No newline at end of file
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample3_EventNotification.md b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample3_EventNotification.md
new file mode 100644
index 0000000000000..ff1a3100ef214
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample3_EventNotification.md
@@ -0,0 +1,14 @@
+# Use `WebPubSubTrigger` to get service notifications
+
+This sample demonstrates how to work with `WebPubSubTrigger` to get service notification. When work with `WebPubSubTrigger`, the event handler settings in the Web PubSub service should be like `https://.azurewebsites.net/runtime/webhooks/webpubsub?code=`. The `code` is required for an Azure Functions App but optional for a local Functions App. See [How to configure event handler](https://learn.microsoft.com/azure/azure-web-pubsub/howto-develop-eventhandler) for details.
+
+This sample below is a function to listen to the user event messages, that whenever a client send a message through the client websocket connection to the Web PubSub service, this configured Function App will be triggered. And with the `UserEventResponse` returned here, the caller client will get an ack with content as the function replied `[SYSTEM ACK] Received.`.
+
+```C# Snippet:WebPubSubTriggerUserEventFunction
+[Function("Broadcast")]
+public static UserEventResponse Run(
+[WebPubSubTrigger("", WebPubSubEventType.User, "message")] UserEventRequest request)
+{
+ return new UserEventResponse("[SYSTEM ACK] Received.");
+}
+```
\ No newline at end of file
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample4_HttpTriggerInputBinding.md b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample4_HttpTriggerInputBinding.md
new file mode 100644
index 0000000000000..c8c924db98d82
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/samples/Sample4_HttpTriggerInputBinding.md
@@ -0,0 +1,29 @@
+# Use `WebPubSubContextInput` to get service notifications
+
+This sample demonstrates how to work with `WebPubSubContextInput` to get service notification. This is useful when work with Static Web Apps which supports `HttpTrigger` functions only. With `WebPubSubContextInput`, the event handler settings in the Web PubSub service should be like `https://.azurewebsites.net/api/{event}}`. The reserved `{event}` is service defined events, and should be mapped to the function's name. See [How to configure event handler](https://learn.microsoft.com/azure/azure-web-pubsub/howto-develop-eventhandler) for details.
+
+This sample is listen to the abuse protection event, that to validate the upstream is a valid one. When the Web PubSub service is configured with `api/{event}`, it'll send to `api/validate` of this request as the first call to validate it.
+
+```C# Snippet:WebPubSubContextInputFunction
+// validate method when upstream set as http:///api/{event}
+[Function("validate")]
+public static HttpResponseData Validate(
+ [HttpTrigger(AuthorizationLevel.Anonymous, "options")] HttpRequestData req,
+ [WebPubSubContextInput] WebPubSubContext wpsReq)
+{
+ return BuildHttpResponseData(req, wpsReq.Response);
+}
+
+// Respond AbuseProtection to put header correctly.
+private static HttpResponseData BuildHttpResponseData(HttpRequestData request, SimpleResponse wpsResponse)
+{
+ var response = request.CreateResponse();
+ response.StatusCode = (HttpStatusCode)wpsResponse.Status;
+ response.Body = response.Body;
+ foreach (var header in wpsResponse.Headers)
+ {
+ response.Headers.Add(header.Key, header.Value);
+ }
+ return response;
+}
+```
\ No newline at end of file
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Converters/WebPubSubActionJsonConverter.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Converters/WebPubSubActionJsonConverter.cs
new file mode 100644
index 0000000000000..f19c0aca73744
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Converters/WebPubSubActionJsonConverter.cs
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ internal class WebPubSubActionJsonConverter : JsonConverter
+ {
+ public override WebPubSubAction Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Write(Utf8JsonWriter writer, WebPubSubAction value, JsonSerializerOptions options)
+ {
+ JsonSerializer.Serialize(writer, value, value.GetType(), options);
+ }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Converters/WebPubSubContextJsonConverter.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Converters/WebPubSubContextJsonConverter.cs
new file mode 100644
index 0000000000000..598e5a97b0c4d
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Converters/WebPubSubContextJsonConverter.cs
@@ -0,0 +1,64 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ internal class WebPubSubContextJsonConverter : JsonConverter
+ {
+ public override WebPubSubContext? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ using var jsonDoc = JsonDocument.ParseValue(ref reader);
+ var element = jsonDoc.RootElement;
+ var isPreflight = element.GetProperty("isPreflight").GetBoolean();
+ WebPubSubEventRequest request;
+ if (isPreflight)
+ {
+ request = JsonSerializer.Deserialize(element.GetProperty("request").GetRawText());
+ }
+ else
+ {
+ // depends on connectionContext info to parse request.
+ var connectionContext = JsonSerializer.Deserialize(element.GetProperty("request").GetProperty("connectionContext").GetRawText());
+ if (connectionContext.EventType == WebPubSubEventType.User)
+ {
+ request = JsonSerializer.Deserialize(element.GetProperty("request").GetRawText());
+ }
+ else if (connectionContext.EventName == "connect")
+ {
+ request = JsonSerializer.Deserialize(element.GetProperty("request").GetRawText());
+ }
+ else if (connectionContext.EventName == "disconnected")
+ {
+ request = JsonSerializer.Deserialize(element.GetProperty("request").GetRawText());
+ }
+ else if (connectionContext.EventName == "connected")
+ {
+ request = JsonSerializer.Deserialize(element.GetProperty("request").GetRawText());
+ }
+ else
+ {
+ throw new ArgumentException($"Not supported event. EventType: {connectionContext.EventType}, EventName: {connectionContext.EventName}.");
+ }
+ }
+
+ // according to property names to detect.
+ return new WebPubSubContext
+ {
+ Request = request,
+ Response = JsonSerializer.Deserialize(element.GetProperty("response").GetRawText()),
+ HasError = element.GetProperty("hasError").GetBoolean(),
+ ErrorMessage = element.GetProperty("errorMessage").GetString(),
+ IsPreflight = isPreflight
+ };
+ }
+
+ public override void Write(Utf8JsonWriter writer, WebPubSubContext value, JsonSerializerOptions options)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub.csproj b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub.csproj
new file mode 100644
index 0000000000000..ce3597392d9f3
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub.csproj
@@ -0,0 +1,24 @@
+
+
+ Microsoft.Azure.Functions.Worker.Extensions.WebPubSub
+ Azure, WebPubSub
+ Azure Web PubSub Service extensions for .NET isolated functions
+ $(RequiredTargetFrameworks)
+ annotations
+
+ 1.5.0-beta.1
+ $(NoWarn);AZC0001;CA2227
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Input/WebPubSubConnection.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Input/WebPubSubConnection.cs
new file mode 100644
index 0000000000000..5a3815f31d1b0
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Input/WebPubSubConnection.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Runtime.Serialization;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Contains necessary information for a Web PubSub client to connect to Web PubSub Service.
+ ///
+ public sealed class WebPubSubConnection
+ {
+ ///
+ /// Base Uri of the websocket connection.
+ ///
+ [JsonPropertyName("baseUrl")]
+ public Uri BaseUri { get; set; }
+
+ ///
+ /// Uri with accessToken of the websocket connection.
+ ///
+ [JsonPropertyName("url")]
+ public Uri Uri { get; set; }
+
+ ///
+ /// Access token of the websocket connection.
+ ///
+ public string AccessToken { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Input/WebPubSubContext.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Input/WebPubSubContext.cs
new file mode 100644
index 0000000000000..09df18b5e6b39
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Input/WebPubSubContext.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+using System.Net;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Web PubSub service request context.
+ ///
+ [JsonConverter(typeof(WebPubSubContextJsonConverter))]
+ public sealed class WebPubSubContext
+ {
+ ///
+ /// Request body.
+ ///
+ [JsonPropertyName("request")]
+ public WebPubSubEventRequest Request { get; set; }
+
+ ///
+ /// System build response for easy return, works for AbuseProtection and Errors.
+ ///
+ [JsonPropertyName("response")]
+ public WebPubSubSimpleResponse Response { get; set; }
+
+ ///
+ /// Error detail message.
+ ///
+ [JsonPropertyName("errorMessage")]
+ public string ErrorMessage { get; set; }
+
+ ///
+ /// Flag to indicate whether the request has error.
+ ///
+ [JsonPropertyName("hasError")]
+ public bool HasError { get; set; }
+
+ ///
+ /// Flag to indicate if it's a validation request.
+ ///
+ [JsonPropertyName("isPreflight")]
+ public bool IsPreflight { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/AddConnectionToGroupAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/AddConnectionToGroupAction.cs
new file mode 100644
index 0000000000000..3aace3fbd5064
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/AddConnectionToGroupAction.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Operation to add connectionId to a group.
+ ///
+ public sealed class AddConnectionToGroupAction : WebPubSubAction
+ {
+ ///
+ /// Target connectionId.
+ ///
+ public string ConnectionId { get; set; }
+
+ ///
+ /// Target group name.
+ ///
+ public string Group { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/AddUserToGroupAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/AddUserToGroupAction.cs
new file mode 100644
index 0000000000000..96282e4e2d939
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/AddUserToGroupAction.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Operation to add a user to group.
+ ///
+ public sealed class AddUserToGroupAction : WebPubSubAction
+ {
+ ///
+ /// Target userId.
+ ///
+ public string UserId { get; set; }
+
+ ///
+ /// Target group name.
+ ///
+ public string Group { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/CloseAllConnectionsAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/CloseAllConnectionsAction.cs
new file mode 100644
index 0000000000000..82d8be47bc915
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/CloseAllConnectionsAction.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Operation to close all connections.
+ ///
+ public sealed class CloseAllConnectionsAction : WebPubSubAction
+ {
+ ///
+ /// ConnectionIds to exclude.
+ ///
+ public IList Excluded { get; set; } = new List();
+
+ ///
+ /// Reason to close the connections.
+ ///
+ public string Reason { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/CloseClientConnectionAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/CloseClientConnectionAction.cs
new file mode 100644
index 0000000000000..1af568d0c21c3
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/CloseClientConnectionAction.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Operation to close a connection.
+ ///
+ public sealed class CloseClientConnectionAction : WebPubSubAction
+ {
+ ///
+ /// Target connectionId.
+ ///
+ public string ConnectionId { get; set; }
+
+ ///
+ /// Reason to close the connection.
+ ///
+ public string Reason { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/CloseGroupConnectionsAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/CloseGroupConnectionsAction.cs
new file mode 100644
index 0000000000000..73876b6234f88
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/CloseGroupConnectionsAction.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Operation to close connections in a group.
+ ///
+ public sealed class CloseGroupConnectionsAction : WebPubSubAction
+ {
+ ///
+ /// Target group name.
+ ///
+ public string Group { get; set; }
+
+ ///
+ /// ConnectionIds to exclude.
+ ///
+ public IList Excluded { get; set; } = new List();
+
+ ///
+ /// Reason to close the connections.
+ ///
+ public string Reason { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/GrantPermissionAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/GrantPermissionAction.cs
new file mode 100644
index 0000000000000..d64647b35c8f7
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/GrantPermissionAction.cs
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Operation to grant permission.
+ ///
+ public sealed class GrantPermissionAction : WebPubSubAction
+ {
+ ///
+ /// Target connectionId.
+ ///
+ public string ConnectionId { get; set; }
+
+ ///
+ /// Target permission.
+ ///
+ public WebPubSubPermission Permission { get; set; }
+
+ ///
+ /// Target name.
+ ///
+ public string TargetName { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/RemoveConnectionFromGroupAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/RemoveConnectionFromGroupAction.cs
new file mode 100644
index 0000000000000..4adbd899bab65
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/RemoveConnectionFromGroupAction.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Operation to remove a connection from group.
+ ///
+ public sealed class RemoveConnectionFromGroupAction : WebPubSubAction
+ {
+ ///
+ /// Target connectionId.
+ ///
+ public string ConnectionId { get; set; }
+
+ ///
+ /// Target group name.
+ ///
+ public string Group { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/RemoveUserFromAllGroupsAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/RemoveUserFromAllGroupsAction.cs
new file mode 100644
index 0000000000000..a2f2d32282312
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/RemoveUserFromAllGroupsAction.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Operation to remove user from all groups.
+ ///
+ public sealed class RemoveUserFromAllGroupsAction : WebPubSubAction
+ {
+ ///
+ /// Target UserId.
+ ///
+ public string UserId { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/RemoveUserFromGroupAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/RemoveUserFromGroupAction.cs
new file mode 100644
index 0000000000000..a46f892d97466
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/RemoveUserFromGroupAction.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Operation to remove a user from group.
+ ///
+ public sealed class RemoveUserFromGroupAction : WebPubSubAction
+ {
+ ///
+ /// Target userId.
+ ///
+ public string UserId { get; set; }
+
+ ///
+ /// Target group name.
+ ///
+ public string Group { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/RevokePermissionAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/RevokePermissionAction.cs
new file mode 100644
index 0000000000000..f22d03b1796c9
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/RevokePermissionAction.cs
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Operation to remove permission.
+ ///
+ public sealed class RevokePermissionAction : WebPubSubAction
+ {
+ ///
+ /// Targe connectionId.
+ ///
+ public string ConnectionId { get; set; }
+
+ ///
+ /// Target permission.
+ ///
+ public WebPubSubPermission Permission { get; set; }
+
+ ///
+ /// Target name.
+ ///
+ public string TargetName { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/SendToAllAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/SendToAllAction.cs
new file mode 100644
index 0000000000000..99d18cf7b24d9
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/SendToAllAction.cs
@@ -0,0 +1,31 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Operation to send message to all.
+ ///
+ public sealed class SendToAllAction : WebPubSubAction
+ {
+ ///
+ /// Message to broadcast.
+ ///
+ [JsonConverter(typeof(BinaryDataJsonConverter))]
+ public BinaryData Data { get; set; }
+
+ ///
+ /// Message data type.
+ ///
+ public WebPubSubDataType DataType { get; set; } = WebPubSubDataType.Text;
+
+ ///
+ /// ConnectionIds to excluded.
+ ///
+ public IList Excluded { get; set; } = new List();
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/SendToConnectionAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/SendToConnectionAction.cs
new file mode 100644
index 0000000000000..fc3ada460904a
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/SendToConnectionAction.cs
@@ -0,0 +1,30 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Operation to send message to a connection.
+ ///
+ public class SendToConnectionAction : WebPubSubAction
+ {
+ ///
+ /// Target ConnectionId.
+ ///
+ public string ConnectionId { get; set; }
+
+ ///
+ /// Message to send.
+ ///
+ [JsonConverter(typeof(BinaryDataJsonConverter))]
+ public BinaryData Data { get; set; }
+
+ ///
+ /// Message data type.
+ ///
+ public WebPubSubDataType DataType { get; set; } = WebPubSubDataType.Text;
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/SendToGroupAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/SendToGroupAction.cs
new file mode 100644
index 0000000000000..206343a4302bf
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/SendToGroupAction.cs
@@ -0,0 +1,36 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Operation to send message to a group.
+ ///
+ public class SendToGroupAction : WebPubSubAction
+ {
+ ///
+ /// Target group name.
+ ///
+ public string Group { get; set; }
+
+ ///
+ /// Message to send.
+ ///
+ [JsonConverter(typeof(BinaryDataJsonConverter))]
+ public BinaryData Data { get; set; }
+
+ ///
+ /// Message data type.
+ ///
+ public WebPubSubDataType DataType { get; set; } = WebPubSubDataType.Text;
+
+ ///
+ /// ConnectionIds to exclude.
+ ///
+ public IList Excluded { get; set; } = new List();
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/SendToUserAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/SendToUserAction.cs
new file mode 100644
index 0000000000000..0c84f928c9567
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/SendToUserAction.cs
@@ -0,0 +1,30 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Operation to send message to a user.
+ ///
+ public sealed class SendToUserAction : WebPubSubAction
+ {
+ ///
+ /// Target UserId.
+ ///
+ public string UserId { get; set; }
+
+ ///
+ /// Message to send.
+ ///
+ [JsonConverter(typeof(BinaryDataJsonConverter))]
+ public BinaryData Data { get; set; }
+
+ ///
+ /// Message data type.
+ ///
+ public WebPubSubDataType DataType { get; set; } = WebPubSubDataType.Text;
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/WebPubSubAction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/WebPubSubAction.cs
new file mode 100644
index 0000000000000..51637725c37fc
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Output/WebPubSubAction.cs
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Abstract class of operation to invoke service.
+ ///
+ [JsonConverter(typeof(WebPubSubActionJsonConverter))]
+ public abstract class WebPubSubAction
+ {
+ ///
+ /// Readonly name to deserialize to correct WebPubSubAction.
+ ///
+ public string ActionName
+ {
+ get
+ {
+ return GetType().Name.Replace("Action", "");
+ }
+ }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/ConnectEventRequest.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/ConnectEventRequest.cs
new file mode 100644
index 0000000000000..0b77c1d4e330a
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/ConnectEventRequest.cs
@@ -0,0 +1,69 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Connect event request.
+ ///
+ public sealed class ConnectEventRequest : WebPubSubEventRequest
+ {
+ ///
+ /// User Claims.
+ ///
+ [JsonPropertyName("claims")]
+ public IReadOnlyDictionary Claims { get; set; }
+
+ ///
+ /// Request query.
+ ///
+ [JsonPropertyName("query")]
+ public IReadOnlyDictionary Query { get; set; }
+
+ ///
+ /// Request headers.
+ ///
+ [JsonPropertyName("headers")]
+ public IReadOnlyDictionary Headers { get; set; }
+
+ ///
+ /// Supported subprotocols.
+ ///
+ [JsonPropertyName("subprotocols")]
+ public IReadOnlyList Subprotocols { get; set; }
+
+ ///
+ /// Client certificates.
+ ///
+ [JsonPropertyName("clientCertificates")]
+ public IReadOnlyList ClientCertificates { get; set; }
+
+ ///
+ /// Create .
+ ///
+ /// Caller userId for current connection.
+ /// Subprotocol applied to current connection.
+ /// User roles applied to current connection.
+ /// Groups applied to current connection.
+ /// A connect response to return service.
+ public static ConnectEventResponse CreateResponse(string userId, IEnumerable groups, string subprotocol, IEnumerable roles)
+ {
+ return new ConnectEventResponse(userId, groups, subprotocol, roles);
+ }
+
+ ///
+ /// Create .
+ /// Methods works for Function Extensions. And AspNetCore SDK Hub methods can directly throw exception for error cases.
+ ///
+ /// .
+ /// Detail error message.
+ /// A error response to return caller and will drop connection.
+ public static EventErrorResponse CreateErrorResponse(WebPubSubErrorCode code, string message)
+ {
+ return new EventErrorResponse(code, message);
+ }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/ConnectEventResponse.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/ConnectEventResponse.cs
new file mode 100644
index 0000000000000..2dd1c8f07bda6
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/ConnectEventResponse.cs
@@ -0,0 +1,128 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Response for connect event.
+ ///
+ public class ConnectEventResponse : WebPubSubEventResponse
+ {
+ private Dictionary _states;
+
+ internal override WebPubSubStatusCode StatusCode
+ {
+ get
+ {
+ return WebPubSubStatusCode.Success;
+ }
+ set
+ {
+ if (value != WebPubSubStatusCode.Success)
+ {
+ throw new ArgumentException("StatusCode shouldn't be set to errors in a normal connect event.");
+ }
+ }
+ }
+
+ ///
+ /// The connection states.
+ ///
+ [JsonPropertyName("states")]
+ public IReadOnlyDictionary ConnectionStates => _states;
+
+ ///
+ /// UserId.
+ ///
+ [JsonPropertyName("userId")]
+ public string UserId { get; set; }
+
+ ///
+ /// Groups.
+ ///
+ [JsonPropertyName("groups")]
+ public string[] Groups { get; set; }
+
+ ///
+ /// Subprotocol.
+ ///
+ [JsonPropertyName("subprotocol")]
+ public string Subprotocol { get; set; }
+
+ ///
+ /// User roles.
+ ///
+ [JsonPropertyName("roles")]
+ public string[] Roles { get; set; }
+
+ ///
+ /// Create an instance of ConnectEventResponse
+ ///
+ /// User Id of current connection.
+ /// Groups belong of current connection.
+ /// Subprotocol to use for current connection.
+ /// Roles belongs of current connection.
+ public ConnectEventResponse(
+ string userId,
+ IEnumerable groups,
+ string subprotocol,
+ IEnumerable roles)
+ : this()
+ {
+ UserId = userId;
+ Groups = groups?.ToArray();
+ Subprotocol = subprotocol;
+ Roles = roles?.ToArray();
+ }
+
+ ///
+ /// Default constructor for JsonSerialize.
+ ///
+ public ConnectEventResponse() =>
+ SetStatesDictionary(new Dictionary());
+
+ ///
+ /// Set connection states.
+ ///
+ /// State key.
+ /// State value.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void SetState(string key, object value) =>
+ SetState(key, BinaryData.FromObjectAsJson(value));
+
+ ///
+ /// Set connection states.
+ ///
+ /// State key.
+ /// State value.
+ public void SetState(string key, BinaryData value)
+ {
+ // In case user cleared states.
+ if (_states == null)
+ {
+ SetStatesDictionary(new Dictionary());
+ }
+ _states[key] = value;
+ }
+
+ ///
+ /// Clear all states.
+ ///
+ public void ClearStates() => SetStatesDictionary(null);
+
+ ///
+ /// Update the dictionary backing both States and ConnectionStates.
+ ///
+ /// The new dictionary or null.
+ private void SetStatesDictionary(Dictionary states)
+ {
+ _states = states;
+ }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/ConnectedEventRequest.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/ConnectedEventRequest.cs
new file mode 100644
index 0000000000000..e08b9173c6396
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/ConnectedEventRequest.cs
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// ServiceRequest for connected event.
+ ///
+ public sealed class ConnectedEventRequest : WebPubSubEventRequest
+ {
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/DisconnectedEventRequest.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/DisconnectedEventRequest.cs
new file mode 100644
index 0000000000000..df7671c7c4542
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/DisconnectedEventRequest.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Disconnected event request.
+ ///
+ public sealed class DisconnectedEventRequest : WebPubSubEventRequest
+ {
+ ///
+ /// Reason of the disconnect event.
+ ///
+ [JsonPropertyName("reason")]
+ public string Reason { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/EventErrorResponse.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/EventErrorResponse.cs
new file mode 100644
index 0000000000000..8ae070635ad29
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/EventErrorResponse.cs
@@ -0,0 +1,72 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Response for errors.
+ ///
+ public class EventErrorResponse : WebPubSubEventResponse
+ {
+ internal override WebPubSubStatusCode StatusCode { get; set; }
+
+ ///
+ /// Error code. Required field to deserialize ErrorResponse.
+ ///
+ [JsonPropertyName("code")]
+ public WebPubSubErrorCode Code
+ {
+ get
+ {
+ return FromStatusCode(StatusCode);
+ }
+ set
+ {
+ StatusCode = ToStatusCode(value);
+ }
+ }
+
+ ///
+ /// Error messages.
+ ///
+ [JsonPropertyName("errorMessage")]
+ public string ErrorMessage { get; set; }
+
+ ///
+ /// Create an instance of .
+ ///
+ /// Error code indicate error type.
+ /// Detail error message.
+ public EventErrorResponse(WebPubSubErrorCode code, string message = null)
+ {
+ Code = code;
+ ErrorMessage = message;
+ }
+
+ ///
+ /// Default constructor for JsonSerialize.
+ ///
+ public EventErrorResponse()
+ { }
+
+ private static WebPubSubErrorCode FromStatusCode(WebPubSubStatusCode statusCode) =>
+ statusCode switch
+ {
+ WebPubSubStatusCode.Unauthorized => WebPubSubErrorCode.Unauthorized,
+ WebPubSubStatusCode.UserError => WebPubSubErrorCode.UserError,
+ // Turn server error as default in EventErrorResponse.
+ _ => WebPubSubErrorCode.ServerError,
+ };
+
+ private static WebPubSubStatusCode ToStatusCode(WebPubSubErrorCode statusCode) =>
+ statusCode switch
+ {
+ WebPubSubErrorCode.Unauthorized => WebPubSubStatusCode.Unauthorized,
+ WebPubSubErrorCode.UserError => WebPubSubStatusCode.UserError,
+ // return server error as default in EventErrorResponse regarding status code.
+ _ => WebPubSubStatusCode.ServerError,
+ };
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/PreflightRequest.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/PreflightRequest.cs
new file mode 100644
index 0000000000000..8d6587ab33821
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/PreflightRequest.cs
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Preflight OPTIONS request for Abuse Protection validation.
+ ///
+ public sealed class PreflightRequest : WebPubSubEventRequest
+ {
+ ///
+ /// Flag to indicate whether the request is valid.
+ /// The property will be preprocessed with available validation options when parsing the request.
+ ///
+ [JsonPropertyName("isValid")]
+ public bool IsValid { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/UserEventRequest.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/UserEventRequest.cs
new file mode 100644
index 0000000000000..bfdc620dda59e
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/UserEventRequest.cs
@@ -0,0 +1,67 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// User message event request.
+ ///
+ public sealed class UserEventRequest : WebPubSubEventRequest
+ {
+ ///
+ /// Message content.
+ ///
+ [JsonConverter(typeof(BinaryDataJsonConverter))]
+ [JsonPropertyName("data")]
+ public BinaryData Data { get; set; }
+
+ ///
+ /// Message data type.
+ ///
+ [JsonPropertyName("dataType")]
+ public WebPubSubDataType DataType { get; set; }
+
+ ///
+ /// Create .
+ ///
+ /// String message to return caller.
+ /// Message , default as Text.
+ /// A message response to return caller.
+ public static UserEventResponse CreateResponse(string data, WebPubSubDataType dataType = WebPubSubDataType.Text)
+ {
+ return new UserEventResponse(data, dataType);
+ }
+
+ ///
+ /// Create .
+ ///
+ /// BinaryData message to return caller.
+ /// Message .
+ /// A message response to return caller.
+ public static UserEventResponse CreateResponse(BinaryData data, WebPubSubDataType dataType)
+ {
+ return new UserEventResponse(data, dataType);
+ }
+
+ ///
+ /// Create .
+ /// Methods works for Function Extensions. And AspNetCore SDK Hub methods can directly throw exception for error cases.
+ ///
+ /// .
+ /// Detail error message.
+ /// A error response to return caller and will drop connection.
+ public static EventErrorResponse CreateErrorResponse(WebPubSubErrorCode code, string message)
+ {
+ return new EventErrorResponse(code, message);
+ }
+
+ ///
+ /// Constructor for Json serialize.
+ ///
+ public UserEventRequest()
+ { }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/UserEventResponse.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/UserEventResponse.cs
new file mode 100644
index 0000000000000..801a0377dcd78
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/UserEventResponse.cs
@@ -0,0 +1,119 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Runtime.Serialization;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Response for message events.
+ ///
+ [DataContract]
+ public class UserEventResponse : WebPubSubEventResponse
+ {
+ private Dictionary _states;
+
+ internal override WebPubSubStatusCode StatusCode
+ {
+ get
+ {
+ return WebPubSubStatusCode.Success;
+ }
+ set
+ {
+ if (value != WebPubSubStatusCode.Success)
+ {
+ throw new ArgumentException("StatusCode shouldn't be set to errors in a normal user event.");
+ }
+ }
+ }
+
+ ///
+ /// The connection states.
+ ///
+ [JsonPropertyName("states")]
+ public IReadOnlyDictionary ConnectionStates { get; set; }
+
+ ///
+ /// Message.
+ ///
+ [JsonPropertyName("data")]
+ [JsonConverter(typeof(BinaryDataJsonConverter))]
+ public BinaryData Data { get; set; }
+
+ ///
+ /// Message data type.
+ ///
+ [JsonPropertyName("dataType")]
+ public WebPubSubDataType DataType { get; set; }
+
+ ///
+ /// Initialize an instance of MessageResponse.
+ ///
+ /// BinaryData type message.
+ /// Message data type.
+ public UserEventResponse(BinaryData data, WebPubSubDataType dataType)
+ : this()
+ {
+ Data = data;
+ DataType = dataType;
+ }
+
+ ///
+ /// Initialize an instance of MessageResponse.
+ ///
+ /// String type message.
+ /// Message data type. Default set to text.
+ public UserEventResponse(string data, WebPubSubDataType dataType = WebPubSubDataType.Text)
+ : this(BinaryData.FromString(data), dataType)
+ { }
+
+ ///
+ /// Default constructor for JsonSerialize
+ ///
+ public UserEventResponse() =>
+ SetStatesDictionary(new Dictionary());
+
+ ///
+ /// Set connection states.
+ ///
+ /// State key.
+ /// State value.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void SetState(string key, object value) =>
+ SetState(key, BinaryData.FromObjectAsJson(value));
+
+ ///
+ /// Set connection states.
+ ///
+ /// State key.
+ /// State value.
+ public void SetState(string key, BinaryData value)
+ {
+ // In case user cleared states.
+ if (_states == null)
+ {
+ SetStatesDictionary(new Dictionary());
+ }
+ _states[key] = value;
+ }
+
+ ///
+ /// Clear all states.
+ ///
+ public void ClearStates() => SetStatesDictionary(null);
+
+ ///
+ /// Update the dictionary backing both States and ConnectionStates.
+ ///
+ /// The new dictionary or null.
+ private void SetStatesDictionary(Dictionary states)
+ {
+ _states = states;
+ }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/WebPubSubErrorCode.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/WebPubSubErrorCode.cs
new file mode 100644
index 0000000000000..3e5e970e9cebf
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/WebPubSubErrorCode.cs
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Response Error Code.
+ ///
+ [JsonConverter(typeof(JsonStringEnumConverter))]
+ public enum WebPubSubErrorCode
+ {
+ ///
+ /// Unauthorized error.
+ ///
+ Unauthorized,
+ ///
+ /// User error.
+ ///
+ UserError,
+ ///
+ /// Server error.
+ ///
+ ServerError
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/WebPubSubEventRequest.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/WebPubSubEventRequest.cs
new file mode 100644
index 0000000000000..0d5ef4f5793d6
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/WebPubSubEventRequest.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Web PubSub service request.
+ ///
+ public abstract class WebPubSubEventRequest
+ {
+ ///
+ /// Connection context contains connection metadata following CloudEvents.
+ ///
+ [JsonPropertyName("connectionContext")]
+ public WebPubSubConnectionContext ConnectionContext { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/WebPubSubEventResponse.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/WebPubSubEventResponse.cs
new file mode 100644
index 0000000000000..bcdcab183987f
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/Trigger/WebPubSubEventResponse.cs
@@ -0,0 +1,17 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// A general type of Web PubSub service response to send to service.
+ ///
+ public abstract class WebPubSubEventResponse
+ {
+ ///
+ /// Reserved code for json deserilize to correct derived response.
+ /// Default to .
+ ///
+ internal virtual WebPubSubStatusCode StatusCode { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubClientCertificate.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubClientCertificate.cs
new file mode 100644
index 0000000000000..962b879bdad11
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubClientCertificate.cs
@@ -0,0 +1,18 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Client certificate info.
+ ///
+ public sealed class WebPubSubClientCertificate
+ {
+ ///
+ /// Certificate thumbprint.
+ ///
+ public string Thumbprint { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubConnectionContext.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubConnectionContext.cs
new file mode 100644
index 0000000000000..9d6883d5c9b6c
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubConnectionContext.cs
@@ -0,0 +1,71 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+using Microsoft.Azure.WebPubSub.Common;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Request context from headers following CloudEvents.
+ ///
+ public sealed class WebPubSubConnectionContext
+ {
+ ///
+ /// The type of the message.
+ ///
+ [JsonPropertyName("eventType")]
+ public WebPubSubEventType EventType { get; set; }
+
+ ///
+ /// The event name of the message.
+ ///
+ [JsonPropertyName("eventName")]
+ public string EventName { get; set; }
+
+ ///
+ /// The hub which the connection belongs to.
+ ///
+ [JsonPropertyName("hub")]
+ public string Hub { get; set; }
+
+ ///
+ /// The connection-id of the client.
+ ///
+ [JsonPropertyName("connectionId")]
+ public string ConnectionId { get; set; }
+
+ ///
+ /// The user identity of the client.
+ ///
+ [JsonPropertyName("userId")]
+ public string UserId { get; set; }
+
+ ///
+ /// The signature for validation.
+ ///
+ [JsonPropertyName("signature")]
+ public string Signature { get; set; }
+
+ ///
+ /// Upstream origin.
+ ///
+ [JsonPropertyName("origin")]
+ public string Origin { get; set; }
+
+ ///
+ /// The connection states.
+ ///
+ [JsonConverter(typeof(ConnectionStatesConverter))]
+ [JsonPropertyName("states")]
+ public IReadOnlyDictionary ConnectionStates { get; set; }
+
+ ///
+ /// The headers of request.
+ ///
+ [JsonPropertyName("headers")]
+ public IReadOnlyDictionary Headers { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubDataType.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubDataType.cs
new file mode 100644
index 0000000000000..608812033fbf4
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubDataType.cs
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Message data type.
+ ///
+ [JsonConverter(typeof(JsonStringEnumConverter))]
+ public enum WebPubSubDataType
+ {
+ ///
+ /// binary of content type application/octet-stream.
+ ///
+ Binary,
+ ///
+ /// json of content type application/json.
+ ///
+ Json,
+ ///
+ /// text of content type text/plain.
+ ///
+ Text
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubEventType.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubEventType.cs
new file mode 100644
index 0000000000000..64d29ae62afa9
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubEventType.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Event type.
+ ///
+ [JsonConverter(typeof(JsonStringEnumConverter))]
+ public enum WebPubSubEventType
+ {
+ ///
+ /// system event, including connect, connected, disconnected.
+ ///
+ System,
+ ///
+ /// user event.
+ ///
+ User
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubPermission.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubPermission.cs
new file mode 100644
index 0000000000000..ec598a48499c1
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubPermission.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Web PubSub permissions.
+ ///
+ [JsonConverter(typeof(JsonStringEnumConverter))]
+ public enum WebPubSubPermission
+ {
+ ///
+ /// Permission to send messages to a group.
+ ///
+ SendToGroup = 1,
+
+ ///
+ /// Permission to join and leave a group.
+ ///
+ JoinLeaveGroup = 2
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubSimpleResponse.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubSimpleResponse.cs
new file mode 100644
index 0000000000000..2f4bb82c45d22
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubSimpleResponse.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Web PubSub service auto generate simple response for input binding.
+ ///
+ public sealed class WebPubSubSimpleResponse
+ {
+ ///
+ /// Response body including error message.
+ ///
+ [JsonPropertyName("body")]
+ public string Body { get; set; }
+
+ ///
+ /// Response status code
+ ///
+ [JsonPropertyName("status")]
+ public int Status { get; set; }
+
+ ///
+ /// Response headers.
+ ///
+ [JsonPropertyName("headers")]
+ public Dictionary Headers { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubStatusCode.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubStatusCode.cs
new file mode 100644
index 0000000000000..e9dfba0de6116
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Models/WebPubSubStatusCode.cs
@@ -0,0 +1,33 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// The general enum to represent response status.
+ /// DO set to Success for backward capability.
+ /// Has mapping relationship to .
+ ///
+ [JsonConverter(typeof(JsonStringEnumConverter))]
+ internal enum WebPubSubStatusCode
+ {
+ ///
+ /// Default success.
+ ///
+ Success,
+ ///
+ /// Unauthorized error.
+ ///
+ Unauthorized,
+ ///
+ /// User error.
+ ///
+ UserError,
+ ///
+ /// Server error.
+ ///
+ ServerError
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Properties/AssemblyInfo.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000000..1b174ec93fce3
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/Properties/AssemblyInfo.cs
@@ -0,0 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.Azure.Functions.Worker.Extensions.Abstractions;
+
+[assembly: ExtensionInformation("Microsoft.Azure.WebJobs.Extensions.WebPubSub", "1.5.0")]
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/WebPubSubConnectionInputAttribute.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/WebPubSubConnectionInputAttribute.cs
new file mode 100644
index 0000000000000..989befc87568d
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/WebPubSubConnectionInputAttribute.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.Azure.Functions.Worker.Extensions.Abstractions;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Provides for a Web PubSub client to connect to Web PubSub Service.
+ ///
+ public sealed class WebPubSubConnectionInputAttribute : InputBindingAttribute
+ {
+ ///
+ /// Target Web PubSub service connection string.
+ ///
+ public string Connection { get; set; }
+
+ ///
+ /// Target hub name.
+ ///
+ public string Hub { get; set; }
+
+ ///
+ /// Client userId.
+ ///
+ public string UserId { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/WebPubSubContextInputAttribute.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/WebPubSubContextInputAttribute.cs
new file mode 100644
index 0000000000000..cf1315be87513
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/WebPubSubContextInputAttribute.cs
@@ -0,0 +1,34 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.Azure.Functions.Worker.Extensions.Abstractions;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Provides from a Web PubSub client event with HttpTrigger.
+ ///
+ public sealed class WebPubSubContextInputAttribute : InputBindingAttribute
+ {
+ ///
+ /// Allowed Web PubSub service connections used for Abuse Protection and signature checks.
+ ///
+ public string[] Connections { get; set; }
+
+ ///
+ /// Constructor to build the attribute.
+ ///
+ /// Allowed service connections.
+ public WebPubSubContextInputAttribute(params string[] connections)
+ {
+ Connections = connections;
+ }
+
+ ///
+ /// Constructor to build the attribute.
+ ///
+ public WebPubSubContextInputAttribute()
+ {
+ }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/WebPubSubOutputAttribute.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/WebPubSubOutputAttribute.cs
new file mode 100644
index 0000000000000..00be1424e0fe5
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/WebPubSubOutputAttribute.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.Azure.Functions.Worker.Extensions.Abstractions;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Attribute used to bind a parameter to an Azure Web PubSub. The attribute supports to invoke
+ /// multiple kinds of operations to service. For details, .
+ ///
+ public sealed class WebPubSubOutputAttribute : OutputBindingAttribute
+ {
+ ///
+ /// The connection of target Web PubSub service.
+ ///
+ public string Connection { get; set; }
+
+ ///
+ /// Target hub.
+ ///
+ public string Hub { get; set; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/WebPubSubTriggerAttribute.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/WebPubSubTriggerAttribute.cs
new file mode 100644
index 0000000000000..dfe2de9c16406
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/src/WebPubSubTriggerAttribute.cs
@@ -0,0 +1,80 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.Azure.Functions.Worker.Extensions.Abstractions;
+
+namespace Microsoft.Azure.Functions.Worker
+{
+ ///
+ /// Binds to to mark a function that should be triggered by messages sent from Web PubSub clients.
+ ///
+ public sealed class WebPubSubTriggerAttribute : TriggerBindingAttribute
+ {
+ ///
+ /// Attribute used to bind a parameter to an Azure Web PubSub, when an request is from Azure Web PubSub service.
+ ///
+ /// Target hub name of the request.
+ /// Target event name of the request.
+ /// Target event type of the request.
+ /// Connection strings of allowed upstreams for signature checks.
+ public WebPubSubTriggerAttribute(string hub, WebPubSubEventType eventType, string eventName, params string[] connections)
+ {
+ Hub = hub;
+ EventName = eventName;
+ EventType = eventType;
+ Connections = connections;
+ }
+
+ ///
+ /// Attribute used to bind a parameter to an Azure Web PubSub, when an request is from Azure Web PubSub service.
+ ///
+ /// Target hub name of the request.
+ /// Target event name of the request.
+ /// Target event type of the request.
+ public WebPubSubTriggerAttribute(string hub, WebPubSubEventType eventType, string eventName)
+ : this(hub, eventType, eventName, null)
+ {
+ }
+
+ ///
+ /// Attribute used to bind a parameter to an Azure Web PubSub, when an request is from Azure Web PubSub service.
+ ///
+ /// Target event name of the request.
+ /// Target event type of the request.
+ /// Connection strings of allowed upstreams for signature checks.
+ public WebPubSubTriggerAttribute(WebPubSubEventType eventType, string eventName, params string[] connections)
+ : this("", eventType, eventName, connections)
+ {
+ }
+
+ ///
+ /// Attribute used to bind a parameter to an Azure Web PubSub, when an request is from Azure Web PubSub service.
+ ///
+ /// Target event name of the request.
+ /// Target event type of the request.
+ public WebPubSubTriggerAttribute(WebPubSubEventType eventType, string eventName)
+ : this("", eventType, eventName)
+ {
+ }
+
+ ///
+ /// The hub of request.
+ ///
+ public string Hub { get; }
+
+ ///
+ /// The event of the request.
+ ///
+ public string EventName { get; }
+
+ ///
+ /// The event type, allowed value is system or user.
+ ///
+ public WebPubSubEventType EventType { get; }
+
+ ///
+ /// Allowed service upstream ConnectionString for Signature checks.
+ ///
+ public string[] Connections { get; }
+ }
+}
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/tests/samples/WebPubSubConnectionInputFunction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/tests/samples/WebPubSubConnectionInputFunction.cs
new file mode 100644
index 0000000000000..7aa26fe6832c4
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/tests/samples/WebPubSubConnectionInputFunction.cs
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Net;
+using Microsoft.Azure.Functions.Worker;
+using Microsoft.Azure.Functions.Worker.Http;
+
+namespace SampleApp;
+
+public static class WebPubSubConnectionInputFunction
+{
+ #region Snippet:WebPubSubConnectionInputFunction
+ [Function("Negotiate")]
+ public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequestData req,
+ [WebPubSubConnectionInput(Hub = "", Connection = "")] WebPubSubConnection connectionInfo)
+ {
+ var response = req.CreateResponse(HttpStatusCode.OK);
+ response.WriteAsJsonAsync(connectionInfo);
+ return response;
+ }
+ #endregion
+}
\ No newline at end of file
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/tests/samples/WebPubSubContextInputFunction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/tests/samples/WebPubSubContextInputFunction.cs
new file mode 100644
index 0000000000000..673f2adc93adc
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/tests/samples/WebPubSubContextInputFunction.cs
@@ -0,0 +1,53 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Net;
+using Microsoft.Azure.Functions.Worker;
+using Microsoft.Azure.Functions.Worker.Http;
+
+namespace SampleApp;
+
+internal class WebPubSubContextInputFunction
+{
+ [Function("connect")]
+ public static HttpResponseData Run(
+ [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req,
+ [WebPubSubContextInput] WebPubSubContext wpsReq)
+ {
+ var response = req.CreateResponse();
+ if (wpsReq.Request is PreflightRequest || wpsReq.ErrorMessage != null)
+ {
+ return BuildHttpResponseData(req, wpsReq.Response);
+ }
+
+ var request = wpsReq.Request as ConnectEventRequest;
+ // assign the properties if needed.
+ response.WriteAsJsonAsync(request.CreateResponse(request.ConnectionContext.UserId, null, null, null));
+ return response;
+ }
+
+ #region Snippet:WebPubSubContextInputFunction
+ // validate method when upstream set as http:///api/{event}
+ [Function("validate")]
+ public static HttpResponseData Validate(
+ [HttpTrigger(AuthorizationLevel.Anonymous, "options")] HttpRequestData req,
+ [WebPubSubContextInput] WebPubSubContext wpsReq)
+ {
+ return BuildHttpResponseData(req, wpsReq.Response);
+ }
+
+ // Respond AbuseProtection to put header correctly.
+ private static HttpResponseData BuildHttpResponseData(HttpRequestData request, SimpleResponse wpsResponse)
+ {
+ var response = request.CreateResponse();
+ response.StatusCode = (HttpStatusCode)wpsResponse.Status;
+ response.Body = response.Body;
+ foreach (var header in wpsResponse.Headers)
+ {
+ response.Headers.Add(header.Key, header.Value);
+ }
+ return response;
+ }
+ #endregion
+}
\ No newline at end of file
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/tests/samples/WebPubSubOutputFunction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/tests/samples/WebPubSubOutputFunction.cs
new file mode 100644
index 0000000000000..59053fc5a3343
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/tests/samples/WebPubSubOutputFunction.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using Microsoft.Azure.Functions.Worker;
+using Microsoft.Azure.Functions.Worker.Http;
+
+namespace SampleApp;
+
+public static class WebPubSubOutputFunction
+{
+ #region Snippet:WebPubSubOutputFunction
+ [Function("Notification")]
+ [WebPubSubOutput(Hub = "", Connection = "")]
+ public static WebPubSubAction Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
+ {
+ return new SendToAllAction
+ {
+ Data = BinaryData.FromString($"Hello SendToAll."),
+ DataType = WebPubSubDataType.Text
+ };
+ }
+ #endregion
+
+ #region Snippet:WebPubSubOutputFunction_Multiple
+ // multiple output
+ [Function("Notification1")]
+ [WebPubSubOutput(Hub = "", Connection = "")]
+ public static WebPubSubAction[] MultipleActions([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
+ {
+ return new WebPubSubAction[]
+ {
+ new SendToAllAction
+ {
+ Data = BinaryData.FromString($"Hello SendToAll."),
+ DataType = WebPubSubDataType.Text
+ },
+ new AddUserToGroupAction
+ {
+ UserId = "user A",
+ Group = "group A"
+ }
+ };
+ }
+ #endregion
+}
\ No newline at end of file
diff --git a/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/tests/samples/WebPubSubTriggerFunction.cs b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/tests/samples/WebPubSubTriggerFunction.cs
new file mode 100644
index 0000000000000..1a3a7bed7165d
--- /dev/null
+++ b/sdk/webpubsub/Microsoft.Azure.Functions.Worker.Extensions.WebPubSub/tests/samples/WebPubSubTriggerFunction.cs
@@ -0,0 +1,18 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.Azure.Functions.Worker;
+
+namespace SampleApp;
+
+public class WebPubSubTriggerFunction
+{
+ #region Snippet:WebPubSubTriggerUserEventFunction
+ [Function("Broadcast")]
+ public static UserEventResponse Run(
+ [WebPubSubTrigger("", WebPubSubEventType.User, "message")] UserEventRequest request)
+ {
+ return new UserEventResponse("[SYSTEM ACK] Received.");
+ }
+ #endregion
+}
\ No newline at end of file
diff --git a/sdk/webpubsub/Microsoft.Azure.WebJobs.Extensions.WebPubSub/CHANGELOG.md b/sdk/webpubsub/Microsoft.Azure.WebJobs.Extensions.WebPubSub/CHANGELOG.md
index deb03e40e7108..526448a4cf5be 100644
--- a/sdk/webpubsub/Microsoft.Azure.WebJobs.Extensions.WebPubSub/CHANGELOG.md
+++ b/sdk/webpubsub/Microsoft.Azure.WebJobs.Extensions.WebPubSub/CHANGELOG.md
@@ -80,4 +80,4 @@
- Fixed exceptions when the library is used in Static Web Apps.
## 1.0.0-beta.1 (2021-04-26)
-- The initial beta release of Microsoft.Azure.WebJobs.Extensions.WebPubSub 1.0.0
+- The initial beta release of Microsoft.Azure.WebJobs.Extensions.WebPubSub 1.0.0
\ No newline at end of file
diff --git a/sdk/webpubsub/ci.yml b/sdk/webpubsub/ci.yml
index 70119ab18f0d8..aa35bf91c92f0 100644
--- a/sdk/webpubsub/ci.yml
+++ b/sdk/webpubsub/ci.yml
@@ -41,3 +41,5 @@ extends:
safeName: MicrosoftAzureWebPubSubAspNetCore
- name: Microsoft.Azure.WebPubSub.Common
safeName: MicrosoftAzureWebPubSubCommon
+ - name: Microsoft.Azure.Functions.Worker.Extensions.WebPubSub
+ safeName: MicrosoftAzureFunctionsWorkerExtensionsWebPubSub