Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Azure Search .NET SDK throws InvalidOperationException with SerializationBinder #3441

Closed
NhanNTWPV opened this issue Jul 1, 2017 · 34 comments
Assignees
Labels
Search Service Attention This issue is responsible by Azure service team.

Comments

@NhanNTWPV
Copy link

NhanNTWPV commented Jul 1, 2017

An exception thrown when entering operations with index (Exists, Create, Delete...). Encountered with .NET Core SDK 1.0.4 on Mac OSX 10.12.4

Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: Cannot get SerializationBinder because an ISerializationBinder was previously set.
   at Newtonsoft.Json.JsonSerializer.get_Binder()
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.Rest.Azure.JsonSerializerExtensions.WithoutConverter(JsonSerializer serializer, JsonConverter converterToExclude)
   at Microsoft.Rest.Azure.CloudErrorJsonConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject[T](String json, JsonSerializerSettings settings)
   at Microsoft.Azure.Search.IndexesOperations.<GetWithHttpMessagesAsync>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Search.ExistsHelper.<ExistsFromGetResponse>d__0`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Search.IndexesOperationsExtensions.<ExistsAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Search.IndexesOperationsExtensions.Exists(IIndexesOperations operations, String indexName, SearchRequestOptions searchRequestOptions)
@NhanNTWPV NhanNTWPV changed the title Azure Search .Net SDK throws InvalidOperationException with SerializationBinder Azure Search .NET SDK throws InvalidOperationException with SerializationBinder Jul 1, 2017
@hovsepm hovsepm added the Search label Jul 3, 2017
@hovsepm
Copy link
Contributor

hovsepm commented Jul 3, 2017

@NhanNTWPV please add a reference to the latest available Microsoft.Rest.ClientRuntime.Azure in your project.

@brjohnstmsft
Copy link
Member

Possibly related: #2552

@NhanNTWPV Can you confirm which versions of the following NuGet packages you are using in your project?

  • Microsoft.Rest.ClientRuntime.Azure
  • Newtonsoft.Json

@NhanNTWPV
Copy link
Author

NhanNTWPV commented Jul 3, 2017

@brjohnstmsft Confirm working with Microsoft.Rest.ClientRuntime.Azure 3.3.8 & Newtonsoft.Json 10.0.2. Can you make them default dependencies?

@brjohnstmsft
Copy link
Member

@NhanNTWPV Thanks for the confirmation. We're working on it. I'll keep this issue open to track this work.

@msfcolombo
Copy link

Any update on this?

I have a similar exception using Microsoft.Azure.Management.Dns. It appears related to version 10.0.2 of Newtonsoft.Json.

System.InvalidOperationException: Cannot get SerializationBinder because an ISerializationBinder was previously set.
at Newtonsoft.Json.JsonSerializer.get_Binder()
 --- End of inner exception stack trace ---
    at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
   at Microsoft.Rest.Azure.JsonSerializerExtensions.WithoutConverter(JsonSerializer serializer, JsonConverter converterToExclude)
   at Microsoft.Rest.Azure.CloudErrorJsonConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject[T](String json, JsonSerializerSettings settings)
   at Microsoft.Azure.Management.Dns.RecordSetsOperations.<GetWithHttpMessagesAsync>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Management.Dns.RecordSetsOperationsExtensions.<GetAsync>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Management.Dns.RecordSetsOperationsExtensions.Get(IRecordSetsOperations operations, String resourceGroupName, String zoneName, String relativeRecordSetName, RecordType recordType)

@brjohnstmsft
Copy link
Member

@msfcolombo I can't speak for Azure DNS, but we haven't been able to ship an updated version of the Azure Search SDK yet. Have you tried using Microsoft.Rest.ClientRuntime.Azure 3.3.8 or higher with Newtonsoft.Json 10.0.2? That combination seems to work for others.

@msfcolombo
Copy link

Thanks. I upgraded to Microsoft.Rest.ClientRuntime.Azure 3.3.10 and that fixed the issue. This is covered at the already-closed #2552, so I think you can close this as well.

@brjohnstmsft
Copy link
Member

The fix for this issue shipped with version 3.0.5 to NuGet.

@isaacabraham
Copy link

@brjohnstmsft Something isn't quite right. I've just upgraded to 3.0.5, with Newtonsoft.Json Newtonsoft.Json (10.0.3) and Microsoft.Rest.ClientRuntime.Azure (3.3.10) but am still seeing this exception.

@isaacabraham
Copy link

OK I think you can ignore me - this is due (I think) to an old version of Newtonsoft.Json being picked up in my script!

@isaacabraham
Copy link

OK, I might need some pointers here: I'm seeing the following stack trace when my script goes pop:

System.AggregateException: One or more errors occurred. ---> System.MissingMethodException: Method not found: 'Newtonsoft.Json.SerializationBinder
Newtonsoft.Json.JsonSerializerSettings.get_Binder()'.
   at Microsoft.Azure.Search.JsonUtility.CopySettings(JsonSerializerSettings baseSettings)
   at Microsoft.Azure.Search.JsonUtility.CreateSerializerSettings[T](JsonSerializerSettings baseSettings, Boolean useCamelCase)
   at Microsoft.Azure.Search.JsonUtility.CreateTypedSerializerSettings[T](JsonSerializerSettings baseSettings, Boolean useCamelCase)
   at Microsoft.Azure.Search.DocumentsOperations.IndexWithHttpMessagesAsync[T](IndexBatch`1 batch, SearchRequestOptions searchRequestOptions, Dictionary`2 customHeaders, CancellationToken cancellationToken)
   at Microsoft.Azure.Search.DocumentsOperationsExtensions.<IndexAsync>d__13`1.MoveNext()
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
   at <StartupCode$FSI_0008>.$FSI_0008.main@() in c:\Users\Isaac\Source\Repos\houseprice-sales\build.fsx:line 43
