VB .Net NullReferenceException work-around

Mike L. picture Mike L. · Feb 12, 2012 · Viewed 15.6k times · Source

This should be simple, but I am having problems. Using the eBay .Net library, sometimes certain fields in a response are Nothing and sometimes contain a value. When they are Nothing they could simple be represented as an empty string, but the developers chose to return them as Nothing so when I try to set a String to the value (when nothing is there) I get a NullReferenceException, see below

Imports System
Imports System.Configuration.ConfigurationManager
Imports System.Globalization
Imports System.Threading
Imports System.Xml

Imports eBay.Service.Core.Soap
Imports eBay.Service.Core.Sdk
Imports eBay.Service.Call
Imports eBay.Service.Util

Public Class eBayOrderImportService
Private Sub ServiceWorkerThread(ByVal state As Object)
    ' Periodically check if the service is stopping.
    Do While Not Me.stopping
        ' Perform main service function here...
        GetLastTime()
        Dim apiContext As ApiContext = GetApiContext()

        Dim apiCall As GetOrdersCall = New GetOrdersCall(apiContext)
        Dim orders As New OrderTypeCollection

        Dim timeFilter As New TimeFilter
        timeFilter.TimeFrom = lastUpdate
        timeFilter.TimeTo = Date.Now


        Dim lastTime As Boolean = SetLastTime()
        apiCall.IncludeFinalValueFee = True
        orders = apiCall.GetOrders(timeFilter, TradingRoleCodeType.Seller, OrderStatusCodeType.Completed)

        Dim order As OrderType

        For Each order In orders
            'do order-wide stuff here
            LogOrder(order)

        Next
        Thread.Sleep(30 * 1000)  ' Simulate some lengthy operations.

    Loop

    ' Signal the stopped event.
    Me.stoppedEvent.Set()
End Sub

Private Sub LogOrder(ByVal Order As OrderType)

    Dim OrderID, AccountID, BillingFirstName, BillingLastName, _
        BillingCompany, BillingEmailAddress, BillingPhone, _
        BillingAddress1, BillingAddress2, BillingCity, _
        BillingStateProvidence, BillingPostalCode, _
        BillingCountry, ShippingFirstName, ShippingLastName, _
        ShippingCompany, ShippingEmailAddress, ShippingPhone, _
        ShippingAddress1, ShippingAddress2, ShippingCity, _
        ShippingStateProvidence, ShippingPostalCode, _
        ShippingCountry, OrderStatus, BillingStatus, _
        OrderDate, ShippingMethod, SalesTax, _
        PreShippingCharge, OrderDiscount, OrderTotalCharged, _
        PaymentMethod, RepeatOrder, GiftCode, CouponCode, RID, _
        OrderNotes, OrderChannel, IsPrinted, IsShipped, PrintDate, _
        ShipDate, ActualShipCharge, DaysInTransit, DeliveryDate, _
        TrackingNumber, ShippedMethod As String


    OrderID = Order.OrderID

    AccountID = ""

    Dim name As String = If(Order.ShippingAddress.Name.ToString(), "None Given")

    BillingFirstName = name.Substring(0, name.IndexOf(" "))
    BillingLastName = name.Substring(name.IndexOf(" ") + 1)
    BillingCompany = If(Order.ShippingAddress.CompanyName.ToString(), "")
    BillingEmailAddress = If(Order.TransactionArray(0).Buyer.Email.ToString(), "")
    BillingPhone = If(Order.ShippingAddress.Phone.ToString(), "")
    BillingAddress1 = If(Order.ShippingAddress.Street1.ToString(), "")
    BillingAddress2 = If(Order.ShippingAddress.Street2.ToString(), "")
    BillingCity = If(Order.ShippingAddress.CityName.ToString(), "")
    BillingStateProvidence = If(Order.ShippingAddress.StateOrProvince.ToString(), "")
    BillingPostalCode = If(Order.ShippingAddress.PostalCode.ToString(), "")
    BillingCountry = If(Order.ShippingAddress.CountryName.ToString(), "")
    ShippingFirstName = If(BillingFirstName, "")
    ShippingLastName = If(BillingLastName, "")
    ShippingCompany = If(Order.ShippingAddress.CompanyName.ToString(), "")
    ShippingEmailAddress = If(Order.TransactionArray(0).Buyer.Email.ToString(), "")
    ShippingPhone = If(Order.ShippingAddress.Phone.ToString(), "")
    ShippingAddress1 = If(Order.ShippingAddress.Street1.ToString(), "")
    ShippingAddress2 = If(Order.ShippingAddress.Street2.ToString(), "")
    ShippingCity = If(Order.ShippingAddress.CityName.ToString(), "")
    ShippingStateProvidence = If(Order.ShippingAddress.StateOrProvince.ToString(), "")
    ShippingPostalCode = If(Order.ShippingAddress.PostalCode.ToString(), "")
    ShippingCountry = If(Order.ShippingAddress.CountryName.ToString(), "")
    OrderStatus = If(Order.OrderStatus.ToString(), "")
    BillingStatus = If(Order.OrderStatus.ToString(), "")
    OrderDate = If(Order.CreatedTime.ToString("MM/DD/yyyy"), "")
    If Order.TransactionArray(0).Taxes IsNot Nothing Then
        Dim tmpTax As Double = 0.0
        Dim tmpTrans As TransactionType
        For Each tmpTrans In Order.TransactionArray
            tmpTax = tmpTax + tmpTrans.Taxes.TotalTaxAmount.Value
        Next
        SalesTax = tmpTax.ToString()

    Else
        SalesTax = "0.0"
    End If


    ShippingMethod = If(Order.ShippingServiceSelected.ShippingService.ToString(), "")
    ShippingMethod = ShippingMethod & ":" & If(Order.ShippingServiceSelected.ShippingServicePriority.ToString(), "")

    OrderTotalCharged = If(Order.Total.Value.ToString(), "")
    OrderChannel = "eBay"
    comm = New OdbcCommand
    comm.CommandText = _
           "INSERT INTO Orders (OrderID, AccountID, BillingFirstName, BillingLastName, " & _
           "BillingCompany, BillingEmailAddress, BillingPhone, BillingAddress1, " & _
           "BillingAddress2, BillingCity, BillingStateProvidence, BillingPostalCode, " & _
           "BillingCountry, ShippingFirstName, ShippingLastName, ShippingCompany, " & _
           "ShippingEmailAddress, ShippingPhone, ShippingAddress1, ShippingAddress2, " & _
           "ShippingCity, ShippingStateProvidence, ShippingPostalCode, ShippingCountry, " & _
           "OrderStatus, BillingStatus, OrderDate, SalesTax, ShippingMethod, OrderTotalCharged, OrderChannel) " & _
           "VALUES('" & OrderID & "', '" & AccountID & "', '" & BillingFirstName & "', '" & _
           BillingLastName & "', '" & BillingCompany & "', '" & BillingEmailAddress & "', '" & _
           BillingPhone & "', '" & BillingAddress1 & "', '" & BillingAddress2 & "', '" & BillingCity & "', '" & _
           BillingStateProvidence & "', '" & BillingPostalCode & "', '" & BillingCountry & "', '" & _
           ShippingFirstName & "', '" & ShippingLastName & "', '" & ShippingCompany & "', '" & _
           ShippingEmailAddress & "', '" & ShippingPhone & "', '" & ShippingAddress1 & "', '" & _
           ShippingAddress2 & "', '" & ShippingCity & "', '" & ShippingStateProvidence & "', '" & _
           ShippingPostalCode & "', '" & ShippingCountry & "', '" & OrderStatus & "', '" & _
           BillingStatus & "', '" & OrderDate & "', '" & SalesTax & "', '" & ShippingMethod & "', '" & _
           OrderTotalCharged & "', '" & OrderChannel & "')"
    ' Dim orderResult As Integer = comm.ExecuteNonQuery()
    sysLog.WriteEntry(comm.CommandText)
