- 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.