0

简介:我有一个服务器 [ WCF 服务库] 和客户端 [ Winform ],客户端使用 netTcpBinding 连接到服务器。

服务器的工作是使用文件管理器功能 { 新建文件夹、移动、复制、删除、属性、属性和搜索}将计算机文件共享给客户端。

在此处输入图像描述

问题: 搜索函数是一个递归函数,当它找到包含搜索键的(文件夹/文件)名称时,它会立即将项目添加到客户端 ListView(使用客户端 CALLBACK )。
所以一切都很完美,直到我添加了一个停止搜索按钮,它假设允许用户停止递归函数_Search(),当我尝试停止搜索时会发生什么情况是冻结 GUI 并且永远不会从冻结模式恢复,直到我“停止调试”。
事实上,当我在调试模式下设置点以查看搜索功能有什么问题时,它可以工作并且搜索停止。

这是我用于搜索的代码:

WCF 库端

     [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerSession)]
  public class MainService : IFileManager,ITaskManager
  {

    IFileManagerCallback callback = OperationContext.Current.GetCallbackChannel<IFileManagerCallback>();

 bool stopSearch = false;

    public void StopSearch()    //client call this function to stop SEARCHING.
    {
        stopSearch = true;
    }

    public void Search(string path, string name)     //client call this function to start searching
    {
        _Search(path, name);
        callback.SearchEnd();
        if (stopSearch)
        {
            callback.InfoLabel("Search Cancelled", InfoState.Info);
            stopSearch = false;
            return;
        }
        callback.InfoLabel("Search Done.", InfoState.Done);
    }

    private void _Search(string path, string name)    //the evil recursive function
    {
        if (stopSearch) return;
        DirectoryInfo Roots = new DirectoryInfo(path);

        foreach (FileInfo file in Roots.GetFiles())
        {
            if (stopSearch) return;
            if (file.Name.IndexOf(name, StringComparison.InvariantCultureIgnoreCase) > -1)
            {
                _File item = new _File();
                item.Name = file.Name;
                item.Size = file.Length;
                item.Path = file.FullName;
                callback.File(item);
            }
        }
        foreach (DirectoryInfo folder in Roots.GetDirectories())
        {
            if (stopSearch) return;
            if (folder.Name.IndexOf(name, StringComparison.InvariantCultureIgnoreCase) > -1)
            {
                _Folder item = new _Folder();
                item.Name = folder.Name;
                item.Path = folder.FullName;
                callback.Folder(item);
            }
            _Search(folder.FullName, name);
        }
    } 
 }

WCF接口:

  [ServiceContract(CallbackContract = typeof(IFileManagerCallback))]
public interface IFileManager
{
    [OperationContract]
    void StopSearch();
     [OperationContract(IsOneWay = true)]
    void Search(string path, string name);
}

     public interface IFileManagerCallback
{
    [OperationContract]
    void File(_File file);

    [OperationContract]
    void Folder(_Folder folder);

    [OperationContract]
    void InfoLabel(string value, InfoState state);

    [OperationContract]
    void SearchEnd();

}

客户端 :

 class Callback : IFileManagerCallback
{
    public delegate void OnFileReceived(object sender, _File item);
    private OnFileReceived _fileReceivedHandler = null;
    public event OnFileReceived OnFileReceivedEvent
    {
        add { _fileReceivedHandler += value; }
        remove { _fileReceivedHandler -= value; }
    }
    private void RaiseFileEvents(_File file)
    {
        if (_fileReceivedHandler != null)
        {
            _fileReceivedHandler(this, file);
        }
    }
    public void File(_File file)
    {
        RaiseFileEvents(file);
    }
    // **I WILL AVOID POSTING Folder event and handler it's the same of the file.**
    public void Folder(_Folder folder)
    {
        RaiseFolderEvents(folder);
    }

客户端 Form1.cs :

  public partial class Form1 : Form
{

