2017-08-31 67 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。