예제 #1
0
        static void ConfigureWcfCountCommand(CommandLineApplication wcfCommand)
        {
            wcfCommand.RelayCommand("count", (countCommand) =>
            {
                countCommand.Description = "Get WCF Relay Count";

                var connectionStringArgument = countCommand.Argument("connectionString", "Relay ConnectionString");

                countCommand.OnExecute(async() =>
                {
                    string connectionString = ConnectionStringUtility.ResolveConnectionString(connectionStringArgument);
                    if (string.IsNullOrEmpty(connectionString))
                    {
                        TraceMissingArgument(connectionStringArgument.Name);
                        countCommand.ShowHelp();
                        return(1);
                    }

                    var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
                    Uri namespaceUri     = namespaceManager.Address;
                    string namespaceHost = namespaceUri.Host;
                    var tokenProvider    = namespaceManager.Settings.TokenProvider;

                    RelayTraceSource.TraceVerbose($"Getting WcfRelay count for '{namespaceUri}");

                    int count = await NamespaceUtility.GetEntityCountAsync(namespaceUri, tokenProvider, "Relays");
                    RelayTraceSource.TraceInfo(string.Format($"{{0,-{namespaceHost.Length}}}  {{1}}", "Namespace", "WcfRelayCount"));
                    RelayTraceSource.TraceInfo(string.Format($"{{0,-{namespaceHost.Length}}}  {{1}}", namespaceHost, count));

                    return(0);
                });
            });
        }
예제 #2
0
        static void ConfigureWcfDeleteCommand(CommandLineApplication wcfCommand)
        {
            wcfCommand.RelayCommand("delete", (deleteCmd) =>
            {
                deleteCmd.Description        = "Delete a WcfRelay";
                var pathArgument             = deleteCmd.Argument("path", "WcfRelay path");
                var connectionStringArgument = deleteCmd.Argument("connectionString", "Relay ConnectionString");
                var protocolOption           = deleteCmd.AddSecurityProtocolOption();

                deleteCmd.OnExecute(async() =>
                {
                    ConfigureSecurityProtocol(protocolOption);
                    string connectionString = ConnectionStringUtility.ResolveConnectionString(connectionStringArgument);
                    if (string.IsNullOrEmpty(connectionString) || string.IsNullOrEmpty(pathArgument.Value))
                    {
                        TraceMissingArgument(string.IsNullOrEmpty(connectionString) ? connectionStringArgument.Name : pathArgument.Name);
                        deleteCmd.ShowHelp();
                        return(1);
                    }

                    var connectionStringBuilder = new ServiceBusConnectionStringBuilder(connectionString);
                    RelayTraceSource.TraceInfo($"Deleting WcfRelay '{pathArgument.Value}' in {connectionStringBuilder.Endpoints.First().Host}...");
                    var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
                    await namespaceManager.DeleteRelayAsync(pathArgument.Value);
                    RelayTraceSource.TraceInfo($"Deleting WcfRelay '{pathArgument.Value}' in {connectionStringBuilder.Endpoints.First().Host} succeeded");
                    return(0);
                });
            });
        }
예제 #3
0
        static async Task TestStreaming(HybridConnectionListener listener, RelayConnectionStringBuilder connectionString, TraceSource traceSource)
        {
            traceSource.TraceInformation("Testing Streaming (WebSocket) mode");
            RunAcceptPump(listener);

            var client       = new HybridConnectionClient(connectionString.ToString());
            var requestBytes = Encoding.UTF8.GetBytes("<data>Request payload from sender</data>");
            HybridConnectionStream stream = await client.CreateConnectionAsync();

            string connectionName = $"S:HybridConnectionStream({stream.TrackingContext.TrackingId})";

            RelayTraceSource.TraceInfo($"{connectionName} initiated");
            RunConnectionPump(stream, connectionName);
            for (int i = 0; i < 2; i++)
            {
                await stream.WriteAsync(requestBytes, 0, requestBytes.Length);

                RelayTraceSource.TraceVerbose($"{connectionName} wrote {requestBytes.Length} bytes");
            }

            using (var closeCts = new CancellationTokenSource(TimeSpan.FromSeconds(5)))
            {
                RelayTraceSource.TraceVerbose($"{connectionName} closing");
                await stream.CloseAsync(closeCts.Token);

                RelayTraceSource.TraceInfo($"{connectionName} closed");
            }

            await Task.Delay(TimeSpan.FromMilliseconds(100));
        }
