Using the same Business Objects in Winforms Client and WebService

Using the same Business Objects in Winforms Client and WebService

Old forum URL: forums.lhotka.net/forums/t/1803.aspx


Sean D posted on Tuesday, November 21, 2006

Hi,

I'm currently developing an application for SmartClient wherein I must call a webservice to access my database.

I would like to have the business objects seamless to the user. That is, if the user calls Project.GetProject(id), the class will call the webservice to access the database, and populate the instance. No problem there, my DataPortal_XYZ methods simply call a webservice.

However, to make things simpler for the developers, I'd like to use the same classes when developing the webservice.This webservice is NOT a data portal. I'm not using WS instead of remoting.

That is, Project.GetProject(id) when called on the client, will call the underlying WS layer, whereas in the ASP.NET Webservice, it will access the database.

I will be using classes akin to ProjectData (From Chapter 11), to return the data.

Has anyone tried this?

I'm using the MS ServiceInterface pattern for my service, and would like to also implement that interface on the client. This will provide the consistency that I need, and hopefully not at the cost of complexity.

Many thanks,

Sean

 

Bayu replied on Tuesday, November 21, 2006

Sean D:

That is, Project.GetProject(id) when called on the client, will call the underlying WS layer, whereas in the ASP.NET Webservice, it will access the database.



Just to make sure I understand you correctly:

You have one smart-client app:
- winforms UI
- which calls a webservice to fetch BOs
- and the webservice calls your DB to fetch data

And you have a web app:
- webforms UI
- which directly calls the DB to fetch BOs ..?

Isn't it true that in both cases your BOs need to populate themselves from the DB?

I don't understand what you mean by 'my DataPortal_XYZ methods simply call a webservice'. Why don't you use the App.Config file to tell CSLA that your BOs should fetch their data through a webservice? In that case, your DataPortal_XYZ methods could be programmed to fetch data using ADO.Net, and the CSLA dataportal will take care of the Webservice part.

Maybe I did not fully understand your challenge, let me know if you need more info.

Regards,
Bayu

Sean D replied on Tuesday, November 21, 2006

Hi,

I have a Winforms app only. I;m developing an ASP.NET WebService. I can't use the DataPortal as a webservice (CRUD functions). My webservice may be used by other apps.

However, when I use the webservice from my application (Winforms), I'd like to use the same class library that I used in the actual webservice. When the static methods, e.g. GetProject(), are called on the client, the DataPortal_XYZ methods will call the webservice, and when the same methods are called in the webservice gateway, the methods will access the database via ADO.NET.

I would like to use the webservice dataportal to create, update, etc from my client, but that's not an option, as future clients will be unaware of this functionality, and will access the webservice methods directly. These will be methods like GetProject(), GetProjectList(), and will return typed data (that's described in the WSDL).

I hope that clarifies things somewhat.

Thanks,

Sean

SonOfPirate replied on Tuesday, November 21, 2006

It seems to me (and trust me, I am no expert as I am only now venturing into this area myself), that the only conflict that you have is differentiating the call on the client which is to pass the request onto the web service and the call on the server that is to perform the data access and return the desired BO. Isn't this handled by the web service itself?

What I mean is, when you call Projects.GetProjectList() on the client, even though it seems like you are calling your BO directly, you are calling a proxy created for your web service.  The web service handles the fact that this call has occurred on the client and passes the call onto the server-side web service.  The body of the method actually executes on the server so you can easily implement whatever data access code you need - in fact, this is where you would implement the data portal to allow for a distributed architecture on the server(s).

As such, your application is actually entirely on the server.  What you have done is exposed a service interface, via the web service to allow client applications to hook into the application.

Now, the catch is, at least as far as my knowledge goes, is determining the proper way to work with the returned objects.  The "object" that is returned from the web service is coming across in an XML serialized format.  So, the proxy should be able to deserialize the stream into the BO on the client so that it can be used as expected.  You'll just have to have the client app reference the class library that contains the class definitions.

Oh, one other thought, to simplify the logic we are considering that it might be easier to use a factory to serve as the interface to the WS rather than the BO.  So, instead of Projects.GetProjectList(), we would have ProjectFactory.GetProjectList() where ProjectFactory is the WS proxy and the method returns a ProjectList BO.  This separates the web service part from the BO.

Hope that helps.  I am interested in how you proceed.  As I said, I am just delving into this approach myself.

 

Sean D replied on Tuesday, November 21, 2006

Hi guys,

Thanks for the feedback.

Let me try and make an analogy to the ProjectTracker examples.

I'm using the PTWebService ASP.NET WebService.

My client (PTServiceClient in this case) currently calls the PTService.GetProjectList() webservice method, that returns an array of ProjectData.

What I want to do, in PTServiceClient, is to have access to the Library classes, and just call call ProjectList.GetProjectList(). This will then call the WS method, which returns the ProjectData array, which then populates the ProjectList with Projectinfo structures.

This might seem like overkill, but it gives me the options I need on the ASP.NET WebService. That is, the service can be used by other applications that don't use the Library.

