Unable to determine the serialization information for "Expression"

3,259 views
Skip to first unread message

Marc Simkin

unread,
May 7, 2019, 4:17:47 PM5/7/19
to mongodb-user
Hi:

I'm trying to understand why I'm getting the error Unable to determine the serialization information for a => a.CurrentProcessingStep. when I attempt to update a record in my Mongo Database.

I thought that since I attributed the private fields with BsonElement, everything would be mapped correctly when I tried to do the update.

I'm using the C# driver version 2.8.0 with .NET 4.7.2.

The relevant parts of my document class:

[BsonIgnoreExtraElements]
[DebuggerDisplay("{Term}, Rule Status = {_ruleStatus}, Current Step = {_currentProcessingStep}")]
public class SearchTermInfo : AMongoConnectedObject
{
   
[BsonElement("CurrentProcessingStep")]
   
private ProcessingStep _currentProcessingStep;
 
   
[BsonElement("RuleStatus")]
   
private RuleStatus _ruleStatus;
 
   
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
   
public DateTime AddDateTime { get; set; }
 
   
[BsonIgnore]
   
[JsonIgnore]
   
public ProcessingStep CurrentProcessingStep
   
{
       
get => _currentProcessingStep;
       
set => AddHistoryRecord(value);
   
}
 
   
[BsonIgnore]
   
[JsonIgnore]
   
public RuleStatus RuleStatus
   
{
       
get => _ruleStatus;
       
set => AddHistoryRecord(value);
   
}
 

I build my filter definition as:

FilterDefinition<SearchTermInfo> filter = Builders<SearchTermInfo>.Filter.And(
   
Builders<SearchTermInfo>.Filter.Eq(a => a.Id, recordId),
   
Builders<SearchTermInfo>.Filter.Or(
       
Builders<SearchTermInfo>.Filter.Eq(a => a.CurrentProcessingStep, currentStep),
       
Builders<SearchTermInfo>.Filter.Exists("CurrentProcessingStep", false)
   
)
);

I also tried defining the CurrentProcessingStep statement as:

Builders<SearchTermInfo>.Filter.Eq("CurrentProcessingStep", currentStep),

This also results in the same error.

My call to update the document is:

UpdateResult results =
   
searchTermInfoCollection.MongoCollection.UpdateOne(filter, update, null, cancellationToken);

When I make the call I get the below exception:
? ex
{"Unable to determine the serialization information for a => a.CurrentProcessingStep."}
    Data: {System.Collections.ListDictionaryInternal}
    HResult: -2146233079
    HelpLink: null
    InnerException: null
    Message: "Unable to determine the serialization information for a => a.CurrentProcessingStep."
    Source: "MongoDB.Driver"
    StackTrace: "   at MongoDB.Driver.ExpressionFieldDefinition`2.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry, Boolean allowScalarValueForArrayField)
    at MongoDB.Driver.SimpleFilterDefinition`2.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry)\r\n
    at MongoDB.Driver.OrFilterDefinition`1.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry)\r\n   
    at MongoDB.Driver.AndFilterDefinition`1.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry)\r\n   
    at MongoDB.Driver.MongoCollectionImpl`1.ConvertWriteModelToWriteRequest(WriteModel`1 model, Int32 index)\r\n   
    at System.Linq.Enumerable.<SelectIterator>d__5`2.MoveNext()\r\n   
    at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)\r\n   
    at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)\r\n   
    at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation..ctor(CollectionNamespace collectionNamespace, IEnumerable`1 requests, MessageEncoderSettings messageEncoderSettings)\r\n   
    at MongoDB.Driver.MongoCollectionImpl`1.CreateBulkWriteOperation(IEnumerable`1 requests, BulkWriteOptions options)\r\n   
    at MongoDB.Driver.MongoCollectionImpl`1.BulkWrite(IClientSessionHandle session, IEnumerable`1 requests, BulkWriteOptions options, CancellationToken cancellationToken)\r\n   
    at MongoDB.Driver.MongoCollectionImpl`1.<>c__DisplayClass23_0.<BulkWrite>b__0(IClientSessionHandle session)\r\n   
    at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSession[TResult](Func`2 func, CancellationToken cancellationToken)\r\n   
    at MongoDB.Driver.MongoCollectionImpl`1.BulkWrite(IEnumerable`1 requests, BulkWriteOptions options, CancellationToken cancellationToken)\r\n   
    at MongoDB.Driver.MongoCollectionBase`1.UpdateOne(FilterDefinition`1 filter, UpdateDefinition`1 update, UpdateOptions options, Func`3 bulkWrite)\r\n   
    at MongoDB.Driver.MongoCollectionBase`1.UpdateOne(FilterDefinition`1 filter, UpdateDefinition`1 update, UpdateOptions options, CancellationToken cancellationToken)\r\n   
    at SaFileIngestion.FileProcessorEngine.LockRecord(Int64 recordId, ProcessingStep currentStep, CancellationToken cancellationToken) 
    in D:\\[FilePath]\\SaFileIngestion\\FileProcessorEngine.cs:line 195"
    TargetSite: {MongoDB.Driver.RenderedFieldDefinition`1[TField] Render(MongoDB.Bson.Serialization.IBsonSerializer`1[TDocument], MongoDB.Bson.Serialization.IBsonSerializerRegistry, Boolean)}


Any guidance you can provide would be appreciated.

Thanks

-marc

Marc Simkin

unread,
May 8, 2019, 4:40:47 PM5/8/19
to mongodb-user
I have a better understanding of what is happening.

The BsonElementAttribute sets the BsonMemberMap::ElementName property to be the value of the elementName string provided in the attribute declaration. At the same time the BsonMemberMap::MemberName property has the name of the field that had attribute applied.

When the BsonClassMapSerializer::TryGetMemberSerializationInfo method is called, the class map that was constructed for my SearchTermInfo class is being scanned for a member who's MemberName is "CurrentProcessingStep".  However, there is no member mapping that has that name.  

My question, shouldn't BsonElementNameAttribute set both the ElementName and the MemberName to be the value of the elementName string provided in the attribute declaration?  In this case "CurrentProcessingStep"

How can I fix this mapping?

Thanks

-marc

Robert Cochran

unread,
May 8, 2019, 4:55:09 PM5/8/19
to mongodb-user
Hi,

I wonder what version of MongoDB are you using? 

Can you provide a sample document?

Thanks so much

Bob

Marc Simkin

unread,
May 9, 2019, 10:04:59 AM5/9/19
to mongodb-user
The servers are 3.4.*, the point version various between Dev, QA, and Prod.

Here is the sample document:

    "_id" : NumberLong(0), 
    "Visits" : NumberLong(498), 
    "UpdateDateTime" : ISODate("2019-05-07T19:14:37.987+0000"), 
    "Term" : "harry potter", 
    "AddDateTime" : ISODate("2018-12-07T20:44:13.637+0000"), 
    "RuleStatus" : NumberInt(1), 
    "CurrentProcessingStep" : NumberInt(1), 
    "LastAtgCheckDateTime" : ISODate("2019-04-22T23:34:15.155+0000"), 
    "LastFetchCheckDateTime" : ISODate("2019-04-16T18:49:36.493+0000"), 
    "PrimaryEan" : NumberLong(9780545596275), 
    "PrimaryWorkId" : NumberLong(1114540338), 
    "LastRuleValidationDateTime" : ISODate("2019-04-22T21:33:13.023+0000"), 
    "LastAugmentation" : ISODate("2019-04-15T19:58:28.370+0000"), 
    "WorkIds" : [
        NumberLong(1108948862), 
        NumberLong(1110118103), 
        NumberLong(1114540739), 
        NumberLong(12288041), 
        NumberLong(25097628), 
        NumberLong(6291175), 
        NumberLong(1100042956), 
        NumberLong(7566695), 
        NumberLong(1013876081), 
        NumberLong(27547356), 
        NumberLong(1100178339), 
        NumberLong(1004338523), 
        NumberLong(1004395694), 
        NumberLong(1102662272), 
        NumberLong(1110292748), 
        NumberLong(1100079342), 
        NumberLong(1100036321), 
        NumberLong(1008655339), 
        NumberLong(1104403088), 
        NumberLong(1107819500), 
        NumberLong(1104510835), 
        NumberLong(1100178133), 
        NumberLong(1100041270), 
        NumberLong(1113898358)
    ], 
    "LastExportDateTime" : ISODate("2019-04-15T19:01:42.949+0000")
}

Can you enlighten me how these questions are relevant to what is a C# Driver issue?

Robert Cochran

unread,
May 12, 2019, 10:08:07 AM5/12/19
to mongodb-user
Hi!

Perhaps you are having some driver and .NET version incompatibilities.

There is no 2.8.0 version of the MongoDB C#.NET driver. Please refer to this document. The same link seems to be stating that the 2.7 C# driver is recommended to be used with .NET version 4.6.

It is good practice to indicate your operating system versions for the MongoDB server and client machines; to provide the exact versions of the MongoDB server and the mongo client shell version; and to provide a short but complete code example which illustrates your issue. Also provide one or two sample documents that can be worked with. This allows others to try to reproduce your issue. 

Based on your problem statement I'm confused about what your ultimate goal is. It does however seem that your MongoDB driver version is probably incompatible with .NET version 4.7.2. You may want to review the link I provided you, and try your code again on a test machine that has the recommended driver and .NET versions installed.

Lastly, MongoDB versions 3.4.x will go to end-of-life in January 2020. See the support policy. That date is not far away and you should consider upgrading to a supported version of MongoDB.

Thanks so much

Bob 
Message has been deleted

Marc Simkin

unread,
May 12, 2019, 11:06:30 AM5/12/19
to mongodb-user
1) If 2.7 is the last version that support, why is 2.8 published to NuGet?
2) .NET 4.6 is considered part of Windows 8.1Windows 8.1 lost mainstream support as of Jan 9th, 2018

If I'm to understand your position, you will only support 2.7 on .NET 4.6, even though the MongoDB organization has published 4.8.  At the same time, you will only support .NET 4.6  which has basically been  EOL-ed by Microsoft.

As for the other requested info, I will get it two you.  However, this is a client driver issue.  I know because I spent the day last Thursday, debugging the client code to understand what was happening.

I know the end of support date for 3.4.x.  I'm working on a plan to get all the code in my organization updated to use the latest drivers, so we can then update our clusters.  Not an easy task when there are over 1,000 applications, some which have been running for 4+ years without changes.

John Murphy

unread,
May 12, 2019, 10:00:00 PM5/12/19
to mongodb-user

Hi Marc,

Apologies for confusion on this thread. Bob is a community user trying to help with your issue and does not work for MongoDB, Inc.

The current release of the .NET driver is indeed 2.8.0, but unfortunately it looks like the driver documentation has not been updated to reflect this yet. The minimum .NET version requirement for this is 4.5.2, however newer .NET versions are also supported. There is also a beta release of the next version of the .NET driver (2.9.0-beta1), which is the version that will be released with the MongoDB 4.2 server.

My question, shouldn’t BsonElementNameAttribute set both the ElementName and the MemberName to be the value of the elementName string provided in the attribute declaration? In this case “CurrentProcessingStep”

The BsonElementNameAttribute is used to control what element name will be used in the resulting Bson document. The MemberName will always be the actual name of the field. As you may be aware from debugging the MongoDB driver code, due to the [BsonIgnore] attribute on the CurrentProcessingStep field, it is not included in the class map and therefore not available for use in a strongly typed filter.

How can I fix this mapping?

Without knowing the behaviour of the AddHistoryRecord method, are you able to use the public properties of the SearchTermInfo object for serialization, instead of attempting to use the private member variables?

Kind Regards,
John Murphy

Marc Simkin

unread,
May 13, 2019, 5:05:52 AM5/13/19
to mongodb-user
Hi John:

Thank you for your response.  Apology accepted.

Back to the issue at hand.

The AddHistoryRecord method is designed to be an audit trail.  If I expose the CurrentProcessIngStep or RuleStatus properties as public I need to do either of the following:

1) Make the property setters private, so only the serialization process can access the methods
2) Find a way of determining if the setter method is being called as a result of serialization or application code that actually changes the properties state.

