Benutzer mit den meisten Antworten
C# SOAP 1.2 Request

Frage
-
Hallo liebe Community,
ich quäle mich derzeit etwas mit einer C# Webanwendung.
Es geht darum, an einen Server der SOAP unterstützt eine XML zu senden, die er verarbeiten kann.So sieht die vorgegebene Insert XML aus:
POST /iltisapi/ILTISAPI.asmx HTTP/1.1 Host: Test.... Content-Type: application/soap+xml; charset=utf-8 Content-Length: length <?xml version="1.0" encoding="utf-8"?> <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"> <soap12:Body> <REMEDY_InsertIncidentXML xmlns="http://test.com/webservices/"> <userName>string</userName> <xml>string</xml> </REMEDY_InsertIncidentXML> </soap12:Body> </soap12:Envelope>
Der String xml ist dazu da, den Insert in ein Ticketsystem zu produzieren.
Dieses XML baue ich mit einem Writer:
StringBuilder sb = new StringBuilder();
using (XmlWriter xmlWriter = XmlWriter.Create(sb))
{
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("incident");
xmlWriter.WriteStartElement("msg_id", "" + computer_idn + "_" + swidn_choice + "");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("contact");
xmlWriter.WriteElementString("employee_id", "" + windows_user + "");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("status", "In Progress");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("state", "Unassigned");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("impact", "5 - BAU");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("urgency", "3 - BAU");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("it_short_desc", "Test: BISS – Software Deployment");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("type", "User Service Request");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("service", "NOT DETERMINDED");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("inquiry_txt", "Test: Installation der Software " + swName_choice + " auf " + CI_Number + "");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("source", "Interface");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteEndDocument();
xmlWriter.Close();
}
sb.ToString();Das ganze möchte ich natürlich dann an den Server senden:
string username = "BISS";
string strReq = @"<?xml version=" + "1.0" + " encoding=" + "utf-8" + "?><soap12:Envelope xmlns:xsi=" + "http://www.w3.org/2001/XMLSchema-instance" + " xmlns:xsd=" + "http://www.w3.org/2001/XMLSchema" + " xmlns:soap12=" + "http://www.w3.org/2003/05/soap-envelope" + "><soap12:Body><REMEDY_InsertIncidentXML xmlns=" + "http://test.com/webservices/" + "><userName>" + username + "</userName><xml>" + sb + ".xml</xml></REMEDY_InsertIncidentXML></soap12:Body></soap12:Envelope>";
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://test.../iltisapi/");
req.Credentials = new NetworkCredential("BISS", "");
req.Method = "POST";
req.ContentType = "application/soap+xml; charset=utf-8";
UTF8Encoding encoding = new UTF8Encoding();
byte[] postBytes = encoding.GetBytes(strReq);
req.ContentLength = postBytes.Length;
Stream postStream = req.GetRequestStream();
postStream.Write(postBytes,0,postBytes.Length);
postStream.Close();
HttpWebResponse reqResponse = (HttpWebResponse) req.GetResponse();
Stream responseStream = reqResponse.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
String strRes = reader.ReadToEnd();
Console.WriteLine("Response: "+strRes);
reqResponse.Close();Ich bekomme die Fehlermeldung:
Length = "postStream.Length" hat eine Ausnahme vom Typ "System.NotSupportedException" verursacht.
und
"postStream.Position" hat eine Ausnahme vom Typ "System.NotSupportedException" verursacht.Ich tappe echt im dunkeln bei der ganzen Geschichte. Kann mir jemand helfen?
LG
ziggyyy
Antworten
-
Hallo Jürgen,
hier einmal die Definitionen der beiden Methoden.
public IAsyncResult BeginInsertIncident(string userName, string password, string MsgId, string ThirdPartyRef, string Type, string EmployeeId, string ShortDescription, string Details, string Category, string Service, string OwnerGrp, string OwnerRep, string SecondLevelGrp, string SecondLevelRep, string ThirdLevelGrp, string ThirdLevelRep, string Impact, string Urgency, string Priority, string Source, string Status, string State, string Solution, string ResolvedDate, string Cause, string Approved, AsyncCallback callback, object asyncState);
EndInsertIncident(IAsyncResult asyncResult, out string msg);
Die EndInsertIncident Methode gibt zurück, ob das Ticket erfolgreich angelegt worden ist.
Der Status von InsertIncidentCompleted steht immer auf null, weil ich die EndInsertIncident nicht aufrufe... :/
- Als Antwort markiert ziggyyy Donnerstag, 28. Februar 2013 11:27
Alle Antworten
-
Hi,
bei einem kurzen Überfliegen fällt mir lediglich auf, dass Du beim Zusammenbauen der namespaces die Gänsebeine nicht richtig setzt
"xmlns:xsi=" + "http://www.w3.org/2001/XMLSchema-instance"
ergibt xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance und nicht
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
Ob das der Grund für die Längen-Fehlermeldung ist, kann ich aber nicht sagen. Wie lang ist denn Dein zu sendendes byte-array?
Was mir aber mehr auffiel: Warum machst Du die ganze Arbeit selbst? Hast Du schon mal VS einen WebService-Client erstellen lassen (RMT im Solution Explorer und "add service reference" wählen im engl. VS)? Das funktioniert ganz wunderbar, wenn Dein WebService seine Schnittstelle via WSDL preisgibt. Dann bekommst Du eine 'normale' C#-Klasse mit Properties für die benötigten Felder und Methoden um den POST (oder auch GETs) durchzuführen.
Gruß
Jürgen -
Hallo Jürgen,
danke für deine Antwort.
Ich bekomme leider die Vorgabe, wie ich es zu machen habe :/ Wir haben noch ein anderes Tool, was die gleiche Schnittstelle benutzt und es sollte so umgesetzt werden, wie dort.Ich habe den String geändert:
string strReq = @"<?xml version=""1.0"" encoding=""utf-8""?><soap12:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap12=""http://www.w3.org/2003/05/soap-envelope"">;<soap12:Body><REMEDY_InsertIncidentXML xmlns=""http://tui.com/webservices/""><userName>" + username + "</userName><xml>" + sb + "</xml></REMEDY_InsertIncidentXML></soap12:Body></soap12:Envelope>";Auf MSDN habe ich aber gelesen, dass nur in VB die doppelten Anführungszeichen genutzt werden und bei C# ein Backslash. Nur wenn ich es mit einem Backslash mache, haut mir der Compiler auf die Finger. Komischerweise ersetzt er ein beim compilen ein Anführungszeichen durch ein Bachslash. Das Resultat sieht dann so aus:"<?xml version=\"1.0\" encoding=\"utf-8\"?><soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\">;<soap12:Body><REMEDY_InsertIncidentXML xmlns=\"http://tui.com/webservices/\"><userName>BISS</userName><xml><?xml version=\"1.0\" encoding=\"utf-16\"?><incident><msg_id xmlns=\"50889_187\" /><contact><employee_id>fischem</employee_id></contact><status xmlns=\"In Progress\" /><state xmlns=\"Unassigned\" /><impact xmlns=\"5 - BAU\" /><urgency xmlns=\"3 - BAU\" /><it_short_desc xmlns=\"Test: BISS – Software Deployment\" /><type xmlns=\"User Service Request\" /><service xmlns=\"NOT DETERMINDED\" /><inquiry_txt xmlns=\"Test: Installation der Software !!!OLD!!! FileMaker Inc. Filemaker Pro Version 5.5 auf 306524\" /><source xmlns=\"Interface\" /></incident></xml></REMEDY_InsertIncidentXML></soap12:Body></soap12:Envelope>"
Die Fehlermeldung bröselt sich irgendwann in ein "Dieser Stream unterstützt keine Suchvorgänge." auf. Wobei ich doch gar nichts suche, sondern nur etwas poste?! Die bytes sind unterschiedlich lang. Von 300 bis über 900 bytes. Ist das ein Problem?
LG
ziggyyy- Bearbeitet ziggyyy Montag, 25. Februar 2013 08:54 schreibfehler
-
Hi,
mit strings in VB kenne ich mich nicht aus. In C# ist es korrekt, wenn Du schreibst:
strReq = "attribue=\"bla\"".
Das wird umgesetzt in 'attribue="bla"'
. Du darfst, um den Backslash als Escape-Zeichen zu nutzen, kein "@" vor den string setzen. AFAIK ist das @ für 'faule' Verzeichnisangaben, wo Du dann nur einen Backslash für die Verzeichnistrennung angeben musst:
@"C:\Programme\..." ist das gleiche wie "C:\\Programme\\..."
Dass mit "@" der Backslash in \" nicht ersetzt wird ist nur folgerichtig.
Das mit dem "Suchen" wird wohl intern passieren (beim Zusammenbau des Streams) und hat vielleicht sogar mit der Ersetzung der Anführungszeichen zu tun. Und: nein, ein paar hundert Bytes sind sicher kein Problem.
Vielleicht probierst Du mal einen XmlWriter aus, um den SOAP-Text zu erstellen; oder - falls das in der 2005er Version schon verfügbar ist - die System.Xml.Linq Klassen XElement und XAttribut (ab .Net 3.5).
Gruß
Jürgen- Bearbeitet Jürgen Röhr Montag, 25. Februar 2013 10:45
-
Hey,
danke für die gute Hilfe!
Ich habe es nun einen WebService hinzugefügt, der auf die SOAP Schnittstelle referenziert. Das Ding ist jetzt unter App_WebServices eingebunden (danke für den Tipp!). Frage ist, wie nutze ich das Teil. Gibt es eine gute Anleitung dazu irgendwo?
http://msdn.microsoft.com/en-US/library/6h0yh8f9(v=vs.80).aspxMuss ich den WebService wie auf MSDN erklärt ist aufrufen? Wie verfahre ich dann weiter? Ich möchte ja meine Daten an den Webservice senden. Gibt es eine Seite, wo es genauer erklärt wird, wie man die dann produktiv einsetzt?
LG
Ziggyyy -
Ich glaube es ist ein kleiner Durchbruch :>
sv3.ILTISAPI api = new sv3.ILTISAPI();
api.BeginInsertIncident(username, msg_id, "", "",windows_user, "BISS - Software Deployment", "", "", "NOT DETERMINED", "", "", "", "", "", "", "5 - BAU", " 3 - BAU", "", "Interface", "", "", "", "", "", "", AsyncCallback, Object asyncState);Wie gehe ich nun mit dem AsyncCallback und dem Object um? Als String kann ich ihn ja nicht nutzen.
Bei dem Aufruf setze ich beide auf null. Um den Request abzuschließen muss ich diese Methode nutzen:
public int EndInsertIncident(IAsyncResult asyncResult, out string msg);
Wie nutze ich nun den IAsyncResult ? Der Dateityp des Asyncresult ist mir auch noch ein rätsel.
LG
Ziggyyy
- Bearbeitet ziggyyy Montag, 25. Februar 2013 16:22
-
Hi,
in VS2010 (und 2008 war es auch so), kann man entscheiden, ob man asynchrone Aufrufe oder synchrone Aufrufe im Client generieren lassen will (Kontrollkästchen "generate async operations"). Du hast - falls Du die Wahl hattest - offenbar die async Version gewählt.
Dann musst Du als AsyncCallback eine Methode übergeben, die vom Client aufgerufen wird, wenn er 'fertig ist'. Diese Methode muss eine bestimmte Signatur haben und bekommt ein zusätzliches object übergeben - das ist "asyncState". "Fertig" kann auch bedeuten, dass erst ein Block von "n" abgearbeitet ist. In diesem Fall (bei ein paar hundert Bytes eher unwahrscheinlich) müsstest Du in der Methode den nächsten Block ababrbeiten (schau mal unter Asynchrones Aufrufen von synchronen Methoden nach). In diesem Zyklus baust Du Dir Dein Ergebnis zusammen. Nach dem letzten Block wird dann die Methode EndInsertIncident aufgerufen.
Das ist alles ziemlich hardcore. Darum kann es sinnvoll sein, dass Du die Konfigurationsseite des WebServices (RMT und "configure service reference" bei mir) noch mal anschaust und das Häkchen entfernst. Dann bekommst Du mit InsertIncident eine synchrone Methode mit dem ganzen Parameterschwanz (ohne die beiden async...s), die die WebService-Funktion "InsertIncident" aufruft und zurückgibt, was immer dort als Rückgabe definiert ist.
Gruß
Jürgen -
Hallo Jürgen,
hier einmal die Definitionen der beiden Methoden.
public IAsyncResult BeginInsertIncident(string userName, string password, string MsgId, string ThirdPartyRef, string Type, string EmployeeId, string ShortDescription, string Details, string Category, string Service, string OwnerGrp, string OwnerRep, string SecondLevelGrp, string SecondLevelRep, string ThirdLevelGrp, string ThirdLevelRep, string Impact, string Urgency, string Priority, string Source, string Status, string State, string Solution, string ResolvedDate, string Cause, string Approved, AsyncCallback callback, object asyncState);
EndInsertIncident(IAsyncResult asyncResult, out string msg);
Die EndInsertIncident Methode gibt zurück, ob das Ticket erfolgreich angelegt worden ist.
Der Status von InsertIncidentCompleted steht immer auf null, weil ich die EndInsertIncident nicht aufrufe... :/
- Als Antwort markiert ziggyyy Donnerstag, 28. Februar 2013 11:27