来自异步序列化操作的 MissingMethodException

Posted

技术标签:

【中文标题】来自异步序列化操作的 MissingMethodException【英文标题】:MissingMethodException from Async serialisation operation 【发布时间】:2013-07-29 02:08:57 【问题描述】:

我已经从 NuGet 为 Json.Net v5.06 编写了一个小型异步库包装器,在更新了许多 Telerik 包后,我的 UnitTests 开始失败并显示 MissingMethodException。

我创建了一个有效的虚拟非 Async 方法,所以我很困惑错误在哪里。

项目目标平台

.Net 4.5

x86 处理器

异步操作

    public class JsonSerialiser : ISerialiser
    

        [InjectionConstructor]
        public JsonSerialiser(IStringCompression streamCompressor, ILog logger)
        
            if (streamCompressor == null) throw new ArgumentNullException("streamCompressor");
            if (logger == null) throw new ArgumentNullException("logger");

            XmlConfigurator.Configure();

            this.streamCompressor = streamCompressor;
            this.logger = logger;
        


        public async Task<string> SerialiseAsync<T>(T serialseObject) where T : class
        
            if (serialseObject == null) throw new ArgumentNullException("serialseObject");

            try
            
                return await JsonConvert.SerializeObjectAsync(serialseObject);
            
            catch (JsonSerializationException ex)
            
                logger.Error(ex);
                throw new SerialisationException("Could Not Serialse The Object", ex);
            
        
   

异步示例

现在将这段代码放在一起只是为了测试基本序列化,我在类构造函数中跳过了 null 检查。

    private async void button1_Click(object sender, EventArgs e)
    
        List<Part> parts = new List<Part>  new Part()  AbstractType = typeof(IOpcController), ConcreteType = typeof(OpcController) ,
                                                new Part()  AbstractType = typeof(ISerialiser), ConcreteType = typeof(JsonSerialiser) ,
                                                new Part()  AbstractType = typeof(IStringCompression), ConcreteType = typeof(StringGZipCompression);

        string serialisedResult = string.Empty;
        JsonSerialiser serialiser = new JsonSerialiser(null, null);
        serialisedResult = await serialiser.SerialiseAsync<List<Part>>(parts);
    

异步结果

这一代出现MissingMethodException