예제 #4
0
        public static int VerifyListen(string connectionString, string path, Binding binding, ConnectivityMode connectivityMode, string response, ServiceThrottlingBehavior throttlingBehavior)
        {
            RelayTraceSource.TraceInfo($"Open relay listener using {binding.GetType().Name}, ConnectivityMode.{connectivityMode}...");
            ServiceHost serviceHost = null;

            try
            {
                var connectionStringBuilder = new ServiceBusConnectionStringBuilder(connectionString);
                var tp = TokenProvider.CreateSharedAccessSignatureTokenProvider(connectionStringBuilder.SharedAccessKeyName, connectionStringBuilder.SharedAccessKey);

                string relayNamespace = connectionStringBuilder.Endpoints.First().Host;
                ServiceBusEnvironment.SystemConnectivity.Mode = connectivityMode;
                EchoService.DefaultResponse = response;
                if (!(binding is WebHttpRelayBinding))
                {
                    serviceHost = new ServiceHost(typeof(EchoService));
                }
                else
                {
                    serviceHost = new WebServiceHost(typeof(EchoService));
                }

                Type            contractType       = IsOneWay(binding) ? typeof(ITestOneway) : typeof(IEcho);
                ServiceEndpoint endpoint           = serviceHost.AddServiceEndpoint(contractType, binding, new Uri($"{binding.Scheme}://{relayNamespace}/{path}"));
                var             listenerActivityId = Guid.NewGuid();
                RelayTraceSource.TraceVerbose($"Listener ActivityId:{listenerActivityId}");
                endpoint.EndpointBehaviors.Add(new TransportClientEndpointBehavior(tp)
                {
                    ActivityId = listenerActivityId
                });
                serviceHost.Description.Behaviors.Add(throttlingBehavior);

                // Trace status changes
                var connectionStatus = new ConnectionStatusBehavior();
                connectionStatus.Connecting += (s, e) => RelayTraceSource.TraceException(connectionStatus.LastError, TraceEventType.Warning, "Relay listener Re-Connecting");
                connectionStatus.Online     += (s, e) => RelayTraceSource.Instance.TraceEvent(TraceEventType.Information, (int)ConsoleColor.Green, "Relay Listener is online");
                EventHandler offlineHandler = (s, e) => RelayTraceSource.TraceException(connectionStatus.LastError, "Relay Listener is OFFLINE");
                connectionStatus.Offline += offlineHandler;
                endpoint.EndpointBehaviors.Add(connectionStatus);
                serviceHost.Faulted += (s, e) => RelayTraceSource.TraceException(connectionStatus.LastError, "Relay listener ServiceHost Faulted");

                serviceHost.Open();
                RelayTraceSource.TraceInfo("Relay listener \"" + endpoint.Address.Uri + "\" is open");
                RelayTraceSource.TraceInfo("Press <ENTER> to close the listener ");
                Console.ReadLine();

                RelayTraceSource.TraceInfo("Closing Connection...");
                connectionStatus.Offline -= offlineHandler; // Avoid a spurious trace on expected shutdown.
                serviceHost.Close();
                RelayTraceSource.TraceInfo("Closed");
                return(0);
            }
            catch (Exception)
            {
                serviceHost?.Abort();
                throw;
            }
        }
예제 #5
0
        void ITestOneway.Operation(DateTime start, string message)
        {
            string duration = string.Empty;

            if (start != default)
            {
                duration = $"({(int)DateTime.UtcNow.Subtract(start).TotalMilliseconds}ms from start)";
            }

            RelayTraceSource.TraceInfo($"Listener received request: ITestOneway.Operation({message}) {duration}");
            RelayTraceSource.TraceVerbose($"Request MessageId:{OperationContext.Current.IncomingMessageHeaders.MessageId}, TrackingId:{this.trackingId}");
        }
