It is possible to use a complex datatype as input for webservices in NAV2009 by using XMLport. But is it also possible to use complex datatype as return value? It isn't possible to use XMLport as return value.
It wouldn't really make sense to return a NAV specific, internal object type in a webservice, unless you're thinking about creating some sort of object control.
Hi Denster,
It make sense to me. If you want to create a webservice for consumers of a webservice the interface/contract for the request and response must be known. It is now possible to use an XMLport as input parameter of a codeunit function (as a complex type). This is a great start, but it isn't possible yet to define the datatype as easy (date, int, etc.) But if you create an XMLPort to export serveral data from Navision, this XMLport should also be used (in my opinion) to define the contract of the webservice response.
Other question:
What can I do in Navision to define the response interface/contract if the response exist of serveral values/elements?
Maybe I haven't understood the problem correctly, but can't you just set the XML port as VAR parameter?
I remember having done something like that earlier, this way I can retrieve multiple data in my VS app.
The information in this post is provided "AS IS" with no warranties, and confers no rights. This post does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion.
An XMLPort is an internal NAV object type that processes XML Documents. You would have to have a NAV client to be able to work with an XMLPort. The XMLPort itself does not contain any data, it's an object. I still don't get how useful this can be. What use is an XMLPort for any external source?
Say you have a webservice that checks the spelling. You wouldn't send the spellchecker itself as a data type, but spellchecked data. Similarly in NAV, you wouldn't send the XMLPort itself, but the XML Document that it processes.
It isn't the type XMLPort you get out - it is the XML Document which the XML Port outputs - meaning that the XMLport is executed and you get the result as output. I will find my sample and post it.
The information in this post is provided "AS IS" with no warranties, and confers no rights. This post does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion.
It is possible to use a complex datatype as input for webservices in NAV2009 by using XMLport. But is it also possible to use complex datatype as return value? It isn't possible to use XMLport as return value.
The purpose of this post is not to return an XMLPort, but i want to define the schema (XSD) definition for the WSDL for the response message of the webservice. It is now possible to define the structure for the request in an XMLPort. If the XMLPort is then used as parameter of a function then the WCF recognize the structure in de XMLPort and use this structure in de WSDL. This is very nice, but is this also possible for the response message?
I'm afraid that I don't know what you mean . You said you can use a complex datatype, an XMLPort, as a parameter, and then you asked if it was possible to return a complex datatype. To me that implied that you were asking to return an XMLPort in a webservice.
I wasn't aware that an XMLPort could be sent into a webservice (I probably misunderstood that part too), and I still don't see how that could possibly be of any use to anyone, since it is an internal NAV specific object type. You are first talking about using an XMLPort as a parameter, and then you say that it only defines the structure of the request. That confuses me. I don't know whether you mean using an XMLPort as the actual parameter or the structure of the XML Document that is defined BY the XMLPort.
I can see how you can structure XML that is accepted by a webservice by way of an XMLPort, and should also be available for the other way around. How that all ties into eachother though I have no clue. But again I apparently don't understand what you said in the first place. Sorry, can't help you on this one
getXMLPort(VAR MyCustomers : XMLport WSTestCustomer)
BEGIN
cust.FINDFIRST();
cust.SETRANGE(cust."No.", '10000', '20000');
MyCustomers.SETTABLEVIEW(cust);
END
Where WSTestCustomer is an XML port defined as:
Node Name Node Type Source Type Data Source
MyXMLCusts Element Text <Customers>
MyXMLCust Element Table <Customer>(Customer)
No Element Field <Customer>::No.
Name Element Field <Customer>::Name
Bookmark Element Text Bookmark1
Then this will result in the following function definition in the WSDL:
and when you look at this from Visual Studio you can do like this:
WSTest1.MyXMLCusts myXMLcusts = new WSTest1.MyXMLCusts();
test.GetXMLPort(ref myXMLcusts);
foreach (WSTest1.MyXMLCust myXMLcust in myXMLcusts.MyXMLCust)
{
// Do Stuff
}
But you could also fill out the myXMLcusts before calling the function and send stuff into the XML Port.
So as I tryed to explain earlier - the XML Port isn't exposed, but the schema of the XML Port is.
and if you put VAR on the XML Port - you will get the result of the XML Port back.
The information in this post is provided "AS IS" with no warranties, and confers no rights. This post does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion.
However, what I was not able to accomplish is to have some control on the xmlport from visual studio. It would be for example great to dynamically pass the filter(-string) to the xmlport/codeunit instead of having it hard-coded in the codeunit. Is this possible? I tried the "normal" NAV-way and created a second function in my published Codeunit that is exposing the XMLPort whereas this function just stored the filter in a global variable. Unfortunately, the value seems to be lost when the GetXMLPort-Method is run - even after changing the codeunit to singleInstance = true.
The C#-Code looks like:
CustomerWS.Customers myXMLCusts = new CustomerWS.Customers();
custWS.SetFilter("10000");
custWS.GetXMLPort(ref myXMLCusts);
foreach (CustomerWS.Customer myXMLcust in myXMLCusts.Customer)
{
label1.Text = myXMLcust.Name;
}
Oh, that was easier than expected. I did not realize that the GetXMLPort-function could just get additional parameters such as my filter-string...
Yet, I would still love to know if it is possible to store/persist values on the middle-tier in between multiple calls of a single client.
Thanks,
Jut
You can store them in a table and the client must identify the session somehow (e.g. using same guid as a parameter when calling the functions - something like corelation ID)
Is it possible to render the result sent back to for example the .NET application into a Dataset? Rather than having to travers each table/node by a loop, like in the example:
WSTest1.MyXMLCusts myXMLcusts = new WSTest1.MyXMLCusts();
test.GetXMLPort(ref myXMLcusts);
myXMLcust.ToString() //This needs to be converted to a stream so it can be read by the dataset, but it only returns WSTest1.MyXMLCusts
System.IO.Stream s = null;
s.Read(*****);
Dataset ds = new Dataset();
ds.ReadXML(s)
I've setup my function in Nav to use BigText as a var parameter instead. Then I use the new TempBlob table to fill the BigText variable with the XMLPort content.
Then I use memorystream and text encoding in my .NET application to be able to use the "ds.ReadXML()" . It work's lik a charm, and using the memorystream felt like the whole application became faster ..
I was not doing any of the filtereing. I suppose you called your function in Nav for "ReadMultiple"? I was just calling my webservice function with the root element of the xmlport as parameter, and then setting that parameter as the datasource. Also I was trying with GridView rather then Listbox.
Ok, the difference is that I have used the Page as source, but you your own function with XMLPort. Than you need to do some transfer from the result into different class like some List or DataSource, which could be used as datasource for ListBox or Grid.
I'm happy with using BigText for now since it was read easily into a dataset. Then I could continue to use the rest of my code that was earlier developed to be used against MSMQ.
If using Page wouldn't you narrow down the result to just one table?
Here is part of my Project if anyone is interested:
XMLPort in Dynamics Nav:
Webservice Codeunit beeing exposed:
OBJECT Codeunit 50007 My Invoices
{
OBJECT-PROPERTIES
{
Date=03.09.10;
Time=09:52:47;
Modified=Yes;
Version List=;
}
PROPERTIES
{
OnRun=VAR
bt@1000000000 : BigText;
BEGIN
END;
}
CODE
{
VAR
tblCustomer@1000000000 : Record 18;
PROCEDURE GetMyInvoices@1000000001(VAR xmlBT@1000000000 : BigText;PartnerID@1000000001 : Integer;AccountID@1000000006 : Text[30]);
VAR
xmlMyInvoicesData@1000000002 : XMLport 50000;
tblTempBlob@1000000003 : TEMPORARY Record 99008535;
oStream@1000000004 : OutStream;
iStream@1000000005 : InStream;
BEGIN
tblTempBlob."Primay Key" := 1;
tblTempBlob.INSERT;
tblTempBlob.Blob.CREATEOUTSTREAM(oStream);
tblCustomer.SETCURRENTKEY(" Partner ID"," Account ID");
tblCustomer.SETRANGE(" Partner ID",PartnerID);
tblCustomer.SETRANGE(" Account ID",AccountID);
xmlMyInvoicesData.SETTABLEVIEW(tblCustomer);
xmlMyInvoicesData.SETDESTINATION(oStream);
xmlMyInvoicesData.EXPORT;
tblTempBlob.MODIFY;
tblTempBlob.CALCFIELDS(Blob);
tblTempBlob.Blob.CREATEINSTREAM(iStream);
xmlBT.READ(iStream);
END;
BEGIN
END.
}
}
In Visual Studio the Code look like this:
int partnerId = Int32.Parse(Request.QueryString.Get("partnerid"));
String accountId = Request.QueryString.Get("accountid");
CPSMyInvoices myInvoicesService = new CPSMyInvoices();
NetworkCredential credentials = new NetworkCredential("***", "***", "***");
myInvoicesService.Credentials = credentials;
myInvoicesService.PreAuthenticate = true;
string xmlBT = "";
myInvoicesService.GetMyInvoices(ref xmlBT,partnerId,accountId);
byte[] byteArray = new byte[xmlBT.Length];
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byteArray = encoding.GetBytes(xmlBT);
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(byteArray);
ds.ReadXml(memoryStream);
DataSet dsCustomer = ds;
if (dsCustomer.Tables.IndexOf("Customer") != -1)
{
and then you can do what you want :)
Comments
RIS Plus, LLC
It make sense to me. If you want to create a webservice for consumers of a webservice the interface/contract for the request and response must be known. It is now possible to use an XMLport as input parameter of a codeunit function (as a complex type). This is a great start, but it isn't possible yet to define the datatype as easy (date, int, etc.) But if you create an XMLPort to export serveral data from Navision, this XMLport should also be used (in my opinion) to define the contract of the webservice response.
Other question:
What can I do in Navision to define the response interface/contract if the response exist of serveral values/elements?
Kind regards
I remember having done something like that earlier, this way I can retrieve multiple data in my VS app.
Group Program Manager, Client
Microsoft Dynamics NAV
http://blogs.msdn.com/freddyk
The information in this post is provided "AS IS" with no warranties, and confers no rights. This post does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion.
Say you have a webservice that checks the spelling. You wouldn't send the spellchecker itself as a data type, but spellchecked data. Similarly in NAV, you wouldn't send the XMLPort itself, but the XML Document that it processes.
RIS Plus, LLC
Group Program Manager, Client
Microsoft Dynamics NAV
http://blogs.msdn.com/freddyk
The information in this post is provided "AS IS" with no warranties, and confers no rights. This post does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion.
RIS Plus, LLC
The purpose of this post is not to return an XMLPort, but i want to define the schema (XSD) definition for the WSDL for the response message of the webservice. It is now possible to define the structure for the request in an XMLPort. If the XMLPort is then used as parameter of a function then the WCF recognize the structure in de XMLPort and use this structure in de WSDL. This is very nice, but is this also possible for the response message?
Benno
I wasn't aware that an XMLPort could be sent into a webservice (I probably misunderstood that part too), and I still don't see how that could possibly be of any use to anyone, since it is an internal NAV specific object type. You are first talking about using an XMLPort as a parameter, and then you say that it only defines the structure of the request. That confuses me. I don't know whether you mean using an XMLPort as the actual parameter or the structure of the XML Document that is defined BY the XMLPort.
I can see how you can structure XML that is accepted by a webservice by way of an XMLPort, and should also be available for the other way around. How that all ties into eachother though I have no clue. But again I apparently don't understand what you said in the first place. Sorry, can't help you on this one
RIS Plus, LLC
Where WSTestCustomer is an XML port defined as:
Then this will result in the following function definition in the WSDL: with the following schema definition in the WSDL and when you look at this from Visual Studio you can do like this: But you could also fill out the myXMLcusts before calling the function and send stuff into the XML Port.
So as I tryed to explain earlier - the XML Port isn't exposed, but the schema of the XML Port is.
and if you put VAR on the XML Port - you will get the result of the XML Port back.
Group Program Manager, Client
Microsoft Dynamics NAV
http://blogs.msdn.com/freddyk
The information in this post is provided "AS IS" with no warranties, and confers no rights. This post does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion.
However, what I was not able to accomplish is to have some control on the xmlport from visual studio. It would be for example great to dynamically pass the filter(-string) to the xmlport/codeunit instead of having it hard-coded in the codeunit. Is this possible? I tried the "normal" NAV-way and created a second function in my published Codeunit that is exposing the XMLPort whereas this function just stored the filter in a global variable. Unfortunately, the value seems to be lost when the GetXMLPort-Method is run - even after changing the codeunit to singleInstance = true.
The C#-Code looks like:
CustomerWS.Customers myXMLCusts = new CustomerWS.Customers();
custWS.SetFilter("10000");
custWS.GetXMLPort(ref myXMLCusts);
foreach (CustomerWS.Customer myXMLcust in myXMLCusts.Customer)
{
label1.Text = myXMLcust.Name;
}
Thanks a lot in advance!
Jut
Yet, I would still love to know if it is possible to store/persist values on the middle-tier in between multiple calls of a single client.
Thanks,
Jut
MVP - Dynamics NAV
My BLOG
NAVERTICA a.s.
MVP - Dynamics NAV
My BLOG
NAVERTICA a.s.
"Unvalid type for datasource". It must be of type "IListSource,IENumerable or IDataSource"
MVP - Dynamics NAV
My BLOG
NAVERTICA a.s.
Then I use memorystream and text encoding in my .NET application to be able to use the "ds.ReadXML()" . It work's lik a charm, and using the memorystream felt like the whole application became faster ..
MVP - Dynamics NAV
My BLOG
NAVERTICA a.s.
MVP - Dynamics NAV
My BLOG
NAVERTICA a.s.
If using Page wouldn't you narrow down the result to just one table?
Here is part of my Project if anyone is interested:
XMLPort in Dynamics Nav:
Webservice Codeunit beeing exposed:
In Visual Studio the Code look like this:
And the result looks like this: