/// <summary>
        /// Invokes an action.
        /// </summary>
        /// <param name="ActionName">Action Name</param>
        /// <param name="InputValues">Input values.</param>
        /// <param name="Timeout">Timeout, in milliseconds.</param>
        /// <returns>Return value, if any, null otherwise, together with any output values found in response.</returns>
        /// <exception cref="ArgumentException">If action is not found.</exception>
        public Task <KeyValuePair <object, Dictionary <string, object> > > InvokeAsync(string ActionName, Dictionary <string, object> InputValues, int Timeout)
        {
            UPnPAction Action = this.GetAction(ActionName);

            if (Action == null)
            {
                throw new ArgumentException("Action not found: " + ActionName, nameof(ActionName));
            }

            return(Action.InvokeAsync(InputValues, Timeout));
        }
        internal ServiceDescriptionDocument(XmlDocument Xml, UPnPClient Client, UPnPService Service)
        {
            List <UPnPStateVariable> Variables = new List <UPnPStateVariable>();
            List <UPnPAction>        Actions   = new List <UPnPAction>();

            this.xml     = Xml;
            this.service = Service;

            if (Xml.DocumentElement != null && Xml.DocumentElement.LocalName == "scpd" &&
                Xml.DocumentElement.NamespaceURI == "urn:schemas-upnp-org:service-1-0")
            {
                foreach (XmlNode N in Xml.DocumentElement.ChildNodes)
                {
                    switch (N.LocalName)
                    {
                    case "specVersion":
                        foreach (XmlNode N2 in N.ChildNodes)
                        {
                            switch (N2.LocalName)
                            {
                            case "major":
                                this.majorVersion = int.Parse(N2.InnerText);
                                break;

                            case "minor":
                                this.minorVersion = int.Parse(N2.InnerText);
                                break;
                            }
                        }
                        break;

                    case "actionList":
                        foreach (XmlNode N2 in N.ChildNodes)
                        {
                            if (N2.LocalName == "action")
                            {
                                UPnPAction Action = new UPnPAction((XmlElement)N2, this);
                                Actions.Add(Action);
                                this.actionsByName[Action.Name] = Action;
                            }
                        }
                        break;

                    case "serviceStateTable":
                        foreach (XmlNode N2 in N.ChildNodes)
                        {
                            if (N2.LocalName == "stateVariable")
                            {
                                UPnPStateVariable Variable = new UPnPStateVariable((XmlElement)N2);
                                Variables.Add(Variable);
                                this.variablesByName[Variable.Name] = Variable;
                            }
                        }
                        break;
                    }
                }
            }
            else
            {
                throw new Exception("Unrecognized file format.");
            }

            this.actions   = Actions.ToArray();
            this.variables = Variables.ToArray();
        }