Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
UPnPAction.cs
1using System;
2using System.IO;
3using System.Collections.Generic;
4using System.Net.Http;
5using System.Text;
6using System.Threading.Tasks;
7using System.Xml;
8
10{
14 public class UPnPAction
15 {
16 private readonly Dictionary<string, UPnPArgument> argumentByName = new Dictionary<string, UPnPArgument>();
17 private readonly ServiceDescriptionDocument parent;
18 private readonly XmlElement xml;
19 private readonly UPnPArgument[] arguments;
20 private readonly string name;
21
22 internal UPnPAction(XmlElement Xml, ServiceDescriptionDocument Parent)
23 {
24 List<UPnPArgument> Arguments = new List<UPnPArgument>();
25
26 this.parent = Parent;
27 this.xml = Xml;
28
29 foreach (XmlNode N in Xml.ChildNodes)
30 {
31 switch (N.LocalName)
32 {
33 case "name":
34 this.name = N.InnerText;
35 break;
36
37 case "argumentList":
38 foreach (XmlNode N2 in N.ChildNodes)
39 {
40 if (N2.LocalName == "argument")
41 {
42 UPnPArgument Argument = new UPnPArgument((XmlElement)N2);
43 Arguments.Add(Argument);
44 this.argumentByName[Argument.Name] = Argument;
45 }
46 }
47 break;
48 }
49 }
50
51 this.arguments = Arguments.ToArray();
52 }
53
57 public XmlElement Xml => this.xml;
58
62 public string Name => this.name;
63
67 public UPnPArgument[] Arguments => this.arguments;
68
73
80 public object Invoke(out Dictionary<string, object> OutputValues, params KeyValuePair<string, object>[] InputValues)
81 {
82 return this.Invoke(out OutputValues, 10000, InputValues);
83 }
84
91 public object Invoke(Dictionary<string, object> InputValues, out Dictionary<string, object> OutputValues)
92 {
93 return this.Invoke(InputValues, out OutputValues, 10000);
94 }
95
103 public object Invoke(out Dictionary<string, object> OutputValues, int Timeout, params KeyValuePair<string, object>[] InputValues)
104 {
105 Dictionary<string, object> InputValues2 = new Dictionary<string, object>();
106
107 foreach (KeyValuePair<string, object> P in InputValues)
108 InputValues2[P.Key] = P.Value;
109
110 return this.Invoke(InputValues2, out OutputValues, Timeout);
111 }
112
120 public object Invoke(Dictionary<string, object> InputValues, out Dictionary<string, object> OutputValues, int Timeout)
121 {
122 KeyValuePair<object, Dictionary<string, object>> Result = this.InvokeAsync(InputValues, Timeout).Result;
123 OutputValues = Result.Value;
124 return Result.Key;
125 }
126
133 public Task<KeyValuePair<object, Dictionary<string, object>>> InvokeAsync(int Timeout, params KeyValuePair<string, object>[] InputValues)
134 {
135 Dictionary<string, object> InputValues2 = new Dictionary<string, object>();
136
137 foreach (KeyValuePair<string, object> P in InputValues)
138 InputValues2[P.Key] = P.Value;
139
140 return this.InvokeAsync(InputValues2, Timeout);
141 }
142
149 public async Task<KeyValuePair<object, Dictionary<string, object>>> InvokeAsync(Dictionary<string, object> InputValues, int Timeout)
150 {
151 Dictionary<string, object> OutputValues;
152 StringBuilder Soap = new StringBuilder();
153 UPnPStateVariable Variable;
154 object Result = null;
155 object First = null;
156
157 Soap.AppendLine("<?xml version=\"1.0\"?>");
158 Soap.AppendLine("<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">");
159 Soap.AppendLine("<s:Body>");
160 Soap.Append("<u:");
161 Soap.Append(this.name);
162 Soap.Append(" xmlns:u=\"");
163 Soap.Append(XmlAttributeEncode(this.parent.Service.ServiceType));
164 Soap.AppendLine("\">");
165
166 foreach (UPnPArgument Argument in this.arguments)
167 {
168 if (Argument.Direction == ArgumentDirection.In)
169 {
170 Soap.Append("<");
171 Soap.Append(Argument.Name);
172 Soap.Append(">");
173
174 if (InputValues.TryGetValue(Argument.Name, out object Value) &&
175 !((Variable = this.parent.GetVariable(Argument.RelatedStateVariable)) is null))
176 {
177 Soap.Append(XmlAttributeEncode(await Variable.ValueToXmlString(Value)));
178 }
179
180 Soap.Append("</");
181 Soap.Append(Argument.Name);
182 Soap.Append(">");
183 }
184 }
185
186 Soap.Append("</u:");
187 Soap.Append(this.name);
188 Soap.AppendLine(">");
189 Soap.AppendLine("</s:Body>");
190 Soap.AppendLine("</s:Envelope>");
191
192 using (HttpClient HttpClient = new HttpClient())
193 {
194 HttpClient.Timeout = TimeSpan.FromMilliseconds(Timeout);
195 HttpClient.DefaultRequestHeaders.ExpectContinue = false;
196
197 HttpContent Body = new StringContent(Soap.ToString(), Encoding.UTF8, "text/xml");
198 Body.Headers.Add("SOAPACTION", "\"" + this.parent.Service.ServiceType + "#" + this.name + "\"");
199
200 XmlDocument ResponseXml;
201
202 HttpResponseMessage Response = await HttpClient.PostAsync(this.parent.Service.ControlURI, Body);
203 Stream Stream = await Response.Content.ReadAsStreamAsync(); // Regardless of status code, we check for XML content.
204
205 ResponseXml = new XmlDocument()
206 {
207 PreserveWhitespace = true
208 };
209 ResponseXml.Load(Stream);
210
211 if (ResponseXml.DocumentElement is null ||
212 ResponseXml.DocumentElement.LocalName != "Envelope" ||
213 ResponseXml.DocumentElement.NamespaceURI != "http://schemas.xmlsoap.org/soap/envelope/")
214 {
215 throw new Exception("Unexpected response returned.");
216 }
217
218 XmlElement ResponseBody = GetChildElement(ResponseXml.DocumentElement, "Body", "http://schemas.xmlsoap.org/soap/envelope/")
219 ?? throw new Exception("Response body not found.");
220
221 XmlElement ActionResponse = GetChildElement(ResponseBody, this.name + "Response", this.parent.Service.ServiceType);
222 if (ActionResponse is null)
223 {
224 XmlElement ResponseFault = GetChildElement(ResponseBody, "Fault", "http://schemas.xmlsoap.org/soap/envelope/")
225 ?? throw new Exception("Unable to parse response.");
226
227 string FaultCode = string.Empty;
228 string FaultString = string.Empty;
229 string UPnPErrorCode = string.Empty;
230 string UPnPErrorDescription = string.Empty;
231
232 foreach (XmlNode N in ResponseFault.ChildNodes)
233 {
234 switch (N.LocalName)
235 {
236 case "faultcode":
237 FaultCode = N.InnerText;
238 break;
239
240 case "faultstring":
241 FaultString = N.InnerText;
242 break;
243
244 case "detail":
245 foreach (XmlNode N2 in N.ChildNodes)
246 {
247 switch (N2.LocalName)
248 {
249 case "UPnPError":
250 foreach (XmlNode N3 in N2.ChildNodes)
251 {
252 switch (N3.LocalName)
253 {
254 case "errorCode":
255 UPnPErrorCode = N3.InnerText;
256 break;
257
258 case "errorDescription":
259 UPnPErrorDescription = N3.InnerText;
260 break;
261 }
262 }
263 break;
264 }
265 }
266 break;
267 }
268 }
269
270 throw new UPnPException(FaultCode, FaultString, UPnPErrorCode, UPnPErrorDescription);
271 }
272
273 XmlElement E;
274
275 OutputValues = new Dictionary<string, object>();
276
277 foreach (XmlNode N in ActionResponse.ChildNodes)
278 {
279 E = N as XmlElement;
280 if (E is null)
281 continue;
282
283 if (this.argumentByName.TryGetValue(E.LocalName, out UPnPArgument Argument2))
284 {
285 if (!((Variable = this.parent.GetVariable(Argument2.RelatedStateVariable)) is null))
286 {
287 object Value2 = Variable.XmlStringToValue(E.InnerText);
288 OutputValues[E.LocalName] = Value2;
289
290 if (First is null)
291 First = Value2;
292
293 if (Argument2.ReturnValue && Result is null)
294 Result = Value2;
295 }
296 else
297 {
298 if (First is null)
299 First = E.InnerXml;
300
301 OutputValues[E.LocalName] = E.InnerXml;
302 }
303 }
304 else
305 {
306 if (First is null)
307 First = E.InnerXml;
308
309 OutputValues[E.LocalName] = E.InnerXml;
310 }
311 }
312 }
313
314 if (Result is null)
315 Result = First;
316
317 return new KeyValuePair<object, Dictionary<string, object>>(Result, OutputValues);
318 }
319
320 private static XmlElement GetChildElement(XmlElement E, string LocalName, string Namespace)
321 {
322 XmlElement E2;
323
324 foreach (XmlNode N in E.ChildNodes)
325 {
326 E2 = N as XmlElement;
327 if (E2 is null)
328 continue;
329
330 if (E2.LocalName == LocalName && E2.NamespaceURI == Namespace)
331 return E2;
332 }
333
334 return null;
335 }
336
342 public static string XmlAttributeEncode(string AttributeValue)
343 {
344 if (AttributeValue is null || AttributeValue.IndexOfAny(reservedCharacters) < 0)
345 return AttributeValue;
346
347 return AttributeValue.
348 Replace("&", "&amp;").
349 Replace("<", "&lt;").
350 Replace(">", "&gt;").
351 Replace("\"", "&quot;").
352 Replace("'", "&apos;");
353 }
354
355 private static readonly char[] reservedCharacters = new char[] { '&', '<', '>', '"', '\'' };
356
357 }
358}
Contains the information provided in a Service Description Document, downloaded from a service in the...
Contains information about an action.
Definition: UPnPAction.cs:15
object Invoke(out Dictionary< string, object > OutputValues, int Timeout, params KeyValuePair< string, object >[] InputValues)
Invokes the action.
Definition: UPnPAction.cs:103
Task< KeyValuePair< object, Dictionary< string, object > > > InvokeAsync(int Timeout, params KeyValuePair< string, object >[] InputValues)
Invokes the action.
Definition: UPnPAction.cs:133
object Invoke(Dictionary< string, object > InputValues, out Dictionary< string, object > OutputValues)
Invokes the action.
Definition: UPnPAction.cs:91
object Invoke(Dictionary< string, object > InputValues, out Dictionary< string, object > OutputValues, int Timeout)
Invokes the action.
Definition: UPnPAction.cs:120
UPnPArgument[] Arguments
Service Arguments.
Definition: UPnPAction.cs:67
object Invoke(out Dictionary< string, object > OutputValues, params KeyValuePair< string, object >[] InputValues)
Invokes the action.
Definition: UPnPAction.cs:80
XmlElement Xml
Underlying XML definition.
Definition: UPnPAction.cs:57
static string XmlAttributeEncode(string AttributeValue)
Encodes an XML attribute.
Definition: UPnPAction.cs:342
async Task< KeyValuePair< object, Dictionary< string, object > > > InvokeAsync(Dictionary< string, object > InputValues, int Timeout)
Invokes the action.
Definition: UPnPAction.cs:149
Contains information about an argument.
Definition: UPnPArgument.cs:28
string RelatedStateVariable
Related State Variable
Definition: UPnPArgument.cs:88
ArgumentDirection Direction
Argument Direction
Definition: UPnPArgument.cs:78
Contains information about a state variable.
ArgumentDirection
Direction of action arguments.
Definition: UPnPArgument.cs:12