I have been testing Paladin and I found it very easy to generate and to use in the basic level I am now.
I have generated with BEWizard the Paladin classes, using Northwind, and several tables, (Customers, Orders,...). I have created a very simple Winforms application to test it and I am able to translate the Customers entity and entitylist to one WinForm binding it to several fields and a datagrid.
Now I would like to extend the sample to use Paladin from a Web Service. So I add the Paladin references to my Web Service and create two methods:
Dim cust As New Customer
cust.CustomerID = Customer_Id
Dim bc As New BusinessComponent
Return
End
This one is working rigth and I can using it from my remote Winform and move the result to the form fields:
cust = ws.Paladin_Customers_Read(CustomerID.Text)
CompanyName.Text = cust.CompanyName
ContactName.Text = cust.ContactName
...
Dim
bc.Populate(catList)
But now when I tried to move the return to one datagrid, (as I already did in the local sample):
DataGrid1.DataSource = ws.Paladin_Customers_List()
The datasource is not showing the data, as the result received is really one array.
How can I obtain the list collection through the Web Service?
Thanks in advance
Roberto
You are very brave to try Paladin on web services.
I'm not really an expert in web services and I designed the objects following the advice from an expert in this forum - Softwaremaker. Perhaps, he can explain whether the behaviour is correct or do I need to implement something extra to make it work.
For the moment, I've came out with a quick hack for you. Change your WebService method to expose a string instead of CustomersList. i.e.
using Paladin.Framework;
[WebMethod]public string GetList(){CustomersList custList = new CustomersList ();BusinessComponent bc = new BusinessComponent();bc.Populate(custList);
// Serialize to XML.return Serializer.GetXml(custList);}
On the consuming end, change your code to:
private void Button1_Click(object sender, System.EventArgs e){localhost.Service1 svc = new localhost.Service1();System.IO.StringReader reader = new System.IO.StringReader(svc.GetList());CustomersList custList = (CustomersList)Paladin.Framework.Serializer.ReadXml(reader, typeof(CustomersList));
DataGrid1.DataSource = custList;DataGrid1.DataBind();
}
Please take note that in your original code, the Customer object that you received from the web service is not a Paladin Entity object. It is just a class generated from the serialized XML that looks like an Entity object. If you try to use it with a BC, it will not compile.
The Entity and EntityList objects are meant to be simplified when crossing the wires so that other consumers such as those implemented in Java or other languages who doesn't know about Paladin can consume it easily.
Thanks a lot for your fast answer.
Now is working.
In VB:
Web Service Method:
<WebMethod()>
Consumer:
Private
cust_List = Paladin.Framework.Serializer.ReadXml(sr,
DataGrid1.DataSource = cust_List
First thing first, it was generally not good practice to expose your business layer directly through a web service (ws). ASMX is best used as a facade layer which marshals the XML crossing from the client to the middle layer. In this case, your object layer can change as much as possible without affecting the contracts that your clients are bound to. Also, infrastrucutre-level like functionality such as security, reliability and transactions are to be handled by the s:headers which shld be abstracted away from your business logic (Paladin).
Do remember one of the key tenets of good principles of Service-Orientation design --- The need to be Explicit. (That you are crossing boundaries and That you need to know what is ON THE WIRE)
Having said that, I am not an expert on Paladin so let me see how I can do to best decipher your situation. First of, do show what Paladin publishes as the WSDL. Without seeing that, I have no idea how Paladin exposes itself to the world.
Robert wrote:The first is just returning the Customer class generate by Paladin for one customer: Public Function Paladin_Customers_Read(ByVal Customer_Id As String) As Customer Dim cust As New Customer cust.CustomerID = Customer_Id Dim bc As New BusinessComponent Return cust End Function
Return cust
End Function
Again, I have no idea how Paladin looks like on the wire and thats why you shld be more explicit to the bound clients to how you want the msg to look like when they come in. Middle-layer objects usually expose proprietary like behaviours to connecting components (such as ADO.NET Datasets) because this is a much more optimized way of doing so. However, your web service facade should expose a marshalling layer that maps 1:1 from a more general interoperable schema to a more proprietary and hence more optimized one.
From your first function below, the best interoperable result would be to see this on the wire:
[SomePieceOfXMLBlob] [Name]Softwaremaker[/Name] [Age]88[/Age][/SomePieceOfXMLBlob]
Robert wrote:The second is returning the Customerlist class generate by Paladin for customers list:Public Function Paladin_Customers_List() As CustomersList Dim catList As New Business.Entities.CustomersList Dim bc As New BusinessComponent bc.Populate(catList) Return catList End Function But now when I tried to move the return to one datagrid, (as I already did in the local sample): Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click Dim ws As New DAL_WS.Service1 Dim cust_list As New CustomersList DataGrid1.DataSource = ws.Paladin_Customers_List() End Sub The datasource is not showing the data, as the result received is really one array. How can I obtain the list collection through the Web Service? Thanks in advance Roberto
Dim catList As New Business.Entities.CustomersList
Return catList
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim ws As New DAL_WS.Service1
Dim cust_list As New CustomersList
End Sub
For this scenario, what does the wire-format look like for a inherited Paladin List ? Do take a peek inside what shows on the wire VS the contract the List is exposing itself to the world through WSDL.
For best interoperability scenarios, this would be the best thing on the wire:
[PiecesOfXMLBlob] [PieceOfXMLBlob] [Name]Softwaremaker[/Name] [Age]88[/Age] [/PieceOfXMLBlob] [PieceOfXMLBlob] [Name]Firedancer[/Name] [Age]45[/Age] [/PieceOfXMLBlob] [PieceOfXMLBlob] [Name]Icelava[/Name] [Age]2[/Age] [/PieceOfXMLBlob][/SomePiecesOfXMLBlob]
Again, this would be the best way to move forward. Databinding as such are great for proprietary protocols such as datasets, etc. Therefore, winforms are great for such activites. Once you deal with IUnknown over the web, you shouldnt bind directly to what pops out from underneath the wire. So the next best thing is to churn out interoperable messages. The world made a big mistake of treating SOAP and Web Services like RPC and by directly binding to it, you are doing RPC Sometimes, deserializing the message as an XML DOM and then doing a 1:1 mapping is the best way forward.
Again, do show what the WSDL look like and what the messages look like as well. You will be able to tell why you cannot data-bind to it.
Firedancer: This could be some prescriptive guidelines for Paladin. It is a business object layer. It should be treated and used by everyone like one.
hth.
~Softwaremaker (BLOG) M. Twain: "I didn't have time to write a short letter, so I wrote a long one instead"
Softwaremaker,
Results returned from a Paladin Entity object via wsdl:
Firedancer:
Can u show the wsdl as well ? Thanks.
From first looks into the soap traces, it seems like you are using CollectionBase.
My personal view is that my preference is not to use any of the .NET proprietary's classes and collections via a web service for interoperability.
If you looked at your client-proxy classes, I believe you would see Public Name as String or something ... and that is where the problem is. The runtime has changed the properties to fields and thats why you cannot bind it to a datagrid. Datagrids need properties
Having said that:- Take a look at this. Of course, you could bind your datagrid to a CollectionBase type as well. There is this good piece here that may require you to sign-on. So, from what I see, there shld be no problems binding the soap messsages to the datagrid provided you do it right. Again, refer to this article.
There is another good article here that talks about the merits of a facade here and it will explain why binding to a CollectionBase over a Web Service may not work intuitively and introduce workarounds to it.
My recommendation is that the removal of RPC-like constructs should be removed from the message. Therefore, a facade layer should do a mapping properly. This will also insulate the paladin business layer if it changes (which it will). This should be done at the service side to minimize any performance lags on the receiving client-end.
It is 0400 hours in the morning. I have been working very hard since 0200 hours. Forgive me if I dont make any sense here.