예제 #6
0
        static void ConfigureWcfListCommand(CommandLineApplication wcfCommand)
        {
            wcfCommand.RelayCommand("list", (listCmd) =>
            {
                listCmd.Description          = "List WcfRelay(s)";
                var pathArgument             = listCmd.Argument("path", "Optional WcfRelay path");
                var connectionStringArgument = listCmd.Argument("connectionString", "Relay ConnectionString");
                var protocolOption           = listCmd.AddSecurityProtocolOption();

                listCmd.OnExecute(async() =>
                {
                    ConfigureSecurityProtocol(protocolOption);
                    string connectionString = ConnectionStringUtility.ResolveConnectionString(connectionStringArgument);
                    if (string.IsNullOrEmpty(connectionString))
                    {
                        TraceMissingArgument(connectionStringArgument.Name);
                        listCmd.ShowHelp();
                        return(1);
                    }

                    string path = pathArgument.Value;

                    var connectionStringBuilder = new ServiceBusConnectionStringBuilder(connectionString);
                    var namespaceManager        = NamespaceManager.CreateFromConnectionString(connectionString);
                    IEnumerable <RelayDescription> relays;
                    if (string.IsNullOrEmpty(path))
                    {
                        RelayTraceSource.TraceInfo($"Listing WcfRelays for {connectionStringBuilder.Endpoints.First().Host}");
                        relays = await namespaceManager.GetRelaysAsync();
                    }
                    else
                    {
                        RelayTraceSource.TraceInfo($"Getting WcfRelay {connectionStringBuilder.Endpoints.First().Host}/{path}");
                        relays = new[] { await namespaceManager.GetRelayAsync(path) };
                    }

                    RelayTraceSource.TraceInfo($"{"Path",-38} {"ListenerCount",-15} {"RequiresClientAuth",-20} RelayType");
                    foreach (var relay in relays)
                    {
                        RelayTraceSource.TraceInfo($"{relay.Path,-38} {relay.ListenerCount,-15} {relay.RequiresClientAuthorization,-20} {relay.RelayType}");
                    }

                    return(0);
                });
            });
        }
예제 #7
0
        public static int VerifySend(
            string request, ServiceBusConnectionStringBuilder connectionString, string path, int number, Binding binding, bool noClientAuth, ConnectivityMode connectivityMode, TimeSpan requestDelay)
        {
            RelayTraceSource.TraceInfo($"Send to relay listener using {binding.GetType().Name}, ConnectivityMode.{connectivityMode}...");
            string relayNamespace = connectionString.Endpoints.First().Host;
            string keyName        = connectionString.SharedAccessKeyName;
            string keyValue       = connectionString.SharedAccessKey;

            if (IsOneWay(binding))
            {
                return(VerifySendCore <ITestOnewayClient>(request, relayNamespace, path, number, binding, noClientAuth, connectivityMode, keyName, keyValue, requestDelay));
            }
            else
            {
                return(VerifySendCore <IEchoClient>(request, relayNamespace, path, number, binding, noClientAuth, connectivityMode, keyName, keyValue, requestDelay));
            }
        }
예제 #8
0
        public string Get(DateTime start, string message, TimeSpan delay)
        {
            string duration = string.Empty;

            if (start != default)
            {
                duration = $"({(int)DateTime.UtcNow.Subtract(start).TotalMilliseconds}ms from start)";
            }

            RelayTraceSource.TraceInfo($"Listener received request: Get({message}) {duration}");
            RelayTraceSource.TraceVerbose($"Request MessageId:{OperationContext.Current.IncomingMessageHeaders.MessageId}, TrackingId:{this.trackingId}");

            if (delay != TimeSpan.Zero)
            {
                RelayTraceSource.TraceVerbose($"Request MessageId:{OperationContext.Current.IncomingMessageHeaders.MessageId} delaying for {delay}");
                Thread.Sleep(delay);
            }

            return(DefaultResponse ?? DateTime.UtcNow.ToString("o"));
        }
예제 #9
0
        static void ConfigureWcfCreateCommand(CommandLineApplication wcfCommand)
        {
            wcfCommand.RelayCommand("create", (createCmd) =>
            {
                createCmd.Description = "Create a WcfRelay";

                var pathArgument             = createCmd.Argument("path", "WcfRelay path");
                var connectionStringArgument = createCmd.Argument("connectionString", "Relay ConnectionString");

                var relayTypeOption = createCmd.Option(
                    "-t|--relaytype <relaytype>", "The RelayType (nettcp|http)", CommandOptionType.SingleValue);
                var requireClientAuthOption = createCmd.Option(
                    CommandStrings.RequiresClientAuthTemplate, CommandStrings.RequiresClientAuthDescription, CommandOptionType.SingleValue);
                var protocolOption = createCmd.AddSecurityProtocolOption();

                createCmd.OnExecute(async() =>
                {
                    ConfigureSecurityProtocol(protocolOption);
                    string connectionString = ConnectionStringUtility.ResolveConnectionString(connectionStringArgument);
                    if (string.IsNullOrEmpty(connectionString) || string.IsNullOrEmpty(pathArgument.Value))
                    {
                        TraceMissingArgument(string.IsNullOrEmpty(connectionString) ? connectionStringArgument.Name : pathArgument.Name);
                        createCmd.ShowHelp();
                        return(1);
                    }

                    var connectionStringBuilder = new ServiceBusConnectionStringBuilder(connectionString);
                    RelayTraceSource.TraceInfo($"Creating WcfRelay '{pathArgument.Value}' in {connectionStringBuilder.Endpoints.First().Host}...");
                    var relayDescription = new RelayDescription(pathArgument.Value, GetRelayType(relayTypeOption));
                    relayDescription.RequiresClientAuthorization = GetBoolOption(requireClientAuthOption, true);
                    var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
                    await namespaceManager.CreateRelayAsync(relayDescription);
                    RelayTraceSource.TraceInfo($"Creating WcfRelay '{pathArgument.Value}' in {connectionStringBuilder.Endpoints.First().Host} succeeded");
                    return(0);
                });
            });
        }