---> (Inner Exception #0) System.MissingMethodException: Method not found: 'Newtonsoft.Json.SerializationBinder Newtonsoft.Json.JsonSerializerSettings.get_Binder()'.
   at Microsoft.Azure.Search.JsonUtility.CopySettings(JsonSerializerSettings baseSettings)
   at Microsoft.Azure.Search.JsonUtility.CreateSerializerSettings[T](JsonSerializerSettings baseSettings, Boolean useCamelCase)
   at Microsoft.Azure.Search.JsonUtility.CreateTypedSerializerSettings[T](JsonSerializerSettings baseSettings, Boolean useCamelCase)
   at Microsoft.Azure.Search.DocumentsOperations.IndexWithHttpMessagesAsync[T](IndexBatch`1 batch, SearchRequestOptions searchRequestOptions, Dictionary`2 customHeaders, CancellationToken cancellationToken)
   at Microsoft.Azure.Search.DocumentsOperationsExtensions.<IndexAsync>d__13`1.MoveNext()<---

I've looked at the old version of the Azure Search SDK and indeed there was a method called Microsoft.Azure.Search.JsonUtility.CopySettings which copied across Binder. If this code no longer exists, it suggests that I'm somehow picking up the wrong version of the Search SDK - yet I have indeed pulled down version 3.0.5.0 from Nuget.

Any ideas?

@brjohnstmsft
Copy link
Member

@isaacabraham Thanks for reporting this. I’m not sure what’s going on. We’ll investigate. Re-opening this issue.

@brjohnstmsft brjohnstmsft reopened this Feb 10, 2018
@brjohnstmsft
Copy link
Member

@isaacabraham I was able to repro the error you're seeing, but only if I explicitly reference Newtonsoft.Json 11.0.1-beta3 from my test project. It appears that in version 11, JSON.NET is deprecating the Binder property in favor of the SerializationBinder property. I'm not sure why your project is picking up a beta version of JSON.NET, but if you're able to use 10.0.3, it should work.

In the meantime I'll figure out if it's safe to change the Azure Search SDK to use SerializationBinder instead of Binder. It may not be because we need to support older versions of JSON.NET.

@brjohnstmsft
Copy link
Member

Just confirmed that we can't use SerializationBinder yet because Azure .NET SDKs still need to support JSON.NET versions prior to 10. Closing this issue since there's nothing we can do in the Azure Search SDK for now.

@isaacabraham
Copy link

Thanks for checking this out, I'll see if I can repro this. It might be worth changing the max version of Newtonsoft in the Search package to 10.x if it isn't already to prevent dependency issues.

@brjohnstmsft
Copy link
Member

@isaacabraham Good point.

FYI @shahabhijeet @markcowl We found an incompatibility between JSON.NET 11 beta and Microsoft.Azure.Search. Specifically, the JsonSerializerSettings.Binder property, which Microsoft.Azure.Search currently references, has been deleted (it was marked as deprecated in JSON.NET 10). I don't know if this change will affect ClientRuntime or not, but I thought I should give you folks a heads up. Do you see any harm in setting the max version of Newtonsoft.Json to 10 in AzSdk.reference.props?

@brjohnstmsft brjohnstmsft reopened this Feb 13, 2018
@shahabhijeet
Copy link
Member

shahabhijeet commented Feb 17, 2018

@isaacabraham I assume you are fine when you use newtonsoft 10.0.3 with Search SDK.

@brjohnstmsft an alternative to fix this problem is to not to initialize deprecated properties in your CopySettings function (leave out TypeNameAssemblyFormat, ReferenceResolver, Binder)
or
update Binder property to baseSetting.SerializationBinder

@isaacabraham
Copy link

@brjohnstmsft also - is there a reason why the Net452 and NetStandard14 versions have different minimum versions of Newtonsoft JSON (i.e. >= 6.0.8 vs >= 9.0.1) ?

@isaacabraham
Copy link

@brjohnstmsft I think I've traced the cause of my particular issue - it's because my script is (for some as-yet unknown reason) implicitly picking up the Newtonsoft.Json assembly inside C:\Program Files\Microsoft SDKs\Azure\.NET SDK\v2.9\bin\plugins\Diagnostics. This contains an old version of the assembly (6.0.8.18111).

6.0.8 does seem to actually contain a Binder property on the Newtonsoft.Json.JsonSerializerSettings type, but it returns a different type to what's expected in 10.x: System.Runtime.Serialization.SerializationBinder vs Newtonsoft.Json.SerializationBinder. This would explain the runtime error I'm seeing.

@shahabhijeet
Copy link
Member

shahabhijeet commented Feb 22, 2018

@isaacabraham currently Azure PowerShell need newtonsoft 6.x.x for .NET 452 target Fx, but all .NET Core Azure SDK are supporting 9.x.x, hence you see two separate minimum versions.

@isaacabraham
Copy link

@shahabhijeet I don't understand - what does Powershell have to do with the minimum version of the Newtonsoft JSON. Are you suggesting that there's actually the possibility of different behaviour between 452 and Core simply because of PowerShell?

@brjohnstmsft
Copy link
Member

@shahabhijeet FYI, @isaacabraham is the one you should be talking to, not @NhanNTWPV :)

@isaacabraham Wow, I didn't realize JSON.NET 6.0.8 doesn't even have the Binder property. What a mess. I'm going to take a deeper look at it and see if it would be safe to just remove the usage of Binder from the CopySettings method altogether. That method is copying everything out of an abundance of caution (in case customers tweak serialization settings), but if it's going to cause headaches like this, the paranoia is not worth it.

Regarding PowerShell, I believe @shahabhijeet is referring to the Azure PowerShell CmdLets, which depend on various Azure SDKs (excluding Azure Search), which depend on Microsoft.Rest.ClientRuntime, which depends on Newtonsoft.Json. I don't know the details of why they needed to use JSON.NET 6.0.8 for the PowerShell CmdLets. Probably another backward compatibility issue like this one.

@isaacabraham
Copy link

@brjohnstmsft Well, it has "a" Binder property - but a different one :-)

Regarding the different versions of Newtonsoft across different TFMs - this strikes me at first glance as as a disaster waiting to happen. Picture situations like: you build some code and run it on the net452 TFM. You then change over to the netstandard TFM, and suddenly you've now silently upgraded to a different version of Newtonsoft JSON. You run the same code but now you're getting different behaviour at runtime. Do you know? Will you ever know? Maybe. Maybe not...

@brjohnstmsft
Copy link
Member

@isaacabraham I agree this is a terrible state of affairs. @shahabhijeet and I are having an offline discussion about possible solutions.

@stpriyanka
Copy link

I had same issue with .Net core. It solved just after degrading newtonsoft.Json to version 10.2. I guess with any of 10 versions it should work

@brjohnstmsft
Copy link
Member

@isaacabraham I have a PR out that includes the fix for this issue. First we'll fix it in the preview SDK (5.x-preview), then in the stable version of that (5.x, which I'm working on and should release in the coming weeks). I wasn't planning to hotfix it in 3.0. Please let me know if that's a blocker for you.

@shahabhijeet
Copy link
Member

@isaacabraham Azure PowerShell consumes Azure SDKs that are targeting .NET 4.5.2 and there are quite few other modules that are still stuck at newtonsoft json 6.0.8, so we are steadily upgrading each of those dependencies to newtonsoftjson 10.x.x until then all SDKs that are targeted .NET 4.5.2 have their minimum version dependency to newtonsoft json 6.x.x

@isaacabraham
Copy link

@shahabhijeet understood. It's just not a good place to be - essentially this breaks the contract for the Search service between different TFMs (and therefore for all .NET developers) for the same of PowerShell. I'm still not sure where the dependency is because this is a decision for Azure Search to make - are you suggesting that there's a huge number of devs using Azure Search from PowerShell compared to e.g. C#?

@brjohnstmsft
Copy link
Member

@isaacabraham All (or nearly all) Azure .NET SDKs, including Azure Search, rely on the Microsoft.Rest.ClientRuntime package. This package in turn takes the dependency on JSON.NET. So the issue exists because the Azure PowerShell Cmdlets and the Azure Search SDK both take a dependency on ClientRuntime.

@isaacabraham
Copy link

@brjohnstmsft ah, that makes more sense - thanks for explaining. So theoretically a new version of ClientRuntime could be made to "fix" this. At any rate the fix you've done should solve this issue anyway :)

@brjohnstmsft
Copy link
Member

It took longer than I thought, but we finally shipped a new SDK version with a hopefully comprehensive fix for the JSON.NET compatibility issues. It's now available on NuGet. Closing this issue, hopefully for the last time. Thanks for your patience.

@RicoSuter
Copy link

@brjohnstmsft how did you fix this problem?

@brjohnstmsft
Copy link
Member

@RSuter The later manifestation of the issue was specific to custom code in the Azure Search SDK that copies properties between JsonSerializerSettings instances. I solved it by using reflection and dynamic compilation to copy the properties, so that it doesn't matter what version of JSON.NET is present. Feel free to take a look at the code here:

// Unfortunately we can't just assign the properties of JsonSerializerSettings between instances,

@RicoSuter
Copy link

RicoSuter commented May 30, 2018

@brjohnstmsft Thanks for the link, we have the exact same problem: https://github.com/RSuter/NSwag/blob/master/src/NSwag.AspNet.WebApi/JsonExceptionFilterAttribute.cs#L106

It would be great if this is part of Newtonsoft.Json (to avoid maintaining this list). Or is there another way to create a serializer settings copy? /cc @JamesNK

@brjohnstmsft brjohnstmsft reopened this Aug 21, 2018
@bsiegel bsiegel added the Service Attention This issue is responsible by Azure service team. label Sep 26, 2018
@github-actions github-actions bot locked and limited conversation to collaborators Mar 29, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Search Service Attention This issue is responsible by Azure service team.
Projects
None yet
Development

No branches or pull requests

9 participants