/// <summary> /// Encodes a call of the specified <paramref name="action"/> with the given <paramref name="inParamValues"/> and /// returns the resulting SOAP XML string. /// </summary> /// <param name="action">Action to be called.</param> /// <param name="inParamValues">List of parameter values which must match the action's signature. /// Can be <c>null</c> if the parameter list is empty.</param> /// <param name="upnpVersion">UPnP version to use for the encoding.</param> /// <returns>XML string which contains the SOAP document.</returns> public static string EncodeCall(CpAction action, IList <object> inParamValues, UPnPVersion upnpVersion) { bool targetSupportsUPnP11 = upnpVersion.VerMin >= 1; StringBuilder result = new StringBuilder(5000); using (StringWriterWithEncoding stringWriter = new StringWriterWithEncoding(result, UPnPConsts.UTF8_NO_BOM)) using (XmlWriter writer = XmlWriter.Create(stringWriter, UPnPConfiguration.DEFAULT_XML_WRITER_SETTINGS)) { SoapHelper.WriteSoapEnvelopeStart(writer, true); writer.WriteStartElement("u", action.Name, action.ParentService.ServiceTypeVersion_URN); // Check input parameters IList <CpArgument> formalArguments = action.InArguments; if (inParamValues == null) { inParamValues = EMPTY_OBJECT_LIST; } if (inParamValues.Count != formalArguments.Count) { throw new ArgumentException("Invalid argument count"); } for (int i = 0; i < formalArguments.Count; i++) { CpArgument argument = formalArguments[i]; object value = inParamValues[i]; writer.WriteStartElement(argument.Name); argument.SoapSerializeArgument(value, !targetSupportsUPnP11, writer); writer.WriteEndElement(); // argument.Name } SoapHelper.WriteSoapEnvelopeEndAndClose(writer); } return(result.ToString()); }
protected static IList <object> ParseResult(TextReader textReader, CpAction action, bool sourceSupportsUPnP11) { object[] outParameterValues = new object[action.OutArguments.Count]; using (XmlReader reader = XmlReader.Create(textReader, UPnPConfiguration.DEFAULT_XML_READER_SETTINGS)) { reader.MoveToContent(); // Parse SOAP envelope reader.ReadStartElement("Envelope", UPnPConsts.NS_SOAP_ENVELOPE); reader.ReadStartElement("Body", UPnPConsts.NS_SOAP_ENVELOPE); // Reader is positioned at the action element string serviceTypeVersion_URN = reader.NamespaceURI; string type; int version; // Parse service and action if (!ParserHelper.TryParseTypeVersion_URN(serviceTypeVersion_URN, out type, out version)) { throw new ArgumentException("Invalid service type or version"); } string actionName = reader.LocalName; if (!actionName.EndsWith("Response") || actionName.Substring(0, actionName.Length - "Response".Length) != action.Name) { throw new ArgumentException("Invalid action name in result message"); } // UPnP spec says we have to be able to handle return values being out // of order to support UPnP 1.0 devices. See UPnP-arch-DeviceArchitecture-v1.1 // section 2.5.4. We need a dictionary to make this easy. IDictionary <string, int> formalArgIdxDictionary = new Dictionary <string, int>(); for (int i = 0; i < action.OutArguments.Count; i++) { formalArgIdxDictionary.Add(action.OutArguments[i].Name, i); } int outArgCount = 0; if (!SoapHelper.ReadEmptyStartElement(reader)) { // Parse and check output parameters while (reader.NodeType != XmlNodeType.EndElement) { string argumentName = reader.Name; // Arguments don't have a namespace, so take full name int formalArgumentIndex; if (!formalArgIdxDictionary.TryGetValue(argumentName, out formalArgumentIndex)) { throw new ArgumentException("Invalid argument name"); } CpArgument formalArgument = action.OutArguments[formalArgumentIndex]; // Get the argument value and store it in the correct position in the return list. object value = null; if (!SoapHelper.ReadNull(reader)) { formalArgument.SoapParseArgument(reader, !sourceSupportsUPnP11, out value); } outParameterValues[formalArgumentIndex] = value; outArgCount++; // Don't allow duplicates of the same argument. formalArgIdxDictionary.Remove(formalArgument.Name); } } if (outArgCount != action.OutArguments.Count) // Too few arguments { throw new ArgumentException("Invalid out argument count"); } } return(outParameterValues); }