예제 #10
0
        static async void RunConnectionPump(HybridConnectionStream stream, string connectionName, bool echoBytes = false)
        {
            try
            {
                var buffer = new byte[256];
                while (true)
                {
                    int read = await stream.ReadAsync(buffer, 0, buffer.Length);

                    RelayTraceSource.TraceVerbose($"{connectionName} received {read} bytes: \"{Encoding.UTF8.GetString(buffer, 0, read)}\"");
                    if (read == 0)
                    {
                        using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
                        {
                            RelayTraceSource.TraceVerbose($"{connectionName} closing");
                            await stream.CloseAsync(cts.Token);

                            RelayTraceSource.TraceInfo($"{connectionName} closed");
                        }

                        return;
                    }

                    if (echoBytes)
                    {
                        await stream.WriteAsync(buffer, 0, read);

                        RelayTraceSource.TraceVerbose($"{connectionName} echoed {read} bytes");
                    }
                }
            }
            catch (Exception exception)
            {
                RelayTraceSource.TraceException(exception, nameof(RunConnectionPump));
            }
        }
예제 #11
0
        static async void RunAcceptPump(HybridConnectionListener listener)
        {
            while (true)
            {
                try
                {
                    HybridConnectionStream stream = await listener.AcceptConnectionAsync();

                    if (stream == null)
                    {
                        return;
                    }

                    string connectionName = $"L:HybridConnectionStream({stream.TrackingContext.TrackingId})";
                    RelayTraceSource.TraceInfo($"{connectionName} accepted");
                    RunConnectionPump(stream, connectionName, echoBytes: true);
                }
                catch (Exception exception)
                {
                    RelayTraceSource.TraceException(exception, nameof(RunAcceptPump));
                    await Task.Delay(TimeSpan.FromMilliseconds(100));
                }
            }
        }
예제 #12
0
        static int VerifySendCore <TChannel>(
            string request, string relayNamespace, string path, int number, Binding binding, bool noClientAuth, ConnectivityMode connectivityMode, string keyName, string keyValue, TimeSpan requestDelay)
            where TChannel : class, IClientChannel
        {
            ChannelFactory <TChannel> channelFactory = null;
            TChannel channel = null;

            try
            {
                ServiceBusEnvironment.SystemConnectivity.Mode = connectivityMode;
                Uri address = new Uri($"{binding.Scheme}://{relayNamespace}/{path}");
                if (binding is WebHttpRelayBinding)
                {
                    channelFactory = new WebChannelFactory <TChannel>(binding, address);
                }
                else
                {
                    channelFactory = new ChannelFactory <TChannel>(binding, new EndpointAddress(address));
                }

                var tp = TokenProvider.CreateSharedAccessSignatureTokenProvider(keyName, keyValue);
                if (!noClientAuth)
                {
                    channelFactory.Endpoint.EndpointBehaviors.Add(new TransportClientEndpointBehavior(tp));
                }

                RelayTraceSource.TraceVerbose("Sender opening channel factory");
                var stopwatch = new Stopwatch();
                stopwatch.Restart();
                channelFactory.Open();
                RelayTraceSource.TraceVerbose($"Sender opened channel factory in {stopwatch.ElapsedMilliseconds} ms");

                channel = channelFactory.CreateChannel();
                RelayTraceSource.TraceInfo("Sender opening channel");
                using (new OperationContextScope(channel))
                {
                    Guid trackingId = Guid.NewGuid();
                    RelayTraceSource.TraceVerbose($"Channel TrackingId:{trackingId}");
                    if (binding.MessageVersion.Addressing != AddressingVersion.None)
                    {
                        OperationContext.Current.OutgoingMessageHeaders.MessageId = new UniqueId(trackingId);
                    }

                    stopwatch.Restart();
                    channel.Open();
                    RelayTraceSource.TraceVerbose($"Sender opened channel in {stopwatch.ElapsedMilliseconds} ms");
                    RelayTraceSource.TraceVerbose($"Channel SessionId:{channel.SessionId}");
                }

                for (int i = 0; i < number; i++)
                {
                    using (new OperationContextScope(channel))
                    {
                        var messageId = Guid.NewGuid();
                        RelayTraceSource.TraceVerbose($"Sending MessageId:{messageId}");
                        if (binding.MessageVersion.Addressing != AddressingVersion.None)
                        {
                            OperationContext.Current.OutgoingMessageHeaders.MessageId = new UniqueId(messageId);
                        }

                        stopwatch.Restart();
                        if (channel is IEchoClient echoChannel)
                        {
                            string response = echoChannel.Echo(DateTime.UtcNow, request, requestDelay);
                            RelayTraceSource.TraceInfo($"Sender received response: {response} ({stopwatch.ElapsedMilliseconds} ms)");
                        }
                        else if (channel is ITestOnewayClient onewayClient)
                        {
                            onewayClient.Operation(DateTime.UtcNow, request);
                            RelayTraceSource.TraceInfo($"Sender sent oneway request: {request} ({stopwatch.ElapsedMilliseconds} ms)");
                        }
                        else
                        {
                            throw new NotSupportedException($"Contract {typeof(TChannel)} is not supported");
                        }
                    }
                }

                RelayTraceSource.TraceInfo("Sender closing channel");
                stopwatch.Restart();
                channel.Close();
                RelayTraceSource.TraceVerbose($"Sender closed channel in {stopwatch.ElapsedMilliseconds} ms");
                channel = null;

                RelayTraceSource.TraceVerbose("Sender closing channel factory");
                stopwatch.Restart();
                channelFactory.Close();
                RelayTraceSource.TraceVerbose($"Sender closed channel factory in {stopwatch.ElapsedMilliseconds} ms");
                channelFactory = null;

                return(0);
            }
            finally
            {
                channel?.Abort();
                channelFactory?.Abort();
            }
        }
