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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions extensions/Worker.Extensions.Rpc/release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@
- My change description (#PR/#issue)
-->

### Microsoft.Azure.Functions.Worker.Extensions.Rpc 1.0.0-preview1
### Microsoft.Azure.Functions.Worker.Extensions.Rpc 1.0.0-preview2

- Add `IHttpClientBuilder.ConfigureForFunctionsHostGrpc` extension method. (#1616)
- Used along with `IServiceCollection.AddGrpcClient<TClient>()` to configure for Functions host communication.
- **NOTE**: when using Grpc.Net.ClientFactory <= 2.54.0-pre1 use `IServiceCollection.AddGrpcClient<TClient>(_ => { })`
- See [grpc/grpc-dotnet/issues/2158](https://github.com/grpc/grpc-dotnet/issues/2158)
- Available in `>=net6.0` only.
- Add `FunctionsGrpcOptions`, which can be used to get a built `CallInvoker` for gRPC communication with the functions host. (#1637)
- Available in all TFMs.
- Replace auto-registration via `WorkerRpcStartup` with manual call `RpcServiceCollectionExtensions.AddWorkerRpc`
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

#if !NETSTANDARD
using System;
using Grpc.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;

namespace Microsoft.Azure.Functions.Worker.Extensions.Rpc
{
/// <summary>
/// <see cref="IServiceCollection" /> extensions for RPC.
/// </summary>
public static partial class RpcServiceCollectionExtensions
{
private static void ConfigureCallInvoker(IServiceCollection services)
{
// Instead of building the GrpcChannel/CallInvoker ourselves, we use Grpc.Net.ClientFactory to
// construct and configure the CallInvoker for us, then we attach that to our options.
services.AddGrpcClient<CallInvokerExtractor>(_ => { })
.ConfigureForFunctionsHostGrpc();
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<FunctionsGrpcOptions>, ConfigureOptions>());
}

// Used as a roundabout way of getting the configured CallInvoker from Grpc.Net.ClientFactory.
private class CallInvokerExtractor
{
public CallInvokerExtractor(CallInvoker callInvoker)
{
CallInvoker = callInvoker ?? throw new ArgumentNullException(nameof(callInvoker));
}

public CallInvoker CallInvoker { get; }
}

private class ConfigureOptions : IConfigureOptions<FunctionsGrpcOptions>
{
private readonly CallInvokerExtractor _extractor;

public ConfigureOptions(CallInvokerExtractor extractor)
{
_extractor = extractor;
}

public void Configure(FunctionsGrpcOptions options)
{
options.CallInvoker = _extractor.CallInvoker;
}
}
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

#if NETSTANDARD
using System;
using Grpc.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;

namespace Microsoft.Azure.Functions.Worker.Extensions.Rpc
{
/// <summary>
/// <see cref="IServiceCollection" /> extensions for RPC.
/// </summary>
public static partial class RpcServiceCollectionExtensions
{
private static void ConfigureCallInvoker(IServiceCollection services)
{
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<FunctionsGrpcOptions>, ConfigureOptions>());
}

private class ConfigureOptions : IConfigureOptions<FunctionsGrpcOptions>
{
private readonly IConfiguration _configuration;

public ConfigureOptions(IConfiguration configuration)
{
_configuration = configuration;
}

public void Configure(FunctionsGrpcOptions options)
{
Uri address = _configuration.GetFunctionsHostGrpcUri();
Channel c = new Channel(address.Host, address.Port, ChannelCredentials.Insecure);
options.CallInvoker = c.CreateCallInvoker();
}
}
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.Azure.Functions.Worker.Extensions.Rpc
{
/// <summary>
/// <see cref="IServiceCollection" /> extensions for RPC.
/// </summary>
public static partial class RpcServiceCollectionExtensions
{
/// <summary>
/// Adds requires types for Functions host and worker RPC communication. Extensions that want to use RPC are
/// expected to call this before configuring their RPC clients.
/// </summary>
/// <param name="services">The service collection.</param>
/// <returns>The original service collection for call chaining.</returns>
public static IServiceCollection AddWorkerRpc(this IServiceCollection services)
{
if (services is null)
{
throw new ArgumentNullException(nameof(services));
}

services.AddOptions<FunctionsGrpcOptions>()
.Validate(options => options.CallInvoker is not null, "gRPC CallInvoker must not be null.");
ConfigureCallInvoker(services);
return services;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<RootNamespace>Microsoft.Azure.Functions.Worker.Extensions.Rpc</RootNamespace>
<Description>Contains types to facilitate RPC communication between a worker extension and the functions host.</Description>
<VersionPrefix>1.0.0</VersionPrefix>
<VersionSuffix>-preview1</VersionSuffix>
<VersionSuffix>-preview2</VersionSuffix>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>

Expand Down
76 changes: 0 additions & 76 deletions extensions/Worker.Extensions.Rpc/src/WorkerRpcStartup.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;

namespace Microsoft.Azure.Functions.Worker.Extensions.Rpc.Tests
{
public class WorkerRpcStartupTests
public class RpcServiceCollectionExtensionsTests
{
[Fact]
public void Configure_AddsFunctionsGrpcOptions()
Expand All @@ -24,11 +23,7 @@ public void Configure_AddsFunctionsGrpcOptions()

ServiceCollection services = new();
services.AddSingleton((IConfiguration)configBuilder.Build());
IFunctionsWorkerApplicationBuilder builder = Mock.Of<IFunctionsWorkerApplicationBuilder>(
m => m.Services == services);

WorkerRpcStartup startup = new();
startup.Configure(builder);
services.AddWorkerRpc();

IServiceProvider sp = services.BuildServiceProvider();
IOptions<FunctionsGrpcOptions> options = sp.GetService<IOptions<FunctionsGrpcOptions>>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFrameworks>net48;net7.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<ImplicitUsings>true</ImplicitUsings>
Expand Down