Monday, April 11, 2011

How to architect DAL for WebService exposure?

We have a highly specialized DAL which sits over our DB. Our apps need to use this DAL to correctly operate against this DB.

The generated DAL (which sits on some custom base classes) has various 'Rec' classes (Table1Rec, Table2Rec) each of which represents the record structure of a given table.

Here is a sample Pseudo-class...

Public Class SomeTableRec
    Private mField1 As String
    Private mField1isNull As Boolean
    Private mField2 As Integer
    Private mField2isNull As Boolean

    Public Sub New()
        mField1isNull = True
        mField2isNull = True
    End Sub
    Public Property Field1() As String
        Get
            Return mField1
        End Get
        Set(ByVal value As String)
            mField1 = value
            mField1isNull = False
        End Set
    End Property
    Public ReadOnly Property Field1isNull() As Boolean
        Get
            Return mField1isNull
        End Get
    End Property
    Public Property Field2() As Integer
        Get
            Return mField2
        End Get
        Set(ByVal value As Integer)
            mField2 = value
            mField2isNull = False
        End Set
    End Property
    Public ReadOnly Property Field2isNull() As Boolean
        Get
            Return mField2isNull
        End Get
    End Property
End Class

Each class has properties for each of the fields... Thus I can write...

Dim Rec as New Table1Rec
Table1Rec.Field1 = "SomeString"
Table2Rec.Field2 = 500

Where a field can accept a NULL value, there is an additional property which indicates if the value is currently null.

Thus....

Dim Rec as New Table1Rec
Table1Rec.Field1 = "SomeString"
If Table1Rec.Field1Null then 
    ' This clearly is not true
End If
If Table1Rec.Field2Null then 
    ' This will be true
End If

This works because the constructor of the class sets all NULLproperties to True and the setting of any FieldProperty will cause the equivalent NullProperty to be set to false.

I have recently had the need to expose my DAL over the web through a web service (which I of course intend to secure) and have discovered that while the structure of the 'Rec' class remains intact over the web... All logic is lost..

If someone were to run the previous piece of code remotely they would notice that neither condition would prove true as there is no client side code which sets null to true.

I get the feeling I have architected this all wrong, but cannot see how I should improve it.

What is the correct way to architect this?

From stackoverflow
  • Web services are designed to expose operation(methods) & data contracts but not internal implementation logic. This is a "good thing" in the world of service-oriented architecture. The scenario you describe is a remote/distributed object architecture. Web services will not support what you are trying to do. Please see this post for more information.

  • Not sure if I fully understand the question, but you can have nullable data types in XML.

    So this...

    Imports System.Web
    Imports System.Web.Services
    Imports System.Web.Services.Protocols
    
    <WebService(Namespace:="http://tempuri.org/")> _
    <WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
    <Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
    Public Class Testing
         Inherits System.Web.Services.WebService
    
        <WebMethod()> _
       Public Function GetObjects() As Generic.List(Of TestObject)
            Dim list As New Generic.List(Of TestObject)
            list.Add(New TestObject(Nothing, "Empty ID Object"))
            list.Add(New TestObject(1, "Full ID Object"))
            list.Add(New TestObject(2, Nothing))
            Return list
        End Function
    
        Public Class TestObject
            Public Sub New()
                _name = String.Empty
                _id = Nothing
            End Sub
            Public Sub New(ByVal id As Nullable(Of Integer), ByVal name As String)
                _name = name
                _id = id
            End Sub
            Private _name As String
            Public Property Name() As String
                Get
                    Return _name
                End Get
                Set(ByVal value As String)
                    _name = value
                End Set
            End Property
    
            Private _id As Nullable(Of Integer)
            Public Property ID() As Nullable(Of Integer)
                Get
                    Return _id
                End Get
                Set(ByVal value As Nullable(Of Integer))
                    _id = value
                End Set
            End Property
        End Class
    
    End Class
    

    outputs this (with nullable areas)

    <?xml version="1.0" encoding="utf-8" ?> 
    <ArrayOfTestObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
     <TestObject>
      <Name>Empty ID Object</Name> 
      <ID xsi:nil="true" /> 
     </TestObject>
     <TestObject>
      <Name>Full ID Object</Name> 
      <ID>1</ID> 
     </TestObject>
     <TestObject>
      <ID>2</ID> 
     </TestObject>
    </ArrayOfTestObject>
    

0 comments:

Post a Comment