none
System.ArgumentNullException: Value cannot be null - error while adding row in the datatable (types dataset)

    Question

  • Hi,
    I am currently having a very strange problem while adding a datarow into a datatable. This was not happening when the application was in .NET 1.1 but once we migrated the application to .NET 3.5, we have started to getting error System.ArgumentNullException: Value cannot be null. I have provided the complete stack trace for the error. Can anybody tell me what's happening? Will be very helpful if anybody encountered similar problem and knows the resolution. This almost 3 days I am trying get hold of this error.

    Below is the code:

    DataRow newRow = moduleEntity.Tables[tableName].NewRow();

    foreach(DataColumn copiedColumn in copiedColumns)

    {

    newRow[copiedColumn.ColumnName] = copiedRowView[copiedColumn.ColumnName];

    }

    moduleEntity.Tables[tableName].Rows.Add(newRow);

    The highlighted line generates the following error:

    Description:
    2009-01-11 21:00:19,657 [Main application thread] [ERROR] Presentation layer captured exception.
    Exception:  System.ArgumentNullException
    Detail:    
    System.ArgumentNullException: Value cannot be null.
    Parameter name: key
       at System.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument)
       at System.Collections.Generic.Dictionary`2.FindEntry(TKey key)
       at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
       at System.Data.DataView.MaintainDataView(ListChangedType changedType, DataRow row, Boolean trackAddRemove)
       at System.Data.DataViewListener.MaintainDataView(ListChangedType changedType, DataRow row, Boolean trackAddRemove)
       at System.Data.Index.<>c__DisplayClass5.<MaintainDataView>b__4(DataViewListener listener, ListChangedType type, DataRow row, Boolean track)
       at System.Data.Listeners`1.Notify[T1,T2,T3](T1 arg1, T2 arg2, T3 arg3, Action`4 action)
       at System.Data.Index.MaintainDataView(ListChangedType changedType, Int32 record, Boolean trackAddRemove)
       at System.Data.Index.InsertRecord(Int32 record, Boolean fireEvent)
       at System.Data.Index.ApplyChangeAction(Int32 record, Int32 action, Int32 changeRecord)
       at System.Data.DataTable.RecordStateChanged(Int32 record1, DataViewRowState oldState1, DataViewRowState newState1, Int32 record2, DataViewRowState oldState2, DataViewRowState newState2)
       at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Int32 position, Boolean fireEvent, Exception& deferredException)
       at System.Data.DataTable.InsertRow(DataRow row, Int32 proposedID, Int32 pos, Boolean fireEvent)
       at System.Data.DataRowCollection.Add(DataRow row)
       at Msc.MscEnterprise.Common.Presentation.Helper.DataSetHelper.UpdateModuleEntityTables(DataSet moduleEntityCopy, DataSet moduleEntity, String[] tableNames, String colPrimary, Boolean isQuoteType, Boolean isCompareDiff)

    I will really appreciate if anybody can help me resolve the issue.


    AD
    Monday, January 12, 2009 2:27 AM

Answers

  •  There is definitely some implementation change in System.Data assembly in .NET 3.5 vs .NET 1.1. For example, after calling NewRow() method on DataTable object, you can add this row in  a row collection. But the implementation of Adding a row to RowCollection has changed in .net3.5 for sure. If you look at the callstack you provided, SetNewRecordWorker is a new method in .net 3.5 and the implementation is a little different indeed.

    However, this issue has to do with why does the newRow object is null after you call on method NewRow()?
    DataRow newRow = moduleEntity.Tables[tableName].NewRow();

    NewRow() method has a very simple implementation, NewRow() method guarantees you that a new DataRow() object with the same schema will be created when you call on a correct table object.
    The reason I say getting a new object is guaranteed is because below is the implementation, so it always new DataRow guaranteeing you a reference to DataRow object on managed heap.

     return new DataRow(builder);
    protected internal DataRow(DataRowBuilder builder) { this.oldRecord = -1; this.newRecord = -1; this.tempRecord = -1; this._element = null; this._Table = builder._table; this.rowID = builder._rowID; this.tempRecord = builder._record; } 
    MSDN documentation has added a new line on DataTable.NewRow method remarks in .NET v3.5
    When you use NewRow to create new rows, the rows must be processed before you call Clear.

    I don't believe any event which gets fired as a result of adding a row can set newRow object to null unless you are passing that newRow object in some method or using in some other way which is not shown in the code snippet you have provided here.

    Are you calling DatTable.Clear() method anywhere? If you are then that is something you will have to probably look at, if you provide some more details on how and where the newRow object is used(if only newRow object is used somewhere else apart from the provided code snippet)

    • Marked as answer by Zhi-Xin Ye Friday, January 16, 2009 7:30 AM
    Wednesday, January 14, 2009 6:25 PM

All replies

  • Smells like the internal corruption you'd get when you use multiple threads but don't lock when you should.
    Hans Passant.
    Monday, January 12, 2009 10:09 AM
  • It looks like many people have encounterd the same problem. Is it a bug in SP1?
    AD
    Tuesday, January 13, 2009 9:13 PM
  • Since the exception type is "ArgumentNullException" with Parameter Name "key", what that means is DataRow object is null. If you look at the implementation detail of System.Data.DataView.MaintainDataView(ListChangedType changedType, DataRow row, Boolean trackAddRemove) either using reflector or the bcl source code, this exception is thrown while looking up the key which is datarow.

    As you mentioned, this exception is occuring after migrating to 3.5 but that should not really mean that there is some issue with .net 3.5 framework. Its possible that this exception might have been there in v1.1 but the exception was eaten. Rememeber in clr2.0 they have made the unhandled exception handler in machine.config configurable.

    Since I don't know the implementation so I can't say for sure what could be causing Datarow to be null, below are the check points

    1. Have you looked at the behavior when the value of "tableName" variable in moduleEntity.Tables[tableName].NewRow()? is some table which doesn't exist or the value is empty ?
    2. I am guessing this is a multithread app, have you verified the access to these variables? Are they on stack or are they member variables? if there are not on stack, do you have the lock?

    if this is something which you can't recreate in development environment, you have an option to catch the exception and log all the information or You will have to use WinDBG or CDB debugger to get a crash dump and analyze it.
    Wednesday, January 14, 2009 12:37 AM
  • Thank you very much for your response. You have rightly pointed out that the datarow is getting null. There is a change in the behaviour while adding rows in a datatable between v1.1 and v3.5. In v1.1, no events get fired while adding row but in v3.5, it triggers several events which is making the row null. Is there any change on this part in v3.5? Also, I would like to know how I can disable event firing while adding row in a datatable.
    AD
    Wednesday, January 14, 2009 3:49 PM
  •  There is definitely some implementation change in System.Data assembly in .NET 3.5 vs .NET 1.1. For example, after calling NewRow() method on DataTable object, you can add this row in  a row collection. But the implementation of Adding a row to RowCollection has changed in .net3.5 for sure. If you look at the callstack you provided, SetNewRecordWorker is a new method in .net 3.5 and the implementation is a little different indeed.

    However, this issue has to do with why does the newRow object is null after you call on method NewRow()?
    DataRow newRow = moduleEntity.Tables[tableName].NewRow();

    NewRow() method has a very simple implementation, NewRow() method guarantees you that a new DataRow() object with the same schema will be created when you call on a correct table object.
    The reason I say getting a new object is guaranteed is because below is the implementation, so it always new DataRow guaranteeing you a reference to DataRow object on managed heap.

     return new DataRow(builder);
    protected internal DataRow(DataRowBuilder builder) { this.oldRecord = -1; this.newRecord = -1; this.tempRecord = -1; this._element = null; this._Table = builder._table; this.rowID = builder._rowID; this.tempRecord = builder._record; } 
    MSDN documentation has added a new line on DataTable.NewRow method remarks in .NET v3.5
    When you use NewRow to create new rows, the rows must be processed before you call Clear.

    I don't believe any event which gets fired as a result of adding a row can set newRow object to null unless you are passing that newRow object in some method or using in some other way which is not shown in the code snippet you have provided here.

    Are you calling DatTable.Clear() method anywhere? If you are then that is something you will have to probably look at, if you provide some more details on how and where the newRow object is used(if only newRow object is used somewhere else apart from the provided code snippet)

    • Marked as answer by Zhi-Xin Ye Friday, January 16, 2009 7:30 AM
    Wednesday, January 14, 2009 6:25 PM
  • A late Comment, but I got this issue with .Net 4.0:

    I just added a DataRow to a DataTable like this:

    DataRow dr = somedatatable.NewRow();
    dr[0] = Guid.Empty;
    dr[1] = "sometext";
    somedatatable.Rows.Add(dr);
    

    Sometimes this worked fine, but sometimes I got the same System.ArgumentNullException for the value key.

    I followed the StackTrace and got my eyes on the line System.Data.DataView.MaintainDataView.

    In my case, I had some DataViews on my DataTable. When I changed a DataRow using a DataView before adding another one, the System.ArgumentNullException was thrown.

    One way solving the problem (I suggest there are some DependencyProperties in the background of System.Data since .Net 3.5, which handle changes in data), was DataTable.AcceptChanges() before adding the DataRow.

    But if you need the RowState for DB, this won't work. Since my DataViews are used in UI, I simply removed the UI-connection, added the new DataRow, and re-connected Data to UI.

    Just to make a guess: The complexity of adding DataRows to a DataTable with multiple DataViews (which are linked to an UI which is reacting on DataChanges, especially WPF-UI which threaded Container-Generation) may cause some Event-Crashing...but that's just suggested :-)

     

    Thursday, January 13, 2011 11:46 AM