下面是一個微小的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;
}
}