Results for tag "xml"

CRM 2011 – Customizations.xml – Validieren!

Christian Wagnsonner 1 Comment

Ein Problem, das vielen vermutlich schon einige Produktivstunden gekostet hat, ist wohl das Erweitern bzw. Validieren der Solution-Customizations.xml-Datei. Wenn man da mal eine Menge an angepassten Entitäten drin hat, wird es schnell unübersichtlich und das Anpassen eine Tortur.

Am einfachsten hilft man sich, in dem man die Schema-Dateien (Teil der SDK) herunterlädt und im Visual Studio einbindet. Im Installations-Ordner der SDK befindet sich ein Ordner „schemas“. Öffnet nun einfach euer Visual Studio und bindet die Schema-Dateien mittels folgenden Schritten ein:

* XML –>
* Schemas… –>
* Add…

Und weil es mich gerade einiges an Zeit gekostet hat: Achtet auf die Sensitivity. Id != id.

Happy Programming!

WCF/Soap Service aus Javascript konsumieren

In einem aktuellen Projekt habe ich die Aufgabe bekommen, ein WCF Service zu erstellen, welches dann mittels Javascript konsumiert werden können soll.
Doch ein SOAP-Service aus Javascript konsumieren ist eine recht aufwendige Geschichte und die gefundenen Tutorials im Internet oft alles andere als einfach verständlich.

Um das Service anzusprechen, verwende ich einen XMLHttpRequest, welchem man einen SoapBody/XML und eine SoapAction mitgeben muss. Um das SOAP-XML nicht selbst produzieren zu müssen, was ja auch gar nicht so einfach wäre, habe ich SOAP UI (http://www.soapui.org/) verwendet. Dort müsst Ihr nur das WSDL des Service eingeben und bekommt für jede Methode, die euer Service zur Verfügung stellt, einen Request (welcher das XML enthält) erzeugt:

Hier seht Ihr auch schon das XML, welches Ihr in eurer JS-Methode verwenden könnt, z.B.:

[sourcecode language=“xml“]
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
<tem:Login>
<!–Optional:–>
<tem:organization>?</tem:organization>
</tem:Login>
</soapenv:Body>
</soapenv:Envelope>
[/sourcecode]

Die SoapAction findet Ihr, wenn Ihr euch euer WSDL anseht.

In meinem Beispiel lautet diese: http://tempuri.org/IAuthentication/Login

Nun geht’s ans Javascript. Ich habe mir hierzu eine kleine Helper-Klasse geschrieben.

[sourcecode language=“javascript“]
var Utils = new function () {

var Request = new XMLHttpRequest();
var fbFunction = null;

this.CallWS = function CallWS(soapHeader, feedbackFunction) {

// Create CRM Request
fbFunction = feedbackFunction;
var url = ‚http://localhost/crm.service/Operation.svc‘;

Request.open("POST", url, true);
Request.setRequestHeader("SOAPAction", soapHeader.SoapAction);
Request.setRequestHeader("Accept", "application/xml");
Request.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
Request.onreadystatechange = WSFinished;

Request.send(soapHeader.SoapXml);
}

function WSFinished() {

if (Request.readyState == 4) {

if (Request.status == 200) {

// parse webservice result
Result.Xml = Request.responseXML;
Result.ParseResult();
}
else {

Result.StatusCode = -2;
Result.StatusMessage = Request.responseText;
}
fbFunction(Result);
}
}
}

var SoapUtils = new function () {

var SoapHeader = new function () {
this.SoapXml = null;
this.SoapAction = null;
}

this.GetSoapHeaderForLogin = function (org) {
SoapHeader.SoapXml = "<soapenv:Envelope xmlns:soapenv=’http://schemas.xmlsoap.org/soap/envelope/‘ xmlns:tem=’http://tempuri.org/‘><soapenv:Header/><soapenv:Body><tem:Login><tem:organization>" + org + "</tem:organization></tem:Login></soapenv:Body></soapenv:Envelope>";
SoapHeader.SoapAction = "http://tempuri.org/IAuthentication/Login";
return SoapHeader;
}

}
[/sourcecode]

Der Aufruf sieht dann wie folgt aus:

[sourcecode language=“javascript“]
var header = SoapUtils.GetSoapHeaderForLogin("xyz");
Utils.CallWS(header, LoginFinished);
[/sourcecode]

Nachdem ich diese Webservice-Methoden mehrmals in meinem Projekt aufrufen muss, habe ich das SoapXML und die SoapAction in eine eigene Methode gepackt (SoapUtils), welche ich mittels SoapUtils.GetSoapHeaderForLogin("xyz"); aufrufe. Die zurückgelieferte Informationen gebe ich dann der CallWS-Methode mit (Utils.CallWS(header, LoginFinished);) und gebe zudem als zweiten Parameter eine Methode bekannt, welche aufgerufen werden soll, sobald der Webservice-Call fertig ist.

Wichtig: Ein Webservice-Aufruf ist immer asynchron! Es gibt zwar Spielereien (ähnlich Thread.Sleep() in C#), diese sollten jedoch erfahrungsgemäß nicht verwendet werden.

Wenn Ihr euch den Source-Code genauer anseht, werdet Ihr feststellen, dass ich in der Methode „CallWS“ dem Request.onreadystatechange-Event subscribed habe. In der Methode WSFinished() prüfe ich nun State des Requests und Status des Requests und erzeuge ein Result-Objekt, welches ich der Feedback-Funktion (übergeben bei CallWS) retour liefere. Hier seid Ihr selbst gefordert, euer Webservice wird naturgemäß andere Resultate erzeugen als meines.

Ich hoffe, ich konnte euch ein wenig weiterhelfen 🙂

Cheers,
Chris