开发者

NullReferenceException makes me want to shoot myself

Ok, so once upon a time, my code worked. Since then I did some refactoring (basic stuf开发者_运维问答f so I thought) but now I'm getting a null reference exception, and I can't bloody well figure out why.

Here's where it starts. note, this is the logout method, but all of my ActivityLogs sections are throwing this error

Function LogOut(ByVal go As String) As ActionResult
    ActivityLogService.AddActivity(AuthenticationHelper.RetrieveAuthUser.ID, _
                                   IActivityLogService.LogType.UserLogout, _
                                   HttpContext.Request.UserHostAddress)
    ActivityLogService.SubmitChanges()
    'more stuff happens after this'
End Function

The service is pretty straight forward (notice the ERROR THROWN HERE)

    Public Sub AddActivity(ByVal userid As Integer, ByVal activity As Integer, ByVal ip As String) Implements IActivityLogService.AddActivity
        Dim _activity As ActivityLog = New ActivityLog With {.Activity = activity,
                                                             .UserID = userid,
                                                             .UserIP = ip.IPAddressToNumber,
                                                             .ActivityDate = DateTime.UtcNow}

        ActivityLogRepository.Create(_activity)  ''#ERROR THROWN HERE
    End Sub

And the Interface that the Service uses looks like this

Public Interface IActivityLogService
    Sub AddActivity(ByVal userid As Integer, ByVal activity As Integer, ByVal ip As String)
    Function GetUsersLastActivity(ByVal UserID As Integer) As ActivityLog
    Sub SubmitChanges()

    ''' <summary> '
    ''' The type of activity done by the user '
    ''' </summary>
    ''' <remarks>Each int refers to an activity. There can be no duplicates or modifications  after this application goes live</remarks> '
    Enum LogType As Integer
        ''' <summary> '
        ''' A new session started '
        ''' </summary> '
        SessionStarted = 1
        ''' <summary> '
        ''' A new user is Added/Created '
        ''' </summary> '
        UserAdded = 2
        ''' <summary> '
        ''' User has updated their profile '
        ''' </summary> '
        UserUpdated = 3
        ''' <summary> '
        ''' User has logged into they system '
        ''' </summary> '
        UserLogin = 4
        ''' <summary> '
        ''' User has logged out of the system '
        ''' </summary> '
        UserLogout = 5
        ''' <summary> '
        ''' A new event has been added '
        ''' </summary> '
        EventAdded = 6
        ''' <summary> '
        ''' An event has been updated '
        ''' </summary> '
        EventUpdated = 7
        ''' <summary> '
        ''' An event has been deleted '
        ''' </summary> '
        EventDeleted = 8
        ''' <summary> '
        ''' An event has received a Up/Down vote '
        ''' </summary> '
        EventVoted = 9
        ''' <summary> '
        ''' An event has been closed '
        ''' </summary> '
        EventCloseVoted = 10
        ''' <summary> '
        ''' A comment has been added to an event '
        ''' </summary> '
        CommentAdded = 11
        ''' <summary> '
        ''' A comment has been updated '
        ''' </summary> '
        CommentUpdated = 12
        ''' <summary> '
        ''' A comment has been deleted '
        ''' </summary> '
        CommentDeleted = 13
        ''' <summary> '
        ''' An event or comment has been reported as spam '
        ''' </summary> '
        SpamReported = 14
    End Enum
End Interface

And the repository is equally straight forward

