public async Task<Dictionary<string, string>> ExecuteAsync(SonosDevice device, UpnpService service, UpnpAction action, Dictionary<string, string> values)
        {
            var uri = new Uri($"http://{device.IpAddress}:1400{service.ControlUrl}");
            var soapAction = $"{service.Id}#{action.Name}";

            var body = new StringBuilder();
            body.Append($"<u:{action.Name} xmlns:u=\"{service.Type}\">");

            foreach (var argument in action.InputArguments)
            {
                string value;
                if (values.TryGetValue(argument, out value))
                {
                    body.Append($"<{argument}>{value}</{argument}>");
                }
            }
            body.Append($"</u:{action.Name}>");

            var result = new Dictionary<string, string>();

            try
            {
                var document = await PostRequestInternalAsync(uri, soapAction, body.ToString());

                foreach (var argument in action.OutputArguments)
                {
                    var value = document.SelectSingleNode("//" + argument)?.InnerText;
                    result.Add(argument, value);
                }
            }
            catch (WebException e)
            {
                _log.Error($"Unable to execute action {action.Name} for device {device.Name}: {e.Message}");
            }
            catch (Exception e)
            {
                _log.Error($"Unable to execute action {action.Name} for device {device.Name}: {e.Message}", e);
            }

            return result;
        }
        public async Task <Dictionary <string, string> > ExecuteAsync(SonosDevice device, UpnpService service, UpnpAction action, Dictionary <string, string> values)
        {
            var uri        = new Uri($"http://{device.IpAddress}:1400{service.ControlUrl}");
            var soapAction = $"{service.Id}#{action.Name}";

            var body = new StringBuilder();

            body.Append($"<u:{action.Name} xmlns:u=\"{service.Type}\">");

            foreach (var argument in action.InputArguments)
            {
                string value;
                if (values.TryGetValue(argument, out value))
                {
                    body.Append($"<{argument}>{value}</{argument}>");
                }
            }
            body.Append($"</u:{action.Name}>");

            var result = new Dictionary <string, string>();

            try
            {
                var document = await PostRequestInternalAsync(uri, soapAction, body.ToString());

                foreach (var argument in action.OutputArguments)
                {
                    var value = document.SelectSingleNode("//" + argument)?.InnerText;
                    result.Add(argument, value);
                }
            }
            catch (WebException e)
            {
                _log.Error($"Unable to execute action {action.Name} for device {device.Name}: {e.Message}");
            }
            catch (Exception e)
            {
                _log.Error($"Unable to execute action {action.Name} for device {device.Name}: {e.Message}", e);
            }

            return(result);
        }