如果你和我一样,想当然用基于委托或事件异步模型来调用 WCF Operation。那么恭喜你,打破脑袋你也不会明白为啥 BeginInvoke() 没效果。
[ServiceContract]
interface IMyService
{
[OperationContract]
void Test();
}
class MyService : IMyService
{
public void Test()
{
Console.WriteLine("Begin {0}...", DateTime.Now);
Thread.Sleep(3000);
Console.WriteLine("End {0}...", DateTime.Now);
}
}
class Program
{
private static void Client()
{
var binding = new BasicHttpBinding();
var address = new EndpointAddress("http://localhost:90");
var channel = ChannelFactory<IMyService>.CreateChannel(binding, address);
using (channel as IDisposable)
{
var test = new Action(channel.Test);
var ir = test.BeginInvoke(null, null); // ???? 为啥不起作用呢?
Console.WriteLine("Test {0}...", DateTime.Now);
test.EndInvoke(ir);
}
}
private static void Server()
{
AppDomain.CreateDomain("Server").DoCallBack(() =>
{
var host = new ServiceHost(typeof(MyService), new Uri("http://localhost:90"));
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");
host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
host.Open();
});
}
static void Main(string[] args)
{
Server();
Client();
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
Environment.Exit(0);
}
}
interface IMyService
{
[OperationContract]
void Test();
}
class MyService : IMyService
{
public void Test()
{
Console.WriteLine("Begin {0}...", DateTime.Now);
Thread.Sleep(3000);
Console.WriteLine("End {0}...", DateTime.Now);
}
}
class Program
{
private static void Client()
{
var binding = new BasicHttpBinding();
var address = new EndpointAddress("http://localhost:90");
var channel = ChannelFactory<IMyService>.CreateChannel(binding, address);
using (channel as IDisposable)
{
var test = new Action(channel.Test);
var ir = test.BeginInvoke(null, null); // ???? 为啥不起作用呢?
Console.WriteLine("Test {0}...", DateTime.Now);
test.EndInvoke(ir);
}
}
private static void Server()
{
AppDomain.CreateDomain("Server").DoCallBack(() =>
{
var host = new ServiceHost(typeof(MyService), new Uri("http://localhost:90"));
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");
host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
host.Open();
});
}
static void Main(string[] args)
{
Server();
Client();
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
Environment.Exit(0);
}
}
输出:
Begin 2008-6-2 16:20:32...
End 2008-6-2 16:20:35...
Test 2008-6-2 16:20:35...
从输出结果来看,很显然异步没 "异" 成。想了 N 久,也用独立线程尝试,很显然不是代码有问题。一番痛苦找寻后看到 MSDN 有这么一句话:
The event-driven asynchronous calling model is not supported when using a ChannelFactory.
火大!!!!!MSDN 给出了答案,就是要生成 "异步版本" 的代理契约。用 svcutil.exe 或者 VS 的导入工具,老老实实生成代理代码后,再来测试一下。
private static void Client()
{
var binding = new BasicHttpBinding();
var address = new EndpointAddress("http://localhost:90");
var channel = ChannelFactory<global::Learn.CUI.ServiceReference1.IMyService>.CreateChannel(binding, address);
using (channel as IDisposable)
{
var ir = channel.BeginTest(null, null); // 使用异步版本!
Console.WriteLine("Test {0}...", DateTime.Now);
channel.EndTest(ir);
}
}
{
var binding = new BasicHttpBinding();
var address = new EndpointAddress("http://localhost:90");
var channel = ChannelFactory<global::Learn.CUI.ServiceReference1.IMyService>.CreateChannel(binding, address);
using (channel as IDisposable)
{
var ir = channel.BeginTest(null, null); // 使用异步版本!
Console.WriteLine("Test {0}...", DateTime.Now);
channel.EndTest(ir);
}
}
输出:
Test 2008-6-2 16:26:52...
Begin 2008-6-2 16:26:52...
End 2008-6-2 16:26:55...
Begin 2008-6-2 16:26:52...
End 2008-6-2 16:26:55...