Public Class ActivityLogRepository : Implements IActivityLogRepository
    Private dc As MyAppDataContext
    Public Sub New()
        dc = New MyAppDataContext
    End Sub

    ''' <summary> '
    ''' Adds the activity. '
    ''' </summary> '
    ''' <param name="activity">The activity.</param>
    Public Sub Create(ByVal activity As ActivityLog) Implements IActivityLogRepository.Create
        dc.ActivityLogs.InsertOnSubmit(activity)
    End Sub

    ''' <summary> '
    ''' Gets the activities. '
    ''' </summary> '
    ''' <returns>results AsQueryable</returns>
    Public Function Read() As IQueryable(Of ActivityLog) Implements IActivityLogRepository.Read
        Dim activity = (From a In dc.ActivityLogs
                        Order By a.ActivityDate Descending
                        Select a)
        Return activity.AsQueryable
    End Function

    ''' <summary> '
    ''' Submits the changes. '
    ''' </summary> '
    Public Sub SubmitChanges() Implements IActivityLogRepository.SubmitChanges
        dc.SubmitChanges()
    End Sub
End Class

The stack trace is as follows

[NullReferenceException: Object reference not set to an instance of an object.] MyApp.Core.Domain.ActivityLogService.AddActivity(Int32 userid, Int32 activity, String ip) in E:\Projects\MyApp\MyApp.Core\Domain\Services\ActivityLogService.vb:49 MyApp.Core.Controllers.UsersController.Authenticate(String go) in E:\Projects\MyApp\MyApp.Core\Controllers\UsersController.vb:258 lambda_method(Closure , ControllerBase , Object[] ) +163 System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +51 System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary2 parameters) +409 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 parameters) +52 System.Web.Mvc.<>c__DisplayClass15.b__12() +127 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func1 continuation) +436 System.Web.Mvc.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14() +61 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList1 filters, ActionDescriptor actionDescriptor, IDictionary2 parameters) +305 System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +830 System.Web.Mvc.Controller.ExecuteCore() +136 System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +232 System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +39 System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +68 System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +44 System.Web.Mvc.Async.<>c__DisplayClass81.b__7(IAsyncResult _) +42 System.Web.Mvc.Async.WrappedAsyncResult`1.End() +141 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +54 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40 System.Web.Mvc.<>c__DisplayClasse.b__d() +61 System.Web.Mvc.SecurityUtil.b__0(Action f) +31 System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +56 System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +110 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +38 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +690 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +194

here's an image of the error when attached to the debugger.

NullReferenceException makes me want to shoot myself

And here's an image of the DB schema in question

NullReferenceException makes me want to shoot myself

Can anyone shed some light on what I might be missing here?


This might seem like I'm being obtuse, but have you added null checks for EVERYTHING on line 49?

MyApp.Core.Domain.ActivityLogService.AddActivity(Int32 userid, Int32 activity, String ip) in E:\Projects\MyApp\MyApp.Core\Domain\Services\ ActivityLogService.vb:49

From the looks of it, that could be ensuring that ActivityLogRepository isn't null.


Here are some general ideas to debug/avoid NullReferenceExceptions:

Make sure everything is initialized.

Initializing to null/Nothing does not count.

Decide what can and what can't be null

Usually a great part of a code base's references is expected to not be null for the whole or most of its scope. If so, then why would you tolerate it?

Aggressively cut down the number of references that you allow to be null at some point. The goal is to make it so that only a few whitelisted references can be found in a null state. Preferably make this explicit, either in comments, or with something like ReSharper's annotations.

Take care to branch on the whitelisted ones and act accordingly.

Defensively reject null arguments

Methods should refuse non-whitelisted null arguments and throw ArgumentNullException. This makes immediately clear what reference is null, and many times this is thrown closer to the source of the null reference than a NullReferenceException, which is only thrown at the dereferencing site.

Handle whitelisted references

If the exception was thrown on a whitelisted reference, add the appropriate code to handle it. This should be an "if" branching; don't catch NullReferenceException.

All non-whitelisted null references are bugs

If the reference that threw the exception isn't whitelisted, this is a bug. You'll have to trace the null reference back to the origin.

Check where the reference is initialized. If it is a variable, you can simply check the containing method.

If it is a field, check the constructor for initialization. Then look for assignment to an explicit null reference (Nothing in Visual Basic) or a to a whitelisted reference. You may need to follow the trail from one variable/field to another until you find the real source of the null reference.

To fix it, replace it by the adequate valid reference, or add an "if" clause if the source was a whitelisted reference.


@gbs pointed me in the right direction.

I had the following in my service

    Private ActivityLogRepository As IActivityLogRepository

    Public Sub New(ByVal ActivityLogRepository As IActivityLogRepository)
        ActivityLogRepository = ActivityLogRepository
    End Sub

Not sure how I missed it, changed to this and it works

    Private ActivityLogRepository As IActivityLogRepository

    Public Sub New(ByVal _ActivityLogRepository As IActivityLogRepository)
        ActivityLogRepository = _ActivityLogRepository
    End Sub
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