如何异步回调WCF中的递归函数?

时间:2012-05-05 03:16:08

标签: c# wcf recursion asynccallback wcf-callbacks

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

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

enter image description here

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

这是我用于搜索的代码:

WCF lib Side

     [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?

2 个答案:

答案 0 :(得分:1)

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

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

<强>更新

根据您的回复,您似乎需要制作WCF service call truly async,或者让客户端代码更加异步(使用TPLbackgroundworkers或只是新的线程旋转)

答案 1 :(得分: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()

,则使用return
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);
        }
    }