I've already done #1. It's not ideal, but it will work.

Ideally, I would like to do #2, so that I don't need to mark the property setters private.  I'm looking for something like the OnSerializing, OnSerialized, OnDeserializing, OnDeserialized attributes.  This would allow my code to bypass the AddHistoryRecord method if the class is being deserialized.

Does something like these attributes exist?

Why wasn't a way designed to allow a mapping to be added to the strongly typed filter?  Is there any way to extend the serialization code to add a new mapping, without redesigning the whole process?

Thank you.

-marc

John Murphy

unread,
May 15, 2019, 2:54:05 AM5/15/19
to mongodb-user

Hi Marc,

Does something like these attributes exist?

Not exactly. If your class implements ISupportInitialize, the driver will call the BeginInit method before deserialization and the EndInit method upon completion. This could allow you to set a flag that will control the use of the AddHistoryRecord method.

An alternate, possibly cleaner way, would be to provide a private constructor for the MongoDB C#/.NET driver to use when creating a SearchTermInfo object during deserialization. To implement this creation customisation, you would simply need to have a private constructor that sets the _currentProcessingStep and _ruleStatus fields, followed by decorating the private constructor with the [BsonConstructor] attribute.

Example code would look like:

[DebuggerDisplay("{Term}, Rule Status = {_ruleStatus}, Current Step = {_currentProcessingStep}")]
public class SearchTermInfo : AMongoConnectedObject

