-1

I have a web method in a MVC .NET application that accepts a json string of data from an AJAX call to be updated in the database

The data is an array of objects, and be one of two package types. I check which package type it is, then deserialize the string to that class. So the function looks something like this:

    public JsonResult SaveData (string jsonIn)
    {
        string rtnStr = "";
        bool hasChanges = false;
        using (var db = new MyDBContext())
        {

            JArray packages = JArray.Parse(jsonIn);
            foreach (JObject package in packages.Children<JObject>())
            {
                string packageType = "Unknown";
                if (package != null & package.TryGetValue("DataType", out JToken value))
                {
                    packageType = value.ToString();
                }
                if (packageType == "PackageTypeA")
                {
                    PackageTypeA pkgTypeA = JsonConvert.DeserializeObject<PackageTypeA>(package.ToString());
                    //do some things
                } 
                else if (packageType == "PackageTypeB") {
                    PackageTypeB pkgTypeB = JsonConvert.DeserializeObject<PackageTypeB>(package.ToString());
                    //do something else
                }
            }
        }
     }

I'm getting occasional exceptions in the error log on this line in particular: packageType = value.ToString();:

Message: Object reference not set to an instance of an object.
Stack Trace: 
   at MyApp.Controllers.PlansController.SaveData(String jsonIn) in C:\home\projects\dotNet\MyApp\MyApp\Controllers\PlansController.cs:line 257
   at lambda_method(Closure , ControllerBase , Object[] )
   at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
   at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
   at System.Web.Mvc.Controller.ExecuteCore()
   at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext)
   at System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext)
   at System.Web.Mvc.MvcHandler.<>c__DisplayClass6.<>c__DisplayClassb.<BeginProcessRequest>b__5()
   at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass1.<MakeVoidDelegate>b__0()
   at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
   at System.Web.Mvc.MvcHandler.<>c__DisplayClasse.<EndProcessRequest>b__d()
   at System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f)
   at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action)
   at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
   at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

As a boolean method shouldn't package.TryGetValue("DataType", out JToken value) equate to false so that packageType = value.ToString(); isnt executed if DataType is null?

jessikwa
  • 750
  • 1
  • 8
  • 23

1 Answers1

1

package != null & package.... Here's your problem. package is null but you attempt to access it's TryGetValue method.

Instead, use &&:

if (package != null && package.TryGetValue("DataType", out JToken value))

or even better (well, shorter, at least):

if (package?.TryGetValue("DataType", out JToken value) ?? false)
Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
  • I would think that my exception would be thrown on the line ````if (package != null & package.TryGetValue("DataType", out JToken value))```` rather than the next line if this were the case, but I see the ````&```` instead of ````&&```` being an issue as well. Thanks – jessikwa Mar 11 '20 at 17:20
  • It will be thrown from this line... – Zohar Peled Mar 11 '20 at 18:00
  • The stacktrace of the exception suggests otherwise – jessikwa Mar 13 '20 at 13:05