views:

34

answers:

1

I am developing an ecommerce app that is using the UPS shipping webservice. I have read that it is good to create a singleton so there is only one instance of a webservice at any time. My code for that is below.

Public Class Ship
    Private Shared sync As New Object()
    Private Shared _Service As New ShipService

    Public Shared ReadOnly Property Service As ShipService
        Get
            If _Service Is Nothing Then
                SyncLock sync
                    If _Service Is Nothing Then
                        _Service = New ShipService
                    End If
                End SyncLock
            End If
            Return _Service
        End Get
    End Property

    Public Shared Function GetInstance() As ShipService
        Return Service()
    End Function
End Class

Here is a snippet from where it will be used.

Public Sub New(ByVal ToAddress As Address, ByVal WeightInLbs As String)
    //Not relevant code
    Ship.Service.UPSSecurityValue = Security
    //More not relevant code 
End Sub

Public Function ProcessShipment() As ShipmentResponse
    Return Ship.Service.ProcessShipment(ShipmentRequest)
End Function

In the line above in the construtor I have to set the UPSSecurityValue of the service. Then later I will call the ProcessShipment function. My question is; Since the webservice is being traeted as a singlton could different instances of the app share that same UPSSecurityValue and could it change between when I set it and when I call ProcessShipment?

+1  A: 

In the case of what you're doing, it could definately change between when you call New and set the Security value and when you actually process the shipment. The singleton is shared across all users of your application (within the same web app, that is - if you had multiple copies of this app on your server, they'd each use their own singleton), so all users will share the same data.

If multiple users run through the application at the same time (or User2 is only 1ms behind):

User1                           User2
New (sets security code)
                                New (sets security code)
ProcessShipment
                                ProcessShipment 

Both shipments will process with User2's security code, which isn't what you want. The way to do this safely could be to pass the security into the function when you ship the package, and then consume it immediately - if you store it for use later, even a single instruction later, you're setting yourself up for a race condition where users read each other's data.

rwmnau