- Home
- LLBLGen Pro
- Architecture
Webservice architecture
Joined: 25-Jan-2006
Hi -
I've been having a look through the forum for some information on the best pratice for webservices. Whilst I'm aware that LLBLGEN entities can be set as data types within the web service, it doesn't look to friendly for none windows platforms.
Instead I want to create simple XML structures from the entities. What's the best approach for this? I'm sure this has been answered before... but I can't find the exact post.
Joined: 28-Jun-2004
The best approach is to create message based objects. What i am doing is creating my own entities then converting them back and forth. I wrote some templates to generate base custom objects with interfaces, then wrote a convert class that will convert back and forth from llblgen entities to my custom data objects.
I can then aggregate my custom entities into a single object for passing the data across the web service and its non-.net friendly
I just started this yesterday so im sure im prolly going to run into a few walls here and there, but so far its working pretty well..
Joined: 10-Feb-2006
We have put together a pretty tight architecture that supports the use of web services with LLBLGenPro on the backend, in a nutshell it looks like the following:
UI Layer Web Service Facade Layer Data Transfer Objects (DTO) Business Logic Layer Object Persistence Layer -> LLBLGenPro Generated Code Database
UI Layer -> nothing but UI here and some simple UI helper objects that encapsulate calls back to the web services.
Web Service Facade Layer -> Here we have very lightweight web service methods that serve as entry points into our BLL layer. This layer does not contain any business logic, it simply contains calls back to our BLL, this layer also includes security logic, exception handling logic (using ASP.NET 2.0 Health Monitoring, very slick...), and asynchronous logging and auditing logic. This layer knows nothing about LLBLGenPro, it simply makes pass through calls to our BLL component. Communication back to the BLL is done with method parameters and Data Transfer Objects via a publically exposed interface layer in the BLL component. All webservice methods are implemented to return a custom generic DTO collection which is basically a generic collection of various DTO types that implements a custom interface so that the web service methods do not have to know what kind of DTO they are dealing with...
Data Transfer Objects -> these are just simple serializable data only objects (no behavior) that expose the relevant properties for a given functional task. DTOs are the data interface between the UI and the web services, the UI calls back to the web services and receives an IDTOCollection in return. Behavior is exposed through our service layer so there is no need for these objects to contain anything but data.
Business Logic Layer -> This component is the heart of the system, all business logic is done here. This layer consists of publically exposed static helper/manager methods that sit on top of (use) internal classes that contain the implementation of our business rules. The BLL talks directly to our Object Persistence Layer (so basically it makes use of the LLBLGenPro entities to do the work). The BLL knows nothing about DTOs, every BLL method uses a factory class called DTOAssembler to generate specific DTOs and DTO collections, the DTOAssembler is responsible for the mapping of LLBLGenPro entities to DTOs which are returned back up to the web services.
Object Persistence Layer -> This is 100% untouched LLBLGenPro generated code. We use the Self-Servicing entities, we can get away with this b/c the LLBLGenPro entities are encapsulated by our BLL and are never sent back up to the higher tiers of the architecture.
While it seems like a lot of layers and abstraction, we have found that this architecture affords us a lot of flexibility, it scales very well, it is very easy to implement, maintain and to control what goes into and comes out of our middle/backend tiers, implementing exception handling and logging/auditing out in the very light weight web service layer makes it very easy to change exception management policies, security scheme or logging/auditing logic without having an impact on our BLL and b/c we have decoupled business logic from the web services, we were able to write an equally light and simple remoting service layer that we can use in place of web services when needed. Also the choice to keep LLBLGenPro abstracted away in the lowest tier affords us the ability to take advantage of other options for implementing our OPL and BLL in the future, for example Object Spaces (if it ever becomes a reality...) without having an impact on our web/remoting service layers or the UI.
This architecture also performs very well, our systems are real-time tracking systems that track, display, and process interactions and movement of people and assets in various environments using infared and ultrawide band technology so we have pretty stringent performance requirements... So far this approach has proven to be very performant, especially LLBLGenPro on the backend . DTOs are also great candidates for caching in the UI layer especially for static lookup data that is not going to change during the lifetime of the application.
We also decided to provide 2 overloaded web service endpoints for many of our web service methods, one returns a custom collection of DTOs (which is great for data binding to controls in the UI), the other returns a serialized xml string of the DTO collections, the xml message version of the web service methods are exposed to 3rd party systems that we integrate with that don't want/need to know about our DTO structures. They both use the same BLL methods so the code that is duplicated is just what is contained in the web service methods themselves, which average less than 10 lines of code a piece, a worthy trade off in our opinion for the flexibility that it provides and b/c it saves us from having to do the extra deserialization step in our UI code that would be required if we only returned xml message from our web services, we just hook up ObjectDataSources directly to our web service methods that return DTO collections and bind away.
I am sure there are many many things that we have done wrong in implementing this architecture from a theoretical perspective, but it works very well for us in practice.
In any case we do know we made one right choice in all of this, using LLBLGenPro. It saved us 100s if not 1000s of hours of development and testing time, Frans and team we simply cannot thank you enough for putting together such a great tool.
Joined: 28-Jun-2004
We have put together a pretty tight architecture that supports the use of web services with LLBLGenPro on the backend, in a nutshell it looks like the following:
UI Layer Web Service Facade Layer Data Transfer Objects (DTO) Business Logic Layer Object Persistence Layer -> LLBLGenPro Generated Code Database
I am doing basically the exact thing and so far it seems to be working very well. I do have an extra layer in there though. A service layer which is basically just many methods from BLL components aggregated into one service.
I have run into a few design decisions that have given me a bit a of trouble. I was wondering if you could reply to how you handle a few things...
1.) Do you make your DTO by hand, and then create the conversion routines by hand? Could you post an example DTO?
2.) Lets say you got an Order DTO with OrderItems, how do you know which OrderItems to add/delete/update when you UPDATE an order? Do you have seperate methods to perform add/delete/update actions on orderitems? If its not to much trouble could you possible post a small example of how you handled this?
Right now for handling #2, i have it so on Adding an order, i got
AddOrder(Order order, OrderItem[] items)
and for Updating an order,
UpdateOrder(Order order) UpdateOrderItems(int orderId, OrderItem[] items) AddOrderItems(int orderId, OrderItem[] items) RemoveOrderItems(int orderId, OrderItem[] items)
I've never created a distributed app or used web services before so bear with me if they are stupid questions I also am using Adapter and not self servicing. i kinda forgot abot self servicing when i started the project.
Thanks!
Joined: 10-Feb-2006
We do create the DTOs by hand, they are really simple, just private member variables and publically exposed properties that contain only the data elements required for a given functional task.
Now that being said, we also do our best to generalize whenever possible, we certainly don't want to end up with 10,000 DTOs, so we abstract and generalize them, for example we have ton of lookup tables in one of our databases, we of course have a web service method for getting the values from each lookup table, but we only use 1 DTO for all of the lookup tables. My only recommendation is not to get too out of control in creating DTOs b/c it can quickly become a maintenance nightmare...
To you 2nd question, yes we use separate methods for each of the basic CRUD operations, it takes time up front to get them all in place, but once the middle tier is built out, it makes it so much easier for our UI developers to work with, it is always clear to them what a particular method is going to do. The way you have your update add and delete methods defined is probably similar to what we would do, however, in some cases like this, we would probably use a custom collection of orderItems and make that a property of the Order class, our orderItem entity would contain a dirty bit then we can just pass off the Order object back to the Update, Delete, Insert methods...
Hope that answers your questions...