2017-08-31 66 views
0

下面是一个微小的WPF测试应用程序来演示该问题。通过设计,它是一个便携式应用程序,通过局域网与其他实例进行通信。如果我编译并在远程机器上运行,然后在本地主机上运行另一个实例,输入远程PC的名称,然后单击“测试连接”它检测到TCP上的远程WCF服务就好了。但是,如果我输入一些垃圾名称,UI会冻结几秒钟,然后抛出“没有DNS主机存在的主机blabla”。尽管这个调用被认为是异步的。当然,如果我在不同的线程上拨打电话,那就很顺利。WCF:DNS查找冻结了UI,尽管调用是异步的

await Task.Run(async() => await channel.TestConnection()); 

有没有办法避免Task.Run()?这关乎可扩展性。如果我需要一次测试数百或数千台电脑的在线状态,我想避免在调用者应用程序中产生新线程。

XAML:

<Window x:Class="Wcf_Test_Connection.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:Wcf_Test_Connection" 
     mc:Ignorable="d" 
     Title="MainWindow" SizeToContent="WidthAndHeight"> 
    <Grid> 
     <StackPanel Margin="20" Width="150"> 
      <TextBlock Text="Computer name:"/> 
      <TextBox x:Name="ComputerNameBox" Margin="0,10"/> 
      <Button x:Name="TestConnectionButton" Content="Test Connection" Click="TestConnectionButton_Click" /> 
     </StackPanel> 
    </Grid> 
</Window> 

WCF服务(通道工厂为基础):

[ServiceContract] 
    public interface IAccessPoint 
    { 
     [OperationContract] 
     Task<bool> TestConnection(); 
    } 

    public class AccessPoint : IAccessPoint 
    { 
     public static int Port = 4848; 
     public static string ServiceAddress = "/AccessPoint"; 

     public static void Configure(ServiceConfiguration config) 
     { 
      ContractDescription contract = ContractDescription.GetContract(typeof(IAccessPoint)); 

      ServiceEndpoint basicEndpoint = new ServiceEndpoint(contract, 
       new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:" + Port.ToString() + ServiceAddress)); 
      config.AddServiceEndpoint(basicEndpoint); 
     } 

     public static IAccessPoint NewChannel(string address) 
     { 
      NetTcpBinding binding = new NetTcpBinding(); 
      EndpointAddress endpoint = new EndpointAddress(address); 
      ChannelFactory<IAccessPoint> channelFactory = new ChannelFactory<IAccessPoint>(binding, endpoint); 
      IAccessPoint channel = channelFactory.CreateChannel(); 
      return channel; 
     } 

     public Task<bool> TestConnection() 
     { 
      return Task.FromResult(true); 
     } 

代码隐藏:

public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 

      var serviceHost = new ServiceHost(typeof(AccessPoint)); 
      serviceHost.Open(); 
     } 

     private async void TestConnectionButton_Click(object sender, RoutedEventArgs e) 
     { 
      this.Background = Brushes.Salmon; 

      var channel = AccessPoint.NewChannel("net.tcp://" + ComputerNameBox.Text + ":" + AccessPoint.Port + AccessPoint.ServiceAddress); 
      try 
      { 
       bool result = await channel.TestConnection(); 
       MessageBox.Show("Connection good"); 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message, "Error"); 
      } 
      finally 
      { 
       var client = (IClientChannel)channel; 
       if (client.State != CommunicationState.Closed && client.State != CommunicationState.Faulted) 
        client.Close(); 
       else client.Abort(); 
      } 

      this.Background = Brushes.White; 
     } 
    } 

回答

1

如果我需要测试几百在线状态或数千台电脑,我想避免产生新线程o来电者应用程序

任务池为您动态调整并发度。这就是为什么你应该创建任务而不是线程。

有没有办法避免Task.Run()

显然你需要调用后台线程的操作,以便不阻塞UI线程。请记住,async方法与其他任何方法一样同步运行,直至遇到await。因此,根据实际实施方法的不同,它可能仍会阻塞。显然它在这种情况下是这样的,所以你最好的拍摄可能在这里使用Task.Run。它是这个或使用另一个API。