WCF:DNS查找冻结了UI,尽管调用是异步的
问题描述:
下面是一个微小的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;
}
}
答
如果我需要测试几百在线状态或数千台电脑,我想避免产生新线程o来电者应用程序
任务池为您动态调整并发度。这就是为什么你应该创建任务而不是线程。
有没有办法避免
Task.Run()
?
显然你需要调用后台线程的操作,以便不阻塞UI线程。请记住,async
方法与其他任何方法一样同步运行,直至遇到await
。因此,根据实际实施方法的不同,它可能仍会阻塞。显然它在这种情况下是这样的,所以你最好的拍摄可能在这里使用Task.Run
。它是这个或使用另一个API。