簡體   English   中英

WCF:即使呼叫是異步的,DNS查找也會凍結UI

[英]WCF: DNS lookup freezes UI despite the call is async

下面是一個微型WPF測試應用程序,用於演示該問題。 通過設計,它是一種便攜式應用程序,可通過LAN與其他實例進行通信。 如果我編譯它並在遠程計算機上運行,​​然后在localhost上運行另一個實例,輸入遠程PC的名稱,然后單擊“測試連接”,它將檢測到TCP上的遠程WCF服務。 但是,如果我輸入一些垃圾名稱,則UI會凍結幾秒鍾,然后拋出“主機blabla不存在DNS條目”。 而且盡管該調用據說是異步的。 當然,如果我在其他線程上進行調用,一切都會很順利。

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服務(基於Channel Factory):

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

如果我需要一次測試數百台或數千台計算機的聯機狀態,我希望避免在調用者應用程序中產生新線程。

任務池可為您動態擴展並發程度。 這就是為什么您應該創建任務而不是線程。

有辦法避免Task.Run()嗎?

顯然,您需要在后台線程上調用該操作,以免阻塞UI線程。 請記住, async方法像其他任何方法一樣同步運行,直到達到await狀態為止。 因此,根據async方法的實際實現方式,它可能仍然會阻塞。 顯然,在這種情況下確實如此,因此最好的選擇可能是使用Task.RunTask.Run在這里運行。 要么是這個,要么是使用另一個API。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM