简介:我有一个服务器[ WCF服务库]和客户端[ Winform ],客户端使用netTcpBinding连接到服务器。
服务器作业是使用文件管理器功能{新建文件夹,移动,复制,删除,属性,属性和搜索}将计算机文件共享到客户端。
问题:
搜索功能是一个递归函数,当它找到包含搜索关键字的(文件夹/文件)名称时,它会立即将项目添加到客户端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?
答案 0 :(得分:1)
我想我知道这里发生了什么,但这只是一个有根据的猜测。由于您的WCF代码设置为每个会话一个实例,并且您在同一个会话中,因此您正在创建一个循环锁。基本上,在客户端代码调用callback.File(item)
的同时,StopSearch
正在回调客户端代码。因此,客户端代码在从StopSearch
回来之前不会响应,服务器将无法访问if(stopSearch)
/ stopSearch = true
,直到它从客户端(正忙于等待)回来WCF,正在忙着等待客户端,这是......得到了点)。尝试将StopSearch
标记为OneWay
,以便(我相信,我的WCF不会太强)客户端中的调用将立即返回(而不是等待WCF),从而解锁客户端。
或者,您可以使您的WCF代码更多多线程,但是您可能会遇到更多问题。
<强>更新强>
根据您的回复,您似乎需要制作WCF service call truly async,或者让客户端代码更加异步(使用TPL或backgroundworkers或只是新的线程旋转)
答案 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);
}
}