SgDotNet
Singapore Professional .NET User Group -For Cool Developers

Using Paladin with WebServices

rated by 0 users
This post has 6 Replies | 0 Followers

Top 200 Contributor
Posts 7
Robert Posted: 09-19-2005 5:35 PM

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:

  • 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

 

This one is working rigth and I can using it from my remote Winform and move the result to the form fields:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim ws As New DAL_WS.Service1

Dim cust As DAL_WS.Customer

cust = ws.Paladin_Customers_Read(CustomerID.Text)

CompanyName.Text = cust.CompanyName

ContactName.Text = cust.ContactName

...

End Sub

 

  • 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

Top 10 Contributor
Posts 1,626

You are very brave to try Paladin on web services. Yes [Y]

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:

using Paladin.Framework;

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.

 

Software development made easy with Paladin RAD Framework. Save some trees, use Stickies.NET
Top 200 Contributor
Posts 7

Thanks a lot for your fast answer.

Now is working.

In VB:

Web Service Method:

<WebMethod()> Public Function Paladin_Customers_List() As String

Try

Dim catList As New CustomersList

Dim bc As New BusinessComponent

bc.Populate(catList)

Return Serializer.GetXml(catList)

Catch ex As Exception

Throw (ex)

Finally

End Try

End Function

 

Consumer:

Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button6.Click

Dim cust_List As New CustomersList

Dim ws As New DAL_WS.Service1

Dim sr As New System.IO.StringReader(ws.Paladin_Customers_List)

cust_List = Paladin.Framework.Serializer.ReadXml(sr, GetType(CustomersList))

DataGrid1.DataSource = cust_List

End Sub

 

Top 10 Contributor
Posts 876

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

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

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 Wink [;)] 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"

Top 10 Contributor
Posts 1,626

Softwaremaker,

Results returned from a Paladin Entity object via wsdl:

  xml version="1.0" encoding="utf-8" ?>
- <Category xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/">
  <AutoLoadParent>falseAutoLoadParent>
  <AutoLoadChildren>falseAutoLoadChildren>
  <Forums />
  <CategoryID>158CategoryID>
  <Sequence>1Sequence>
  <Name>Test StoredProcName>
  <Description>Test DescriptionDescription>
  <CreatedDate>2005-07-19T22:46:30.3130000+08:00CreatedDate>
  <CreatedBy>0CreatedBy>
  <ModifiedDate>0001-01-01T00:00:00.0000000+08:00ModifiedDate>
  <ModifiedBy>0ModifiedBy>
  <IsDeleted>falseIsDeleted>
  <DeletedDate>0001-01-01T00:00:00.0000000+08:00DeletedDate>
  <DeletedBy>0DeletedBy>
  Category>
 
Results returned from an Entity List object:
 
 <?xml version="1.0" encoding="utf-8" ?>
- <ArrayOfCategoryBase xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/">
- <CategoryBase xsi:type="Category">
  <AutoLoadParent>false</AutoLoadParent>
  <AutoLoadChildren>false</AutoLoadChildren>
  <Forums />
  <CategoryID>158</CategoryID>
  <Sequence>1</Sequence>
  <Name>Test StoredProc</Name>
  <Description>Test Description</Description>
  <CreatedDate>2005-07-19T22:46:30.3130000+08:00</CreatedDate>
  <CreatedBy>0</CreatedBy>
  <ModifiedDate>0001-01-01T00:00:00.0000000+08:00</ModifiedDate>
  <ModifiedBy>0</ModifiedBy>
  <IsDeleted>false</IsDeleted>
  <DeletedDate>0001-01-01T00:00:00.0000000+08:00</DeletedDate>
  <DeletedBy>0</DeletedBy>
  </CategoryBase>
-- <CategoryBase xsi:type="Category">
  <AutoLoadParent>false</AutoLoadParent>
  <AutoLoadChildren>false</AutoLoadChildren>
  <Forums />
  <CategoryID>369</CategoryID>
  <Sequence>1</Sequence>
  <Name>Test StoredProc</Name>
  <Description>Test Description</Description>
  <CreatedDate>2005-08-01T21:59:13.3900000+08:00</CreatedDate>
  <CreatedBy>0</CreatedBy>
  <ModifiedDate>0001-01-01T00:00:00.0000000+08:00</ModifiedDate>
  <ModifiedBy>0</ModifiedBy>
  <IsDeleted>false</IsDeleted>
  <DeletedDate>0001-01-01T00:00:00.0000000+08:00</DeletedDate>
  <DeletedBy>0</DeletedBy>
  </CategoryBase>
- <CategoryBase xsi:type="Category">
  <AutoLoadParent>false</AutoLoadParent>
  <AutoLoadChildren>false</AutoLoadChildren>
  <Forums />
  <CategoryID>380</CategoryID>
  <Sequence>1</Sequence>
  <Name>Test StoredProc</Name>
  <Description>Test Description</Description>
  <CreatedDate>2005-08-03T21:11:13.0000000+08:00</CreatedDate>
  <CreatedBy>0</CreatedBy>
  <ModifiedDate>0001-01-01T00:00:00.0000000+08:00</ModifiedDate>
  <ModifiedBy>0</ModifiedBy>
  <IsDeleted>false</IsDeleted>
  <DeletedDate>0001-01-01T00:00:00.0000000+08:00</DeletedDate>
  <DeletedBy>0</DeletedBy>
  </CategoryBase>
  </ArrayOfCategoryBase>
Software development made easy with Paladin RAD Framework. Save some trees, use Stickies.NET
Top 10 Contributor
Posts 876

Firedancer:

Can u show the wsdl as well ? Thanks.

~Softwaremaker (BLOG) M. Twain: "I didn't have time to write a short letter, so I wrote a long one instead"

Top 10 Contributor
Posts 876

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.

~Softwaremaker (BLOG) M. Twain: "I didn't have time to write a short letter, so I wrote a long one instead"

Page 1 of 1 (7 items) | RSS
Copyright SgDotNet 2004-2009
Powered by Community Server (Commercial Edition), by Telligent Systems