diff --git a/tests/IceRpc.Protobuf.Tests/ServiceProviderExtensionsTests.cs b/tests/IceRpc.Protobuf.Tests/ServiceProviderExtensionsTests.cs new file mode 100644 index 000000000..582c85e95 --- /dev/null +++ b/tests/IceRpc.Protobuf.Tests/ServiceProviderExtensionsTests.cs @@ -0,0 +1,38 @@ +// Copyright (c) ZeroC, Inc. + +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; + +namespace IceRpc.Protobuf.Tests; + +[Parallelizable(scope: ParallelScope.All)] +public partial class ServiceProviderExtensionsTests +{ + [Test] + public void Create_protobuf_client_with_no_params() + { + var serviceCollection = + new ServiceCollection() + .AddSingleton(InvalidInvoker.Instance) + .AddSingleton(provider => provider.CreateProtobufClient()); + + var provider = serviceCollection.BuildServiceProvider(validateScopes: true); + + var client = (IProtobufClient?)provider.GetService(); + Assert.That(client, Is.Not.Null); + Assert.That(client.Invoker, Is.EqualTo(InvalidInvoker.Instance)); + Assert.That(client.ServiceAddress.Path, Is.EqualTo(MyOperationsClient.DefaultServicePath)); + Assert.That(client.EncodeOptions, Is.Null); + } + + [Test] + public void Create_protobuf_client_without_invoker_fails() + { + var serviceCollection = + new ServiceCollection() + .AddSingleton(provider => provider.CreateProtobufClient()); + + var provider = serviceCollection.BuildServiceProvider(validateScopes: true); + Assert.That(() => provider.GetService(), Throws.InvalidOperationException); + } +} diff --git a/tests/IceRpc.Slice.Tests/ServiceProviderExtensionsTests.cs b/tests/IceRpc.Slice.Tests/ServiceProviderExtensionsTests.cs new file mode 100644 index 000000000..977076687 --- /dev/null +++ b/tests/IceRpc.Slice.Tests/ServiceProviderExtensionsTests.cs @@ -0,0 +1,38 @@ +// Copyright (c) ZeroC, Inc. + +using Microsoft.Extensions.DependencyInjection; +using NUnit.Framework; + +namespace IceRpc.Slice.Tests; + +[Parallelizable(scope: ParallelScope.All)] +public partial class ServiceProviderExtensionsTests +{ + [Test] + public void Create_slice_proxy_with_no_params() + { + var serviceCollection = + new ServiceCollection() + .AddSingleton(InvalidInvoker.Instance) + .AddSingleton(provider => provider.CreateSliceProxy()); + + var provider = serviceCollection.BuildServiceProvider(validateScopes: true); + + var proxy = (IProxy?)provider.GetService(); + Assert.That(proxy, Is.Not.Null); + Assert.That(proxy.Invoker, Is.EqualTo(InvalidInvoker.Instance)); + Assert.That(proxy.ServiceAddress.Path, Is.EqualTo(MyOperationsAProxy.DefaultServicePath)); + Assert.That(proxy.EncodeOptions, Is.Null); + } + + [Test] + public void Create_slice_proxy_without_invoker_fails() + { + var serviceCollection = + new ServiceCollection() + .AddSingleton(provider => provider.CreateSliceProxy()); + + var provider = serviceCollection.BuildServiceProvider(validateScopes: true); + Assert.That(() => provider.GetService(), Throws.InvalidOperationException); + } +} diff --git a/tools/IceRpc.ProtocGen/ClientGenerator.cs b/tools/IceRpc.ProtocGen/ClientGenerator.cs index f1d2062ed..01e379591 100644 --- a/tools/IceRpc.ProtocGen/ClientGenerator.cs +++ b/tools/IceRpc.ProtocGen/ClientGenerator.cs @@ -118,10 +118,10 @@ internal static string GenerateImplementation(ServiceDescriptor service) public ProtobufEncodeOptions? EncodeOptions {{ get; init; }} /// Gets or initializes the invoker of this client. - public IceRpc.IInvoker Invoker {{ get; init; }} + public required IceRpc.IInvoker Invoker {{ get; init; }} /// Gets or initializes the address of the remote service. - public IceRpc.ServiceAddress ServiceAddress {{ get; init; }} + public IceRpc.ServiceAddress ServiceAddress {{ get; init; }} = _defaultServiceAddress; private static IceRpc.ServiceAddress _defaultServiceAddress = new(IceRpc.Protocol.IceRpc) {{ Path = DefaultServicePath }}; @@ -131,6 +131,7 @@ internal static string GenerateImplementation(ServiceDescriptor service) /// The service address. is equivalent to an icerpc service /// address with path . /// The encode options, used to customize the encoding of request payloads. + [System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute] public {clientImplementationName}( IceRpc.IInvoker invoker, IceRpc.ServiceAddress? serviceAddress = null, @@ -145,6 +146,7 @@ internal static string GenerateImplementation(ServiceDescriptor service) /// The invocation pipeline of the proxy. /// A URI that represents a service address. /// The encode options, used to customize the encoding of request payloads. + [System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute] public {clientImplementationName}( IceRpc.IInvoker invoker, System.Uri serviceAddressUri, @@ -153,6 +155,11 @@ internal static string GenerateImplementation(ServiceDescriptor service) {{ }} + /// Constructs a client with an icerpc service address with path . + public {clientImplementationName}() + {{ + }} + {methods.Trim()} }}"; return clientImplementation;