Does this make sense? I could, I suppose, put some code in the ProjectList::dataPortal_Fetch to determine the context (i.e. WinForms, or WebService), and execute the WS or ADO.NET code accordingly. does that seem like a reasonable approach?

Thanks,

Sean 

Bayu replied on Tuesday, November 21, 2006

Sean D:

I would like to use the webservice dataportal to create, update, etc from my client, but that's not an option, as future clients will be unaware of this functionality, and will access the webservice methods directly. These will be methods like GetProject(), GetProjectList(), and will return typed data (that's described in the WSDL).



Ahhhhh, now I get it. ;-)

The solution is simple: have 2 webservices ....
- one that hosts the dataportal and provides CRUD functionality
- another one that you expose to the external world and provides all your GetProject, GetProjectList, etc. functions

This would nicely deal with all your scenarios:
- your BOs can forget about webservices, all you program in the dataportal_xxx methods is ADO.net code that allows a BO to populate itself from the DB
- in your Winforms app you configure the app.config file so CSLA uses the webservice as dataportal host
- you do the same in your public (non-dataportal) webservice
- and for this latter webservice you can define whatever methods you like (GetProject, GetProjectList etc) and all your method bodies would contain just 1 line of code I guess that invokes the factory method of the particular BO


Thinking about it, this also yields nice benefits for your security as you can fully lock-up the dataportal webservice with all the CRUD functionality on the one hand, and on the other hand you are in full control of what functionality you expose publicly in the second webservice.

Does this solve it?

Bayu


ajj3085 replied on Tuesday, November 21, 2006

Sean,

Regarding your web service.  Your web service should use the BOs just as your winforms app would.  In effect, your web service should provide a facade.  Now, you should NOT expose your BOs to clients of the web service.  If you do this, you couple the interface of your service to the interface of your BOs, and every change to your BOs will break any clients using your web service... and thats exactly the opposite of what you want to have happen.

Regarding your WinForms application.  Have it use the BOs directly just as it has been doing.  There's absolutely no good reason an application which you have control over to use a web service to talk to a business layer which you also have control over.  The business layer may use Web services to talk to the database (which would be the WSDataPortal), but you've indicated you do not want to do that.  So there really is no reason at all to use Web services from within your WinForms application.  If you have the WinForms use the Web service you're exposing to clients you're just adding unnecessary overhead and complexity and you gain nothing.

HTH
Andy

Sean D replied on Tuesday, November 21, 2006

Hi guys,

Thanks for the excellent feedback. I've tried the following, and it works. But, its not the nicest of solution:

In ProjectList::DataPortal_Fetch() I do the following:

System.Web.HttpContext l_Context = System.Web.HttpContext.Current;

if (l_Context == null) // We're not in a WS or Web App

{

using (PTService.PTService svc = new PTService.PTService())

{

this.IsReadOnly = false;

foreach (ProjectData l_Project in svc.GetProjectList())

this.Add(new ProjectInfo(l_Project.Id, l_Project.Name));

this.IsReadOnly = true;

}

}

else

{

using (SqlConnection cn = new SqlConnection(Database.PTrackerConnection))

{

cn.Open();

using (SqlCommand cm = cn.CreateCommand())

.

.

Rest of existing code......

}

In the PTWebService, ProjectList.GetProjectList()  is called as normal.

In the PTWin application, I call ProjectList.GetProjectList() - This now calls the PTWebService (as in the above code)...

My problem here is that a) theres a reference from the ProjectTracker.Library to the PTService, and b) if the ProjectList object is called from an ASP.NET application, it will alway call the ADO.NET directly.

This is the kinda thing I'm trying to do. I don't really want to do it this way though. Any ideas?

Many thanks,

Sean

Sean D replied on Tuesday, November 21, 2006

One final thing.

I dont want to use the WebServicePortal, because I don't want objects being created and passed around the network at this time with neither Remoting nor SOAP/WS.

However, I might be changing to either .NET Remoting host, or webservice host at a later date.

Currently,  CSLA.NET is configured for local dataportal only. But, as per my changes in the previous post, it calls an ASP.NET webservice (NOT the portal).

Regards,

Sean

ajj3085 replied on Tuesday, November 21, 2006

Sean,

It looks like what you want is a DAL that abstracts away your data access, so that you have objects which represent tables or views, but you don't know the underlying database.

Look into NHibernate if that's what you're trying to do.  That way your web service has a certain configuration which will get its data from a web service, and your forms app will have another configuration file that uses Sql server directly.

I must admit though I'm note sure if NHibernate supports a 'web service database,', so you may have to roll your own.. but the concept is the same.

Andy

Sean D replied on Monday, November 27, 2006

Thanks everyone for your excellent responses. I've come to a solution to my predicament.

I am going to share my objects library between the webservice, and the client (winforms). The data access methods' implementation will be configured using a factory. The factory, configured from the config file, creates one implementation that calls the webservice methods, and the other implementation that calls the ADO.NET implementation.

Effectively, my webservice is simply an added layer of communication. I will be testing the use of  the Remoting Data Portal, and WebServices data portal to see if the overhead of passing the objects round the network is minimal enough to remove my webservices comms layer.

Regards,

Sean

Copyright (c) Marimer LLC