/// <summary>
        /// Configures the <see cref="IServiceModelProxyBuilder"/> to use the given <see cref="Binding"/> when creating the proxy.
        /// </summary>
        /// <param name="builder">The <see cref="IServiceModelProxyBuilder"/>.</param>
        /// <param name="binding">The <see cref="Binding"/> used to connect to the remote service.</param>
        /// <returns>An instance of <see cref="IServiceModelProxyBuilder"/>.</returns>
        public static IServiceModelProxyBuilder SetBinding(this IServiceModelProxyBuilder builder, Binding binding)
        {
            _ = builder ?? throw new ArgumentNullException(nameof(builder));

            _ = binding ?? throw new ArgumentNullException(nameof(binding));

            return(Configure(builder, options => options.BindingFactory = _ => binding));
        }
        /// <summary>
        /// Configures the <see cref="IServiceModelProxyBuilder"/> to use the given <see cref="Uri"/> when creating the proxy.
        /// </summary>
        /// <param name="builder">The <see cref="IServiceModelProxyBuilder"/>.</param>
        /// <param name="endpoint">The <see cref="Uri"/> to connect to.</param>
        /// <returns>An instance of <see cref="IServiceModelProxyBuilder"/>.</returns>
        public static IServiceModelProxyBuilder SetEndpointAddress(this IServiceModelProxyBuilder builder, Uri endpoint)
        {
            _ = builder ?? throw new ArgumentNullException(nameof(builder));

            _ = endpoint ?? throw new ArgumentNullException(nameof(endpoint));

            return(Configure(builder, options => options.EndpointAddressFactory = _ => new EndpointAddress(endpoint.ToString())));
        }
        /// <summary>
        /// Configures the <see cref="IServiceModelProxyBuilder" /> to customize the <see cref="ServiceEndpoint" /> when creating the proxy.
        /// </summary>
        /// <param name="builder">The <see cref="IServiceModelProxyBuilder"/>.</param>
        /// <param name="configuration">A delegate to be used to configure the <see cref="ServiceEndpoint"/>.</param>
        /// <returns>An instance of <see cref="IServiceModelProxyBuilder"/>.</returns>
        public static IServiceModelProxyBuilder ConfigureServiceEndpoint(this IServiceModelProxyBuilder builder, Action <IServiceProvider, ServiceEndpoint> configuration)
        {
            _ = builder ?? throw new ArgumentNullException(nameof(builder));

            _ = configuration ?? throw new ArgumentNullException(nameof(configuration));

            return(Configure(builder, options => options.EndpointConfigurations.Add(configuration)));
        }
        /// <summary>
        /// Configures the <see cref="IServiceModelProxyBuilder" /> by customizing the <see cref="ServiceModelProxyOptions"/> used when creating the proxy.
        /// </summary>
        /// <param name="builder">The <see cref="IServiceModelProxyBuilder"/>.</param>
        /// <param name="configuration">A delegate to be used to configure the <see cref="ServiceModelProxyOptions"/>.</param>
        /// <returns>An instance of <see cref="IServiceModelProxyBuilder"/>.</returns>
        public static IServiceModelProxyBuilder Configure(this IServiceModelProxyBuilder builder, Action <ServiceModelProxyOptions> configuration)
        {
            _ = builder ?? throw new ArgumentNullException(nameof(builder));

            _ = configuration ?? throw new ArgumentNullException(nameof(configuration));

            builder.Services.Configure(builder.Name, configuration);

            return(builder);
        }
        public void SetBindings_configures_options_to_return_given_binding(IServiceModelProxyBuilder builder, Binding binding)
        {
            builder.SetBinding(binding);

            var sp = builder.Services.BuildServiceProvider();

            var options = sp.GetRequiredService <IOptionsMonitor <ServiceModelProxyOptions> >().Get(builder.Name);

            var actual = options.BindingFactory(sp);

            Assert.That(actual, Is.SameAs(binding));
        }
        /// <summary>
        /// Configures the <see cref="IServiceModelProxyBuilder"/> to attach an instance of the specified <see cref="IClientMessageInspector"/> to the proxy.
        /// </summary>
        /// <typeparam name="TInspector">A class implementing the <see cref="IClientMessageInspector"/> interface.</typeparam>
        /// <param name="builder">The <see cref="IServiceModelProxyBuilder"/>.</param>
        /// <returns>An instance of <see cref="IServiceModelProxyBuilder"/>.</returns>
        public static IServiceModelProxyBuilder AddClientMessageInspector <TInspector>(this IServiceModelProxyBuilder builder)
            where TInspector : class, IClientMessageInspector
        {
            _ = builder ?? throw new ArgumentNullException(nameof(builder));

            builder.Services.AddSingleton <IClientMessageInspector, TInspector>();

            builder.ConfigureServiceEndpoint((services, endpoint) => endpoint.EndpointBehaviors.Add(services.GetRequiredService <ClientMessageInspectorEndpointBehavior>()));

            builder.Services.TryAddSingleton <ClientMessageInspectorEndpointBehavior>();

            return(builder);
        }
        /// <summary>
        /// Configures the <see cref="IServiceModelProxyBuilder"/> to use a wrapper of the specified type.
        /// </summary>
        /// <typeparam name="TClient">The interface to be used to get an instance of the proxy wrapper.</typeparam>
        /// <typeparam name="TContract">The contract of the WCF service to build a proxy for.</typeparam>
        /// <typeparam name="TProxy">The type of the proxy to use to connect to the service.</typeparam>
        /// <typeparam name="TWrapper">The concrete type to be used for the wrapper. This type must inherit from <see cref="ClientBaseProxyWrapper{TContract,TProxy}"/> and implement <typeparamref name="TClient"/>.</typeparam>
        /// <param name="builder">The <see cref="IServiceModelProxyBuilder{TContract,TProxy}"/>.</param>
        /// <returns>An instance of <see cref="IServiceModelProxyBuilder{TContract,TProxy}"/>.</returns>
        /// <remarks>
        /// <para>
        /// This overloads is best used when working with clients generated by Visual Studio or dotnet-svcutil.
        /// </para>
        /// </remarks>
        public static IServiceModelProxyBuilder <TContract, TProxy> AddTypedWrapper <TClient, TContract, TProxy, TWrapper>(this IServiceModelProxyBuilder <TContract, TProxy> builder)
            where TContract : class
            where TClient : class, IProxyWrapper <TContract>
            where TProxy : ClientBase <TContract>, TContract
            where TWrapper : ClientBaseProxyWrapper <TContract, TProxy>, TClient
        {
            _ = builder ?? throw new ArgumentNullException(nameof(builder));

            builder.Services.AddTransient <TClient, TWrapper>();

            return(builder);
        }
        public void SetEndpointAddress_configures_options_to_return_endpointAddress_matching_given_uri(IServiceModelProxyBuilder builder, Uri uri)
        {
            builder.SetEndpointAddress(uri);

            var sp = builder.Services.BuildServiceProvider();

            var options = sp.GetRequiredService <IOptionsMonitor <ServiceModelProxyOptions> >().Get(builder.Name);

            var actual = options.EndpointAddressFactory(sp);

            Assert.That(actual.Uri, Is.EqualTo(uri));
        }