{
    private ProcessingStep _currentProcessingStep;
    private RuleStatus _ruleStatus;

    public SearchTermInfo() { }

    [BsonConstructor]
    private SearchTermInfo(ProcessingStep currentProcessingStep, RuleStatus ruleStatus)
    {
        _currentProcessingStep = currentProcessingStep;
        _ruleStatus = ruleStatus;
    }

    [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
    
public DateTime AddDateTime { get; set
; }

    
public ProcessingStep CurrentProcessingStep
    {
        get => _currentProcessingStep;
        set => AddHistoryRecord(value
);
    }

    
public RuleStatus RuleStatus
    {
        get => _ruleStatus;
        set => AddHistoryRecord(value);
    }
}

Why wasn’t a way designed to allow a mapping to be added to the strongly typed filter?

Deserialization leverages reflection in a lot of places, so there is currently no concept of an exposed map for member field names.

Is there any way to extend the serialization code to add a new mapping, without redesigning the whole process?

The areas of serialization that can be customised are outlined in the member customisation documentation. If you have more advanced use cases we provide the ability to implement a custom serializer, whereby you can completely control what happens during serialization/deserialization.

Hopefully this provides some useful information for you, please let me know if you have further questions.

Kind Regards,
John Murphy

Marc Simkin

unread,
May 15, 2019, 9:36:09 AM5/15/19
to mongodb-user
John:

Thank you for the explanations.

Please consider this closed.

-marc
Reply all
Reply to author
Forward
0 new messages