       private void callback_FileReceivedEvent(object sender, _File file)
    {
        ListViewItem item = new ListViewItem();
        item.Text = file.Name;
        item.ToolTipText = file.Path;
        item.Tag = item.ImageIndex;
        item.Name = item.Text;
        item.SubItems.Add(CnvrtUnit(file.Size));
        item.Group = listView1.Groups[0];
        item.ImageIndex = _iconListManager.AddFileIcon(file.Path);
        listView1.Items.Add(item);
    }
    bool IsSearch = false;
    private void btnSearch_Click(object sender, EventArgs e)
    {
        if (!IsSearch)
        {
           IsSearch = true;
           listView1.Items.Clear();
           client.Search(currAddress, txtAddress.Text);
           return;
        }
        client.StopSearch();
    }
    public void StopSearching()
    {
        UpdateLabel();    //updating GUI label "Selected 0:,Items: 0"
        IsSearch = false;
    }
}

我对修复它真的很困惑,我不确定我是否为我的问题选择了正确的标题,所以如果发生这种情况是因为我需要异步回调,我将如何使用 WCF 转换我的搜索函数和异步回调?

4

2 回答 2

1

我想我知道这里发生了什么,但这只是一个有根据的猜测。由于您的 WCF 代码设置为每个会话一个实例,并且您处于同一会话中,因此您正在创建一个循环锁。基本上,您正在达到一个点,callback.File(item)即在您的客户端代码调用StopSearch. 因此,客户端代码在收到回复之前不会响应,StopSearch并且服务器在收到客户端回复之前不会到达if(stopSearch)/ stopSearch = true(忙于等待 WCF,忙于等待客户端,即.. ..明白这点)。尝试将其标记StopSearchOneWay(我相信,我的 WCF 不是太强)客户端中的调用将立即返回(而不是等待 WCF),从而解锁客户端。

或者,您可以使您的 WCF 代码更加多线程,但是您可能会遇到更多问题。

更新

根据您的回复,您似乎需要使您的WCF 服务调用真正 async,或者使客户端代码更加异步(使用TPLbackgroundworkers或只是启动一个新线程)

于 2012-05-05T04:30:19.310 回答
0

我找到了一个解决方案,也许不是完美的,但我不得不使用 Thread.Abort 来阻止它。

    public void Search(string path, string name)
    {
        Thread th = new Thread(s => SearchThread(path, name));
        th.Start();
    }

    private void SearchThread(string path, string name)
    {
        try
        {
            _Search(path, name);
        }
        finally
        {
            callback.SearchEnd();
            if (stopSearch)
            {
                callback.InfoLabel("Search Cancelled", InfoState.Info);
                stopSearch = false;
            }
            else
                callback.InfoLabel("Search Done.", InfoState.Done);
        }
    }

Thread.Abort()改用 ifreturn

private void _Search(string path, string name)
    {
        if (stopSearch) Thread.CurrentThread.Abort();
        DirectoryInfo Roots = new DirectoryInfo(path);

        foreach (FileInfo file in Roots.GetFiles())
        {
            if (stopSearch) Thread.CurrentThread.Abort(); 
            if (file.Name.IndexOf(name, StringComparison.InvariantCultureIgnoreCase) > -1)
            {
                _File item = new _File();
                item.Name = file.Name;
                item.Size = file.Length;
                item.Path = file.FullName;
                callback.File(item);
            }
        }
        foreach (DirectoryInfo folder in Roots.GetDirectories())
        {
            if (stopSearch) Thread.CurrentThread.Abort();
            if (folder.Name.IndexOf(name, StringComparison.InvariantCultureIgnoreCase) > -1)
            {
                _Folder item = new _Folder();
                item.Name = folder.Name;
                item.Path = folder.FullName;
                callback.Folder(item);
            }
            _Search(folder.FullName, name);
        }
    }
于 2012-05-06T06:41:33.237 回答