Method not found: 'System.Threading.Tasks.Task`1<System.String> Newtonsoft.Json.JsonConvert.SerializeObjectAsync(System.Object)'.

   at Helper.Core.Serialisation.Json.JsonSerialiser.<SerialiseAsync>d__0`1.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at Helper.Core.Serialisation.Json.JsonSerialiser.SerialiseAsync[T](T serialseObject)
   at OpcTester.Form1.<button1_Click>d__9.MoveNext() in c:\Users\phil.murray\Desktop\tmp\OpcTester\Form1.cs:line 44

无异步操作

只是为了检查是否是导致问题的方法的异步部分,我编写了一个非异步实现。

public string Serialise<T>(T serialseObject) where T : class

    if (serialseObject == null) throw new ArgumentNullException("serialseObject");

    try
    
        return  JsonConvert.SerializeObject(serialseObject);
    
    catch (JsonSerializationException ex)
    
        logger.Error(ex);
        throw new SerialisationException("Could Not Serialse The Object", ex);
    

无异步实现

private async void button1_Click(object sender, EventArgs e)

    List<Part> parts = new List<Part>  new Part()  AbstractType = typeof(IOpcController), ConcreteType = typeof(OpcController) ,
                                            new Part()  AbstractType = typeof(ISerialiser), ConcreteType = typeof(JsonSerialiser) ,
                                            new Part()  AbstractType = typeof(IStringCompression), ConcreteType = typeof(StringGZipCompression);

    string serialisedResult = string.Empty;
    JsonSerialiser serialiser = new JsonSerialiser(null, null);
    serialisedResult = serialiser.Serialise<List<Part>>(parts);

无异步结果

该方法完成列表并将其序列化为字符串。

失败的测试示例

    Test Name:  SerialiserSerialiseObjectExists
    Test FullName:  Helper.Tests.SerialiserTests.SerialiserSerialiseObjectExists
    Test Source:    c:\Perforce\Development\SharedAPIs\Helper.Core\Helper.Tests\SerialiserTests.cs : line 38
    Test Outcome:   Failed
    Test Duration:  0:00:00.0116216

    Result Message: 
    Test method Helper.Tests.SerialiserTests.SerialiserSerialiseObjectExists threw exception: 
    System.MissingMethodException: Method not found: 'System.Threading.Tasks.Task`1<System.String> Newtonsoft.Json.JsonConvert.SerializeObjectAsync(System.Object)'.
    Result StackTrace:  
    at Helper.Core.Serialisation.Json.JsonSerialiser.<SerialiseAsync>d__0`1.MoveNext()
       at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
       a

t System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at Helper.Core.Serialisation.Json.JsonSerialiser.SerialiseAsync[T](T serialseObject)
   at Helper.Tests.SerialiserTests.<SerialiserSerialiseObjectExists>d__3.MoveNext() in c:\Perforce\Development\SharedAPIs\Helper.Core\Helper.Tests\SerialiserTests.cs:line 40
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()

没有 Json.Net 的异步测试

只是为了争论,我用一个虚拟任务替换了 Json.Net 调用,它工作了,所以看起来问题在于使用 Await\Async 调用 Json.net。奇怪,因为它正在工作并且版本尚未更新。

public async Task<string> SerialiseAsync<T>(T serialseObject) where T : class

    if (serialseObject == null) throw new ArgumentNullException("serialseObject");

    try
    
        //return await JsonConvert.SerializeObjectAsync(serialseObject);
        return await Task.Run(() => string.Empty);
    
    catch (JsonSerializationException ex)
    
        logger.Error(ex);
        throw new SerialisationException("Could Not Serialse The Object", ex);
    

问题

现在,在我更新 Telerik 控件套件之前,异步方法 UnitTests 以前可以工作,并且我确实在许多真实世界的实例中测试了该操作。我并不是说 Telerik 更新导致了问题,因为这可能是巧合。在测试其他类(与 Json.Net 无关)时,还有许多其他异步测试用例通过。

知道 Async 方法有什么问题以及如何解决问题吗?

可能的解决方案

当我继续调查问题时,我发现问题可能出在 Json.Net 库中的 Async 调用中,因此我将 none Async 调用包装在 Task 中,如下所示,它起作用了

    public async Task<string> SerialiseAsync<T>(T serialseObject) where T : class
    
        if (serialseObject == null) throw new ArgumentNullException("serialseObject");

        try
        
            //return await JsonConvert.SerializeObjectAsync(serialseObject);
            return await Task.Run<string>(() => JsonConvert.SerializeObject(serialseObject));
        
        catch (JsonSerializationException ex)
        
            logger.Error(ex);
            throw new SerialisationException("Could Not Serialse The Object", ex);
        
    

出于兴趣,我下载了 Json.Net 的源代码并检查了 JsonConvert.SerializeObjectAsync 调用,它正在做同样的事情,所以我再次不确定潜在的问题。

public static Task<string> SerializeObjectAsync(object value, Formatting formatting, JsonSerializerSettings settings)

  return Task.Factory.StartNew(() => SerializeObject(value, formatting, settings));

【问题讨论】:

你试过重新安装Json.net吗? 是的,我尝试的第一件事。 【参考方案1】:

检查包含您正在执行的程序集的输出目录。 在 Newtonsoft.Json.dll 属性中,您会看到描述为“Json.Net Portable .Net 4.0”,并且此版本不提供 SerializeObjectAsync(您可以使用 ILSpy 检查程序集)。

用 .Net 4.5 版本替换 Json 程序集,它应该可以工作。

【讨论】:

dll 是 NuGet 包的 net45 文件夹中的版本。文件描述 - Json.Net;文件版本 - 5.0.6.16206。 看起来您的 AppDomain 中加载的程序集不是 net45 版本。您可以使用 fuslogvw 或手动列出 AppDomain 中加载的程序集来检查使用了哪个程序集。

以上是关于来自异步序列化操作的 MissingMethodException的主要内容,如果未能解决你的问题,请参考以下文章

使用异步操作时,来自 Vuex 的 NUXT 属性不会在 DOM 中更新

尽管有异步计算,Redux 的最小状态?

HttpClient来自官方的JSON扩展方法

NGXS:测试异步操作:自动订阅不起作用

阻塞的 Python 异步函数调用也会阻塞另一个异步函数

使用 WCF 中的任务构建异步操作合同的正确方法