C# 如何在WCF中异步回调递归函数?
简介:我有一个服务器[WCF服务库]和客户机[Winform],客户机使用netTcpBinding连接到服务器 服务器的任务是使用文件管理器功能{新建文件夹、移动、复制、删除、属性、属性和搜索}将计算机文件共享给客户端 问题: 搜索函数是一个递归函数,当它找到包含搜索键的(文件夹/文件)名称时,它会立即(使用客户端回调)将项添加到客户端ListView中。C# 如何在WCF中异步回调递归函数?,c#,wcf,recursion,asynccallback,wcf-callbacks,C#,Wcf,Recursion,Asynccallback,Wcf Callbacks,简介:我有一个服务器[WCF服务库]和客户机[Winform],客户机使用netTcpBinding连接到服务器 服务器的任务是使用文件管理器功能{新建文件夹、移动、复制、删除、属性、属性和搜索}将计算机文件共享给客户端 问题: 搜索函数是一个递归函数,当它找到包含搜索键的(文件夹/文件)名称时,它会立即(使用客户端回调)将项添加到客户端ListView中。 因此,它工作得非常完美,直到我添加了一个停止搜索按钮,该按钮允许用户停止递归函数\u search(),当我尝试停止搜索时,会发生的情况
因此,它工作得非常完美,直到我添加了一个停止搜索按钮,该按钮允许用户停止递归函数\u search(),当我尝试停止搜索时,会发生的情况是冻结GUI,在我“停止调试”之前,永远不会从冻结模式中恢复过来。
事实上,当我在调试模式下设置点以查看搜索功能的错误时,它会工作,搜索也会停止。
这是我用于搜索的代码:
WCF lib侧:
[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);
}
}
}
客户端:
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转换我的搜索函数和异步回调?我想我知道这里发生了什么,但这只是一个有根据的猜测。由于您的WCF代码被设置为每个会话一个实例,并且您处于同一会话中,因此您正在创建一个循环锁。基本上,您正处于这样一个点上:
callback.File(item)
在调用客户机代码的同时调用您的客户机代码StopSearch
。因此,客户端代码在从StopSearch
回音之前不会响应,服务器在从客户端回音之前不会到达if(StopSearch)
/StopSearch=true
(该客户端正忙着等待WCF,该服务器正忙着等待客户端,这就是……抓住要点)。尝试将StopSearch
标记为OneWay
,这样(我相信,我的WCF不是太强)客户端中的呼叫将立即返回(而不是等待WCF),从而解锁客户端
或者,您可以使WCF代码更具多线程性,但这样可能会遇到更多问题
更新
根据您的回答,似乎确实需要使您的或使客户端代码更异步(使用或或只是一个新线程)我找到了一个解决方案,可能不是完美的,但我必须使用线程。中止以停止它
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);
}
}
您是否尝试将停止搜索设置为静态?另外,如果您在调试模式下运行,只需等待UI冻结,然后暂停执行以查看是否在某个位置锁定?@JustinPihony我将stopSearch设置为静态,它仍然冻结,然后我暂停执行,它指向这一行
client.stopSearch()
位于private void btnSearch\u单击@JustinPihony它正在等待WCF服务执行停止搜索功能客户端冻结时,我也暂停了WCF服务,它指向callback.File(项)代码>在\u Search()
中,静态的东西实际上只是一个偶然的机会。但是,您肯定锁定了回调。我很想知道你们是如何建立客户关系的。你能发布这些代码吗?正如我告诉你的,当我使用one-way
进行StopSearch时,它仍然是一样的,但是当调用client.StopSearch()
到一个单独的线程时,它就起作用了。那么,我们能从中得出什么结论呢?我能在不初始化新线程的情况下让它工作吗@MurHafSoz我已经更新了我的答案,但是看起来你需要使你的代码异步。现在它工作得很好,但是我不确定使用Thread.Abort是否是一个好主意,请检查我的答案。事实上,Thread.Abort不是一个好主意,并且非常不鼓励。
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);
}
}