来自异步序列化操作的MissingMethodException

时间:2013-07-29 10:17:18

标签: c# .net json.net .net-4.5 async-await

我已经从NuGet向Json.Net v5.06编写了一个小的Async库包装器,在更新了许多Telerik软件包之后,我的UnitTests开始失败并带有MissingMethodException

我已经创建了一个虚拟的非异步方法,因此我很困惑错误所在。

项目目标平台

.Net 4.5

x86 CPU

异步操作

    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

enter image description here

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);
}

无异步结果

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

测试示例失败

    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的异步测试

为了论证,我用一个虚拟的Task替换了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);
    }
}

问题

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

知道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>(() => 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));
}

1 个答案:

答案 0 :(得分:0)

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

enter image description here

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