예제 #13
0
        internal static async Task VerifySendAsync(RelayConnectionStringBuilder connectionString, int number, string httpMethod, string requestData, TraceSource traceSource)
        {
            Uri hybridHttpUri = new Uri($"https://{connectionString.Endpoint.GetComponents(UriComponents.HostAndPort, UriFormat.SafeUnescaped)}/{connectionString.EntityPath}");
            var tokenProvider = GetTokenProvider(connectionString);

            if (string.Equals("WS", httpMethod, StringComparison.OrdinalIgnoreCase) ||
                string.Equals("WEBSOCKET", httpMethod, StringComparison.OrdinalIgnoreCase))
            {
                var client       = new HybridConnectionClient(connectionString.ToString());
                var requestBytes = Encoding.UTF8.GetBytes(requestData ?? string.Empty);
                HybridConnectionStream stream = await client.CreateConnectionAsync();

                string connectionName = $"S:HybridConnectionStream({stream.TrackingContext.TrackingId})";
                RelayTraceSource.TraceInfo($"{connectionName} initiated");
                RunConnectionPump(stream, connectionName);
                for (int i = 0; i < number; i++)
                {
                    await stream.WriteAsync(requestBytes, 0, requestBytes.Length);

                    RelayTraceSource.TraceVerbose($"{connectionName} wrote {requestBytes.Length} bytes");
                }

                await Task.Delay(TimeSpan.FromSeconds(1));

                using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)))
                {
                    RelayTraceSource.TraceVerbose($"{connectionName} closing");
                    await stream.CloseAsync(cts.Token);

                    RelayTraceSource.TraceInfo($"{connectionName} closed");
                }

                return;
            }

            string token = null;

            if (tokenProvider != null)
            {
                token = (await tokenProvider.GetTokenAsync(hybridHttpUri.AbsoluteUri, TimeSpan.FromDays(2))).TokenString;
            }

            var stopwatch = new Stopwatch();

            using (var client = new HttpClient {
                BaseAddress = hybridHttpUri
            })
            {
                client.DefaultRequestHeaders.ExpectContinue = false;

                for (int i = 0; i < number; i++)
                {
                    stopwatch.Restart();
                    var httpRequest = new HttpRequestMessage();
                    if (token != null)
                    {
                        httpRequest.Headers.Add("ServiceBusAuthorization", token);
                    }

                    httpRequest.Method = new HttpMethod(httpMethod);
                    if (requestData != null)
                    {
                        httpRequest.Content = new StringContent(requestData);
                    }

                    LogHttpRequest(httpRequest, client, traceSource);
                    using (HttpResponseMessage response = await client.SendAsync(httpRequest))
                    {
                        LogHttpResponse(response, traceSource);
                    }

                    traceSource.TraceInformation($"Elapsed:  {stopwatch.ElapsedMilliseconds} ms");
                }
            }
        }