Unexpected character encountered while parsing value when using var result = data.ContentAs<string>();

When using SDK 3.x when trying to get a JSON document from Couchbase and using

var result = data.ContentAs<string>();

It always return this error message:

“Unexpected character encountered while parsing value: {. Path ‘’, line 1, position 1.”

I checked CB and the JSON data is valid, tried this with many different files and same result.

Now when using the actual type of the object or Type < dynamic> no error.

So if I use this instead of String:

var result = data.ContentAs<ConnectionTestData>();
or
var result = data.ContentAs<dynamic>();

It works.

But,
var result = data.ContentAs<string>();

Does not.

With previous version of SDK 2.x did not had this issue.

Was using this with no issues:

var data = CouchBaseClient.GetDocument<string>(this.type, this.jnid);

Then convert to actual Object:

var couchAccount = data.Document.Content.ToFastObject<Customer>();

We have 100+'s of files that are using Is there any way to get this to work?

Thanks,

Brian Davis

1 Like

@Brian_Davis

Can you provide the content of the document?

ContentAs is really only applicable to storing data as a string in the format "string wrapped in quotes". For handling a raw string, without quotes, you’ll want to use the RawStringTranscoder https://github.com/couchbase/couchbase-net-client/blob/master/src/Couchbase/Core/IO/Transcoders/RawStringTranscoder.cs.

Content of one of the Docs:

{
“id”: 1,
“date”: “2020-11-09T15:50:31.471788-05:00”
}

@btburnett3

What would be the best way to handle cases when we have

data.ContentAs<string>();

We have 100’s of files that are using even through the content itself on CB is JSON, not a String in JSON format.

Other areas we are using actual Types, so it is mixed between the two.

@btburnett3

Is there a way to configure Couchbase to just use the RawStringTranscoder just for when the .ContentAs is a String? for all other types, use the default transcoder?

data.ContentAs<string>();

Hi @Brian_Davis -

The Transcoder API was redesigned in SDK3; its now much more specialized and this type of conversion doesn’t work with the default JsonTranscoder. Fortunately, we do have another transcoder which mimics the sdk2 behavior called the LegacyTranscoder which should be able to handle this for you.

-Jeff

Hi @jmorris

The LegacyTranscoder would that also use SDK 3.x api’s too? so it would allow both SDK 2.x “by mimics” and SDK 3.x?

Eventually we will be replacing all <string> with <ActualType> but need to be able to do this side by side eventually and not all at once.

So if I set up couchbase to use the LegacyTranscoder that should do it then?

How do I set up the Couchbase client to use it?

Thanks again for your help :slight_smile:

Brian Davis

In the docs all code examples are not loading.

You can set the transcoder in the ClusterOptions or on the individual Options for any operation.

-Jeff

There is an open ticket to do this: Loading...

-Jeff

_clusterConfiguration.Transcoder = new LegacyTranscoder();

The LegacyTranscoder, works for <string> now, but now throwing error when using actual type <ConnectionTestData>

InnerException = {“Cannot access a disposed object.\r\nObject name: ‘DataFlowConnectionPool’.”}

I need to be able to use use both <string> and <StronglyTyped> objects

Is there a way to just set it to be used when type is <string> ? for all other Types use the default transcoder?

@Brian_Davis

That sounds like a different problem to me. Are you disposing the cluster/bucket on requests instead of reusing?

I am using a Static class, so should not dispose until the application is shutdown I believe.

I am trying to configure the Get Option.

Think would be best just to set it there so this only effects one method :slight_smile:

Just not sure on how to do it.

@Brian_Davis

I’d recommend a static field storing an instance of LegacyTranscoder, then pass that static field to options.Transcoder(…).

@btburnett3 and @jmorris

Thanks for your help!

I think I got it figured out on what to do, this so far seems to be working.

Looking deeper into this, I do think you encountered a bug as the JsonTranscoder should handle this case: https://issues.couchbase.com/browse/NCBC-2706

Note there is a patch and should be available in 3.0.8 release next month.

After much thought, I think the JsonTranscoder is working as expected; you can mix and match any of the other Transcoders for your use-cases or write your own if you have a corner case not covered by the ones that come with the SDKs.

-Jeff

1 Like

Hello!
I have just posted a thread, on this exact subject (not sure why I didnt see it in the suggestions, but nevermind).

However, I think that the solutions presented here are way to convoluted/complex. It is not clear to me why Newtonsoft JSON should be involved when I clearly specify that I want a string, and nothing else. LegacyTranscoder or not, the data should be parsed as a string and returned, without a developer needing to to complex workarounds.

Can I suggest that you update the SDK so transcoder options are not necessary?

@wagger

If you’d like to operate in such a model, feel free to configure your cluster to use the LegacyTranscoder globally. This transcoder is compatible with the 2.x SDK approach, which did do things like you are suggesting.

The new approach is to vastly simplify the transcoder operations. During the 2.x SDK phase, it was determined that the LegacyTranscoder approach was creating more confusion, not less. For example, if I’m reading/writing strings, should they be JSON encoded with double-quotes and backslash escaping, or not? There was no clear way to indicate one situation or the other, the LegacyTranscoder was forced to make assumptions that may not be accurate for all use cases.

The new approach is to have the JsonTranscoder assume that any type you send it is meant to be encoded as JSON, as clearly indicated by using the JsonTranscoder. If you send it a string, it will assume it’s wrapped in quotes and escaped as JSON. If you send it a byte array, it will output it as a JSON array of numbers. This provides a clear and understandable way of handling the data to and from the server which is consistent across SDKs from all development platforms. Other behaviors like directly decoding strings without escaping or reading raw binary data are also supported using alternative transcoders like RawStringTranscoder and RawBinaryTranscoder. This is more expressive than the previous LegacyTranscoder approach, allowing the developer to specify which way they want the type to be serialized/deserialized (as JSON or raw) rather than always assuming raw.

1 Like

Thanks for the answer and reasoning behind, appreciated.

So, I then assume that nothing is saved as “strings” in Couchbase, but in some other format, and to get a string requires some translation of the underlying persistance format, and thus, you need to specify how that string is created from whatever-format-couchbase-is-using-under-the-hood?

@wagger

Basically correct, everything is stored in Couchbase as binary data. Though Couchbase does recognize UTF-8 encoded JSON (by far the most common) to provide functions like indexing and querying. This is typically indicated by the transcoder by applying a JSON data format flag when persisting.

1 Like