自定义WCF通道在ChannelBase.EndInvoke上抛出NullReferenceException

时间:2017-08-09 10:07:07

标签: c# wcf

我有一个非常简单的WCF服务,我需要编写一个自定义客户端,必须覆盖CreateChannel,但是当我在EndInvoke实现中调用ChannelBase时,我得到< / p>

System.NullReferenceException occurred
  HResult=0x80004003
  Message=Object reference not set to an instance of an object.
  Source=System.ServiceModel
  StackTrace:
   at System.ServiceModel.Dispatcher.ProxyOperationRuntime.MapAsyncEndInputs(IMethodCallMessage methodCall, IAsyncResult& result, Object[]& outs)
   at System.ServiceModel.ClientBase`1.ChannelBase`1.EndInvoke(String methodName, Object[] args, IAsyncResult result)
   at Client.TestServiceClient.TestServiceChannel.<SayHello>b__1_0(IAsyncResult result) 
   at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)

我不确定我做错了什么,StackTrace也没有帮助我,google没有找到任何有用的东西。我的解决方案是使用.net 4.6.2并且对服务的调用成功(它打印到控制台),但是EndInvoke从框架代码中抛出。非常感谢任何帮助。

最小的重复:

namespace Service {
    using System;
    using System.ServiceModel;

    [ServiceContract]
    public interface ITestService {
        [OperationContract]
        void SayHello();
    }

    public class TestService : ITestService {
        public void SayHello() => Console.WriteLine("Hello");
    }
}


namespace Host {
    using System;
    using System.ServiceModel;
    using Service;

    internal static class Program {
        private static void Main() {
            var host = new ServiceHost(typeof(TestService));
            host.AddServiceEndpoint(typeof(ITestService), new BasicHttpBinding(BasicHttpSecurityMode.None), "http://localhost:13377/");
            host.Open();
            Console.ReadLine();
        }
    }
}

namespace Client {
    using System;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using Service;

    public class TestServiceClient : ClientBase<ITestService>, ITestService {
        public TestServiceClient(Binding binding, EndpointAddress remoteAddress) : base(binding, remoteAddress) {}

        public void SayHello() => Channel.SayHello();

        protected override ITestService CreateChannel() => new TestServiceChannel(this);

        private class TestServiceChannel: ChannelBase<ITestService>, ITestService {
            public TestServiceChannel(ClientBase<ITestService> client) : base(client) {}

            public void SayHello() => base.BeginInvoke("SayHello", new object[0], result => base.EndInvoke("SayHello", new object[0], result), null);
        }
    }

    internal static class Program {
        private static void Main() {
            var client = new TestServiceClient(new BasicHttpBinding(BasicHttpSecurityMode.None), new EndpointAddress("http://localhost:13377/"));
            client.SayHello();
            Console.ReadLine();
        }
    }
}

1 个答案:

答案 0 :(得分:0)

原因是只有在服务合同具有BeginInvoke / EndInvoke对方法时,才允许调用Begin... / End...对。 WCF在内部分析契约接口,如果它看到看起来像异步的方法(从“开始”开始,有3个或更多参数等),那么它初始化一些内部结构,这些内部结构稍后由EndInvoke使用(在MapAsyncEndInputs)。

如果要将WCF基础结构用于异步调用,则客户端服务协定接口应为异步样式。或者,您需要包装整个通道对象以在顶部提供异步操作。

您可以查看this answer(选项#3),了解基于任务的异步模式是如何完成的。