End Sub
End Class

There is updated code please note no exception is thrown until: BillingCompany = If(Order.ShippingAddress.CompanyName.ToString(), "") is executed. The Name property has a value which successfully stored into its variable, while Order.ShippingAddress.CompanyName is set to Nothing (this property does exist, and can sometimes have a value). I updated the code to include Anthony Pegram's answer which did not help.

Everything is declared properly, to shorten the code I just showed a relevant example. Consider this inside of a loop for each order returned from a GetOrders() call, sometimes the Order.ShippingAddress.CompanyName will be nothing, at these times is it possible to handle it as an empty string? I tried the ToString() method. In other languages I could $CompanyName = this || that;

Anything similar in VB .Net?

Answer

Anthony Pegram picture Anthony Pegram · Feb 12, 2012

You can use If(a, b) to coalesce a null to another value. Example:

Dim obj as String = Nothing
Dim foo as String = If(obj, "foo")

The output of foo in this example will be the string "foo". If you had a non-null string assigned to obj, then foo would also reference that string.

However, I have a strong feeling that your null reference exception could be happening not on the property, but on the object. Order or ShippingAddress could be null. Accessing properties or methods on a null reference is an error. Simply accessing a null value by storing it to a variable is not an error in and of itself.

If you are getting your exception on one of these lines

CompanyName = Order.ShippingAddress.CompanyName 
State = Order.ShippingAddress.StateOrProvince

It is because either Order or ShippingAddress is null.

Check and see if these objects could actually return as nothing. If so, you will need to apply null-checking around them prior to accessing their properties.


Your update:

There is updated code please note no exception is thrown until:

BillingCompany = If(Order.ShippingAddress.CompanyName.ToString(), "")

is executed.

This can throw because Order can be null, ShippingAddress can be null, or CompanyName can be null. It is an exception to access a property or a method on a null reference. If Order is null, you will get an error accessing ShippingAddress. Similarlu, if ShippingAddress is null, you cannot access CompanyName. If CompanyName is null, you cannot call ToString().

You have to at some point verify which object is null. I don't have confidence that any of them will not be null. Do you? Check. Step through your program and observe the object states.

If it does come down to properties like CompanyName being null, and if CompanyName is a string, omit the ToString() call.

BillingCompany = If(Order.ShippingAddress.CompanyName, "")

If CompanyName is not a string, you will simply have to compare it to Nothing before calling ToString() or accessing a property.