- Home
- LLBLGen Pro
- Architecture
Yet another remoting thread
Joined: 19-Apr-2006
Sorry to go over old ground - I have read most if not all of the threads that a search for remoting returns but have not found anything that covers the whole topic end to end. Has anyone got a framework / working sample / good advice that they are willing to share that deals with using LL... in a scenario where the client talks to a business services middle tier via remoting?
Thanks,
Jascha
Joined: 29-Mar-2005
Hi,
This is what I have done (in the following code you will find class that use the public members directly instead of declare them as property; but the idea is that you have a sample) :
In the Interface project:
This class allows to pass the server name, database name and other fields. The idea is to allow the BL to return data from different database (with the same structure) depending of the content of this fields.
<Serializable()> _
Public Class DataServerInfo
Implements ICloneable
Public SqlServer As String
Public Database As String
Public UserID As String
Public CultureName As String
......
Public Function Clone() As Object Implements System.ICloneable.Clone
Dim info As DataServerInfo
info = Me.MemberwiseClone
Return info
End Function
End Class
The following interface define the common set of functions and sub that each business service object must implements. Normally all my tables has a indentity field as primary key and an ID field that is the key that the user use to access a specific record. I use a array to pass the value for primary key and ID, because sometime the PK or ID are composed of more than one value, all of this will change when I migrate this to VS 2005 and generics. The GetTypedList function is use to return all the data that are use for: dropdowns, selector screen (that allow the user create, edit and delete records), reports, etc.
Public Interface IBasicBusiness
Function GetByPK(ByVal pk() As Object, ByVal serverInfo As DataServerInfo) As ORMSupportClasses.EntityBase2
Function GetByID(ByVal id() As Object, ByVal serverInfo As DataServerInfo) As ORMSupportClasses.EntityBase2
Function Update(ByVal entity As ORMSupportClasses.EntityBase2, ByVal serverInfo As DataServerInfo) As Object
Sub Delete(ByVal pk() As Object, ByVal serverInfo As DataServerInfo)
Function ExistID(ByVal id() As Object, ByVal serverInfo As DataServerInfo) As Boolean
Function ExistPK(ByVal pk() As Object, ByVal serverInfo As DataServerInfo) As Boolean
Function GetTypedList(ByVal dispatcher As ITypedListDispatch, ByVal serverInfo As DataServerInfo) As DataTable
End Interface
The following interface is implemented by all service that will return business objects. Actually I have 3 kind of this service :Local, Remoting and WebService, and I have implemented Local and Remoting:
Public Interface IBusinessFactory
Function GetUserBusiness() As Interfaces.IUserBusiness
Function GetCustomerBusiness() As Interfaces.ICustomerBusiness
......
End Interface
Public Enum ServiceMode As Byte
Local = 0
Remoting = 1
WebServices = 2
End Enum
Public Interface IBasicTypedList
Function GetAll(ByVal serverInfo As DataServerInfo) As DataTable
Function GetAllList(ByVal dispatcher As IGetTypedListRowByID, ByVal serverInfo As DataServerInfo) As DataTable
End Interface
------------------------------------------------------------------------------------------------------
In the BusinessFactory project:
The following class allow you to get a businessfactory that will return a business service object. Normally I use the GetBusinessFactory() function to get the default business factory (the default business factory is assigned depending of an enrtry in the application.config file. The GetBusinessFactory(ByVal mode As Interfaces.ServiceMode) can be used when you know from where you want a business service object.
Public NotInheritable Class BusinessFactory
Private Sub New()
End Sub
Private Shared _factory As IBusinessFactory
Public Shared Function GetBusinessFactory() As Interfaces.IBusinessFactory
Return _factory
End Function
Public Shared Function GetBusinessFactory(ByVal mode As Interfaces.ServiceMode) As Interfaces.IBusinessFactory
Select Case mode
Case Interfaces.ServiceMode.Local
Return LocalServices.Instance
Case Interfaces.ServiceMode.Remoting
Return RemotingServices.Instance
Case Interfaces.ServiceMode.WebServices
Return WebServices.Instance
End Select
End Function
' to init the default business factory
Friend Shared Sub FactoryConfig()
_factory = GetBusinessFactory(ServicesConfig.ServiceMode)
End Sub
End Class
This class allow to config the service mode and to get the default service mode that the application is using. The ReadConfig method is call from the load event of the main form.
Public Class ServicesConfig
Private Sub New()
End Sub
Private Shared _serviceMode As Interfaces.ServiceMode = Interfaces.ServiceMode.Local
Public Shared ReadOnly Property ServiceMode() As ServiceMode
Get
Return _serviceMode
End Get
End Property
Public Shared Sub ReadConfig()
Dim serviceMode As String
serviceMode = System.Configuration.ConfigurationSettings.AppSettings("BusinessServiceMode")
If Not serviceMode Is Nothing Then
Select Case serviceMode.ToLower
Case "local"
_serviceMode = Interfaces.ServiceMode.Local
Case "remoting"
_serviceMode = Interfaces.ServiceMode.Remoting
Case "webservices"
_serviceMode = Interfaces.ServiceMode.WebServices
Case Else
_serviceMode = Interfaces.ServiceMode.Local
End Select
End If
BusinessFactory.FactoryConfig()
End Sub
The following class allows to get local business service object. To create business service object locally the client side need to have a copy of the business assembly.
Friend Class LocalServices
Implements Interfaces.IBusinessFactory
Private Sub New()
End Sub
Public Shared ReadOnly Instance As New LocalServices
Public Function GetCustomerBusiness() As Interfaces.ICustomerBusiness Implements Interfaces.IBusinessFactory.GetCustomerBusiness
Return CustomerBusiness.Instance
End Function
Public Function GetUserBusiness() As Interfaces.IUserBusiness Implements Interfaces.IBusinessFactory.GetUserBusiness
Return UserBusiness.Instance
End Function
End Class
The following class allows to get Remote business service object. If you do not want the client (user interface) to have a copy of the business assembly then you need to remove all the options that allow create business service locally and create the instance of Services.Remoting.RemoteServicesFactory using reflection.
Friend Class RemotingServices
Implements Interfaces.IBusinessFactory
Public Shared ReadOnly Instance As New RemotingServices
Private Sub New()
Me._remoteServicesFactory = New Services.Remoting.RemoteServicesFactory
End Sub
Private _remoteServicesFactory As Services.Remoting.RemoteServicesFactory
Private ReadOnly Property RemoteServiceFactory() As Services.Remoting.RemoteServicesFactory
Get
Return Me._remoteServicesFactory
End Get
End Property
Private iUserBusiness As Interfaces.IUserBusiness
Public Function GetUserBusiness() As Interfaces.IUserBusiness Implements Interfaces.IBusinessFactory.GetUserBusiness
If Me.iUserBusiness Is Nothing Then
Me.iUserBusiness = Me.RemoteServiceFactory.GetUserBusiness
End If
Return Me.iUserBusiness
End Function
.......
End Class
Note that using this class allow you to add more business services without need to worry about modifing the application.config file neither creating instances using reflection. In the application.config file you will have something like this:
<appSettings >
<add key="BusinessServiceMode" value="Local"/>
</appSettings>
<system.runtime.remoting>
<application name="MyApplicationClient">
<client>
<wellknown type="MyApplicationNameSpace...RemoteServicesFactory,MyApplication.RemotingServices" url="tcp://RemotingHost:8050/MyApplicationServer/RemoteServicesFactory" />
</client>
<channels>
<channel ref="tcp client">
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full" />
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
......
With this framework no matter the amount of business services, you only need to create a instance of RemoteServicesFactory after registering the above configuration or using reflection. Remember that if you are going to use reflection then you do not need to register the configuration of the application.config file.
----------------------------------------------------------------------------------------------------------------
In the RemotingServices project:
This is the project that is referenced by the RemotingServiceHost project (this is a windows service project, let me know if you need more details of this windows service project).
This project has to have references to your Interface and Business projects.
The following is the only class in this project.
Public Class RemoteServicesFactory
Inherits MarshalByRefObject
Implements Interfaces.IBusinessFactory
'the object will lives forever
Public Overrides Function InitializeLifetimeService() As Object
MyBase.InitializeLifetimeService()
Return Nothing
End Function
Public Function GetUserBusiness() As Interfaces.IUserBusiness Implements Interfaces.IBusinessFactory.GetUserBusiness
Return UserBusiness.Instance
End Function
..........
End Class
You need to register this class, in the RemotingServiceHost project, to allow the clients to create instance, normally I register it using the singleton call.
-----------------------------------------------------------------------------------------------------------------
In the Business project:
The classes in this project delegate the operations of fetching, saving and deleting entities to classes in the DataAccess project, the business rules are validate by the classes in this project (for example the sale of an item need to change the quantity in stock,etc).
All the business service classes inherit from the following base class:
Public MustInherit Class BasicBusiness
Inherits MarshalByRefObject
Implements Interfaces.IBasicBusiness, Interfaces.IBasicTypedList
Protected errorDelete As String
Protected recordDB As DataAccess.BasicDB
' alive forever
Public Overrides Function InitializeLifetimeService() As Object
MyBase.InitializeLifetimeService()
Return Nothing
End Function
Public Overridable Sub Delete(ByVal pk() As Object, ByVal serverInfo As Interfaces.DataServerInfo) Implements Interfaces.IBasicBusiness.Delete
Dim entity As ORM.EntityBase2
Try
Me.recordDB.Delete(pk, serverInfo, Nothing)
Catch ex As MyApplicationException
Throw
Catch ex As Exception
Throw New MyApplicationException(Me.errorDelete, ex)
End Try
End Sub
Public Overridable Function GetByID(ByVal id() As Object, ByVal serverInfo As Interfaces.DataServerInfo) As ORM.EntityBase2 Implements Interfaces.IBasicBusiness.GetByID
Return Me.recordDB.GetByID(id, serverInfo, Nothing)
End Function
Public Overridable Function GetByPK(ByVal pk() As Object, ByVal serverInfo As Interfaces.DataServerInfo) As ORM.EntityBase2 Implements Interfaces.IBasicBusiness.GetByPK
Return Me.recordDB.GetByPK(pk, serverInfo, Nothing)
End Function
Public Overridable Function Update(ByVal entity As ORM.EntityBase2, ByVal serverInfo As Interfaces.DataServerInfo) Implements Interfaces.IBasicBusiness.Update
Return Me.recordDB.Update(entity, serverInfo, False, Nothing)
End Function
Public Overridable Function ExistID(ByVal id() As Object, ByVal serverInfo As Interfaces.DataServerInfo) As Boolean Implements Interfaces.IBasicBusiness.ExistID
Dim entity As ORM.EntityBase2
entity = Me.recordDB.GetByID(id, serverInfo, Nothing)
Return (Not entity Is Nothing)
End Function
Public Overridable Function ExistPK(ByVal pk() As Object, ByVal serverInfo As Interfaces.DataServerInfo) As Boolean Implements Interfaces.IBasicBusiness.ExistPK
Dim table As ORM.TypedListBase
Try
table = Me.recordDB.GetByPKList(pk, serverInfo, Nothing)
Return (table.Rows.Count > 0)
Finally
If Not table Is Nothing Then
table.Dispose()
End If
End Try
End Function
Public Overridable Function GetTypedList(ByVal dispatcher As ITypedListDispatch, ByVal serverInfo As Interfaces.DataServerInfo) As System.Data.DataTable Implements Interfaces.IBasicBusiness.GetTypedList
Try
Return dispatcher.Execute(Me, serverInfo)
Catch ex As MyApplicationException
Throw
Catch ex As Exception
Throw New MyApplicationException("Error Message", ex)
End Try
End Function
Public Function GetAll(ByVal serverInfo As Interfaces.DataServerInfo) As System.Data.DataTable Implements Interfaces.IBasicTypedList.GetAll
Return Me.recordDB.GetAll(serverInfo)
End Function
Public Function GetAllList(ByVal dispatcher As IGetTypedListRowByID, ByVal serverInfo As Interfaces.DataServerInfo) As System.Data.DataTable Implements Interfaces.IBasicTypedList.GetAllList
Return Me.recordDB.GetAllList(dispatcher, serverInfo, Nothing)
End Function
End Class
This is an example of a business service class:
Public Class UserBusiness
Inherits BasicBusiness
Implements IUserBusiness
Public Shared Instance As New UserBusiness
Private Sub New()
MyBase.New()
Me.errorDelete = MensajeBS.ErrorUserDelete
Me.recordDB = DataAccess.UserDB.Instance
End Sub
End Class
At this point you must be asking about LLBLGen code, almost all the LLBLGen code is done in the DataAccess classes.
Let me know if you need additional info.
Joined: 19-Apr-2006
Rogelio,
Quite a post - thanks! A few initial questions:
So it looks like you are creating a remotable manager class for each entity class? How do you deal with retrieving an object with pre-fetched related entities to avoid the remote access getting too "chatty"? How do you fetch entity lists? How do you update saved objects with any db generated property values e.g. identity fields?
I will study this further asap.
Jascha
Joined: 29-Mar-2005
jaschag wrote:
So it looks like you are creating a remotable manager class for each entity class? Jascha
Only for the main entities, for example InvoiceEntity and the InvoiceDetailEntity is managed inside the InvoiceBusiness manager.
jaschag wrote:
How do you deal with retrieving an object with pre-fetched related entities to avoid the remote access getting too "chatty"? Jascha
Normally I do pre-fetch when I have an entity that has children, for example InvoiceEntity; but I do not do pre-fetch for the entities that are related with the children (for example I do not pre-fetch ProductEntity that is related with each InvoiceDetailEntity; because normally I only need two fields (code and description) from the related entities. I prefer to add two custom fields to the InvoiceDetailEntity (code and description) and loop all the details and assign value to this fields from a typedlist that I fetch based in the primary key. It is only done when I am fetching a main entity to be edited, in the UI when the user add a detail I get the two fields (code and description) from the dropdown's row that the user select.
jaschag wrote:
How do you fetch entity lists? Jascha
To fetch entity lists I use typedlist, because it allow me to fetch a subset of the fields and I think that typedlists are more light than entities.
jaschag wrote:
How do you update saved objects with any db generated property values e.g. identity fields? Jascha
I do not have to worry about identity fields, I only have to save the main entity (for example InvoiceEntity) and LLBLGen takes care of assigning the generate identity to the main entity and its children.
Joined: 19-Apr-2006
Rogelio, thanks once again. Some more questions if I may
Rogelio wrote:
Normally I do pre-fetch when I have an entity that has children, for example InvoiceEntity; but I do not do pre-fetch for the entities that are related with the children (for example I do not pre-fetch ProductEntity that is related with each InvoiceDetailEntity; because normally I only need two fields (code and description) from the related entities. I prefer to add two custom fields to the InvoiceDetailEntity (code and description) and loop all the details and assign value to this fields from a typedlist that I fetch based in the primary key. It is only done when I am fetching a main entity to be edited, in the UI when the user add a detail I get the two fields (code and description) from the dropdown's row that the user select.
Is your pre-fetch path hardcoded in the retrieval method or can you pass one in as a parameter so that each use case can retrieve exactly what it requires?
Rogelio wrote:
To fetch entity lists I use typedlist, because it allow me to fetch a subset of the fields and I think that typedlists are more light than entities.
Good point
Rogelio wrote:
I do not have to worry about identity fields, I only have to save the main entity (for example InvoiceEntity) and LLBLGen takes care of assigning the generate identity to the main entity and its children.
But there will be some entity properties that are assigned at the DAL / server - InvoiceNumber for example. How do you propagate these values back to the client?
Regarding entity deletion, if a user is editing an invoice and deletes an InvoiceDetailEntity by using a delete key in a detail grid, how do you perform the entity deletion?
How do you implement authentication / security, particularly for remoting connections?
Are there any threading issues to consider?
Have you used this framework over the internet or slow, high latency connections? How does it perform (are the users happy)?
Are there any pitfalls / gotcha's that I should be aware of?
Thanks again.
Joined: 29-Mar-2005
jaschag wrote:
Is your pre-fetch path hardcoded in the retrieval method or can you pass one in as a parameter so that each use case can retrieve exactly what it requires?
Normally I have (in the DataAccessBase class) two overloaded function to fetch an entity using the primary key: - One that get the primary key, serverInfo and adapter. Inside this function a call is done to an overridable function that return a pre-fetch path object, then this function calls the other one that received the pre-fetch path and the other parameters. If I want to retrieve additional entities (via pre-fetch path) then I overrides the function (in the final DataAccess class that inherits from DataAccessBase), create and config the pre-fetch object and return it.
jaschag wrote:
But there will be some entity properties that are assigned at the DAL / server - InvoiceNumber for example. How do you propagate these values back to the client?
In that cases I return the ID (InvoiceNumber) from the update function.
jaschag wrote:
Regarding entity deletion, if a user is editing an invoice and deletes an InvoiceDetailEntity by using a delete key in a detail grid, how do you perform the entity deletion?
The InvoiceDetail table has a column named Deleted, I add a custom field of type Boolean to the InvoiceDetailEntity named ToBeDeleted. When the user delete the row, I check is the row is new, is it is new then it is removed from the collection, it is is not new then it is marked as to be deleted. At the business layer when the InvoiceEntity is being updated, each details is checked to be deleted, it is maked then do the reversion of all entities affected and mark the row as deleted.
jaschag wrote:
How do you implement authentication / security, particularly for remoting connections?
All the implementation was inside an intranet, not need to check for external access; however is you want to avoid any other assembly calls your remote business object, then you can strong signed yours assemblies and add an attribute the the RemoteHost assembly to indicate that only can received calls from specific assembly with public key xxxxx.
jaschag wrote:
Are there any threading issues to consider?
Have you used this framework over the internet or slow, high latency connections? How does it perform (are the users happy)?
I have not used remoting over internet.
jaschag wrote:
Are there any pitfalls / gotcha's that I should be aware of?
Try to use binary formatter always.
If you want your exceptions be propagated back to the client then be sure the RemoteHost application.config file has the following entry: …… <system.runtime.remoting> <application name="NameOfYourRemoteHost"> ……….. </application> <customErrors mode="off" /> </system.runtime.remoting> ………..
Joined: 28-Jun-2004
Are there any threading issues to consider?
Have you used this framework over the internet or slow, high latency connections? How does it perform (are the users happy)?
Depends on your remoting host...if you use IIS which is what i would use and which type of remoting. If your using IIS as a host and SingleCall remoting, then threading isnt really an issue..this is the type i use.
As far usign it over the internet, again, if your using IIS it should work just fine and you get all the built in features of IIS including SSL and it should pass through firewalls just like a webservice would.
As far as my services go, i do things a bit different. All my "Save" functions return the entity you passed in,so clients can get an BL generated fields. And for deletes, take an invoice for example, if i modifiy an invoice, a user may wish to delete a invoice line item for example. But i want to save everything in one transaction. So i create a "request" object...
that has a invoice property and a "Invoice Line Items TO Be Deleted Collection"
public InvoiceEntity SaveInvoice(SaveInvoiceRequest request)
This has worked very well for me so far...
Joined: 19-Apr-2006
Answer wrote:
Depends on your remoting host...if you use IIS which is what i would use and which type of remoting. If your using IIS as a host and SingleCall remoting, then threading isnt really an issue..this is the type i use.
As far usign it over the internet, again, if your using IIS it should work just fine and you get all the built in features of IIS including SSL and it should pass through firewalls just like a webservice would.
Are you using this approach over the net?
Experience with multithreading has taught me to avoid if possible so singlecall sounds like the way to go - have you noticed any performance issues with it?
Answer wrote:
As far as my services go, i do things a bit different. All my "Save" functions return the entity you passed in,so clients can get an BL generated fields. And for deletes, take an invoice for example, if i modifiy an invoice, a user may wish to delete a invoice line item for example. But i want to save everything in one transaction. So i create a "request" object...
that has a invoice property and a "Invoice Line Items TO Be Deleted Collection"
public InvoiceEntity SaveInvoice(SaveInvoiceRequest request)
This has worked very well for me so far...
Good to hear How have you found performance over internet / slower connections? I guess I'm wondering whether the "smartclient" approach is a realistic technique for data entry type applications over the net? I realise that this depends on the nature of the application but if you are always battling with bandwidth and compromising the ui to suit then maybe asp.net becomes more attractive. What are your feelings on that?
You decided not to use unitofwork to handle update/deletes - for strong typing reasons?
Are you passing logical entities - i.e. are you passing an object graph with invoice lines and possibly other related entities as part of the invoice entity above?
Joined: 29-Mar-2005
[quotenick="Answer"]
As far as my services go, i do things a bit different. All my "Save" functions return the entity you passed in,so clients can get an BL generated fields. And for deletes, take an invoice for example, if i modifiy an invoice, a user may wish to delete a invoice line item for example. But i want to save everything in one transaction. So i create a "request" object...
that has a invoice property and a "Invoice Line Items TO Be Deleted Collection"
public InvoiceEntity SaveInvoice(SaveInvoiceRequest request)
This has worked very well for me so far...
I do return only the generated ID because after a transaction ( for example Invoice) is saved the user need to print it, then to print any transaction I use a typedlist that has all the fields (including the ones from related tables) that I will need to print the transaction. Why I do this instead of print the transaction directly from the entity, because: - I pass the typedlist directly to my report generator. - Normally I allow the user to reprint a transaction, then I use the same class to print a new transaction and to reprint a transaction, I only have to pass the ID of the transaction. - Normally for each transaction that is going to be printed there are custom fields (quanty by price, total discount, etc) that have to be calculated at the BL before returning the typedlist.
Edit. Writing the above lines I thought why not before saving the transaction ask the user whether he(she) wants to print the transaction and return the typedlist from the BusinessService's update function, that would save me a trip to the Server!
Joined: 28-Jun-2004
Are you using this approach over the net?
Experience with multithreading has taught me to avoid if possible so singlecall sounds like the way to go - have you noticed any performance issues with it?
I have only tested on the lan so far...but originally i was going to use webservices for my application and i switched to remoting, i did a lot of reading prior...Remoting over IIS with singlecall is basically identical to webservices, except that i can take advantage of the Binary formatter And it works a bit nicer with llblgen... Using single also gives the benefit of being able to use load balancing fairly easily.
Good to hear How have you found performance over internet / slower connections? I guess I'm wondering whether the "smartclient" approach is a realistic technique for data entry type applications over the net? I realise that this depends on the nature of the application but if you are always battling with bandwidth and compromising the ui to suit then maybe asp.net becomes more attractive. What are your feelings on that?
So far i have been very happy but again, im only doing primitive testing. I am using those request objects etc to limit requests to the server but i havent really hammered the server yet to see what it can handle. With me jsut using it, its very fast and CPU usuage is hardly anything. I get a few spikes here and there, but most the time it like 2-4%.
I would say smart client is def faster. As the server doesnt have to render any UI. Passing a large collection of entities will be slow, you should use typed lists or typedviews for any "List Form" for instance. Other then that i am very happy with performance.
You decided not to use unitofwork to handle update/deletes - for strong typing reasons?
Strong typing was one reason. However the big deal killer was the fact that the unit of work performs inserts then udpates, then deletes. This would cause problems in my case as i needed deleted to be performed first, then inserts and updates..so i just do it manually.
Are you passing logical entities - i.e. are you passing an object graph with invoice lines and possibly other related entities as part of the invoice entity above?
Absolutely! On Some forms, im passing entities 3 levels deep... My request objecst contain the main entity graph, then a collection for each entity type that can be deleted.
On the server, i delete the collections, do any BL work on the entity graph then persist. and return the persisted entity graph back. Works like a charm
Joined: 19-Apr-2006
Guys,
Thanks for all your advice - your experience suggests that many of the risks of remoting are manageable. Typed lists are mentioned often by both of you - I was hoping to keep everything as objects but it sounds like the efficiency of typed lists is too attractive - for browsable lists in particular. However one risk seems to remain - solid experience of this working over slower connections. I am less concerned about server cpu - that is scaleable - it's bandwidth and latency that are the limiting factors so I am going to start a new thread specifically about remoting over the net to see if anyone has done this in anger...
Joined: 28-Jun-2004
well, even though i havent actually tested and used it over the web...YET
1, remoting uses binary formatter which = smaller payload then webservices...
2, your not passing visual markup (ie HTML) along with the data, which = smaller payload.
3, With remoting, you can add a compresssion sink in the chain, which really = smaller payload. ie, 33k entity graph serialized = 5k after compression.
Now, given that, and the fact taht your smart client can cache various things smart clients are definetly much faster IMHO. Especially if your web app isnt using AJAX.
Our internet here sucks, its got a 15k/s upload limit, so performance over the internet is a big factor for me. Plus its wireless, so i have a higher ping then a land line. So minimizing round trips and smallest payload are key
Joined: 19-Apr-2006
Answer wrote:
2, your not passing visual markup (ie HTML) along with the data, which = smaller payload.
I guess that depends on whether the markup payload is > data payload... typed lists...
Answer wrote:
3, With remoting, you can add a compresssion sink in the chain, which really = smaller payload. ie, 33k entity graph serialized = 5k after compression.
Have you tried that? Is it easy to configure? Have you looked at WCF?
Answer wrote:
Our internet here sucks, its got a 15k/s upload limit, so performance over the internet is a big factor for me. Plus its wireless, so i have a higher ping then a land line. So minimizing round trips and smallest payload are key
Ouch
Joined: 28-Jun-2004
Have you tried that? Is it easy to configure? Have you looked at WCF?
I havent actually written it yet, but its pretty common, and there plenty of info on the net about it.
I have looked at WCF. remoting + singlecall should be a fairly easy migration. However i have no reason to really use WCF at this point so im going to stick with remoting.