Dan*_*olf 3 .net c# winforms async-await
我有这个方法返回string:
public string SendResponse(HttpListenerRequest request)
{
string result = "";
string key = request.QueryString.GetKey(0);
if (key == "cmd")
{
if (request.QueryString[0] == "uploadstatus")
{
switch (Youtube_Uploader.uploadstatus)
{
case "uploading file":
return "uploading " + Youtube_Uploader.fileuploadpercentages;
case "status":
return Youtube_Uploader.fileuploadpercentages.ToString();
case "file uploaded successfully":
Youtube_Uploader.uploadstatus = "";
return "upload completed," + Youtube_Uploader.fileuploadpercentages + ","
+ Youtube_Uploader.time;
default:
return "upload unknown state";
}
}
if (request.QueryString[0] == "nothing")
{
return "Connection Success";
}
if (request.QueryString[0] == "start")
{
StartRecrod();
result = "Recording started";
}
if (request.QueryString[0] == "stop")
{
dirchanged = false;
StartRecrod();
result = "Recording stopped and preparing the file to be shared on youtube";
string fileforupload = await WatchDirectory();
await WaitForUnlockedFile(fileforupload);
using (StreamWriter w = new StreamWriter(userVideosDirectory + "\\UploadedVideoFiles.txt", true))
{
w.WriteLine(fileforupload);
}
uploadedFilesList.Add(fileforupload);
Youtube_Uploader youtubeupload = new Youtube_Uploader(uploadedFilesList[0]);
}
}
else
{
result = "Nothing have been done";
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
问题是,在这个方法中,我使用两行await:
string fileforupload = await WatchDirectory();
await WaitForUnlockedFile(fileforupload);
Run Code Online (Sandbox Code Playgroud)
并在这两行上得到错误.两个错误都是一样的:
错误'await'运算符只能在异步方法中使用.考虑使用'async'修饰符标记此方法并将其返回类型更改为
'Task<string>'.
问题是,是否有可能使SendResponse()方法返回字符串,因为我需要它,并使用await?
这是我需要await在SendResponse()方法中使用的两种方法:
private async Task<string> WatchDirectory()
{
using (FileSystemWatcher watcher = new FileSystemWatcher())
{
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
watcher.Path = userVideosDirectory;
watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size;
watcher.Filter = "*.mp4";
watcher.Changed += (sender, e) => tcs.SetResult(e.FullPath);
watcher.EnableRaisingEvents = true;
return await tcs.Task;
}
}
// You can get rid of the OnChanged() method altogether
private async Task WaitForUnlockedFile(string fileName)
{
while (true)
{
try
{
using (IDisposable stream = File.Open(fileName, FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.None))
{ /* on success, immediately dispose object */ }
break;
}
catch (IOException)
{
// ignore exception
// NOTE: for best results, consider checking the hresult value of
// the exception, to ensure that you are only ignoring the access violation
// exception you're expecting, rather than other exceptions, like
// FileNotFoundException, etc. which could result in a hung process
}
// You might want to consider a longer delay...maybe on the order of
// a second or two at least.
await Task.Delay(100);
}
}
Run Code Online (Sandbox Code Playgroud)
更新:
我将方法SendResponse()更改为async Task<string>
但是然后在WebServer类构造函数中我有这个并且在这一行上得到错误:
WebServer ws = new WebServer(SendResponseAsync, "http://+:8098/");
Run Code Online (Sandbox Code Playgroud)
(SendResponseAsync是SendResponse更名)
错误是:
错误1'System.Threading.Tasks.Task Automatic_Record.Form1.SendResponseAync(System.Net.HttpListenerRequest)'具有错误的返回类型
WebServer类是:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Threading;
namespace Automatic_Record
{
class WebServer
{
private readonly HttpListener _listener = new HttpListener();
private readonly Func<HttpListenerRequest, string> _responderMethod;
public WebServer(string[] prefixes, Func<HttpListenerRequest, string> method)
{
if (!HttpListener.IsSupported)
throw new NotSupportedException(
"Needs Windows XP SP2, Server 2003 or later.");
// URI prefixes are required, for example
// "http://localhost:8080/index/".
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException("prefixes");
// A responder method is required
if (method == null)
throw new ArgumentException("method");
foreach (string s in prefixes)
_listener.Prefixes.Add(s);
_responderMethod = method;
_listener.Start();
}
public WebServer(Func<HttpListenerRequest, string> method, params string[] prefixes)
: this(prefixes, method) { }
public void Run()
{
ThreadPool.QueueUserWorkItem((o) =>
{
Console.WriteLine("Webserver running...");
try
{
while (_listener.IsListening)
{
ThreadPool.QueueUserWorkItem((c) =>
{
var ctx = c as HttpListenerContext;
try
{
string rstr = _responderMethod(ctx.Request);
System.Diagnostics.Trace.Write(ctx.Request.QueryString);
//ctx.Request.QueryString
byte[] buf = Encoding.UTF8.GetBytes(rstr);
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
System.Data.SqlClient.SqlConnectionStringBuilder builder = new System.Data.SqlClient.SqlConnectionStringBuilder();
}
catch { } // suppress any exceptions
finally
{
// always close the stream
ctx.Response.OutputStream.Close();
}
}, _listener.GetContext());
}
}
catch { } // suppress any exceptions
});
}
public void Stop()
{
_listener.Stop();
_listener.Close();
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新2
我尝试了peter解决方案,所以我将WebServer类代码更改为此问题解决方案中的Peter显示.
然后在form1构造函数中我做了:
var ws = new WebServer(
() => Task.Run(request => SendResponseAsync(request)),
"http://+:8098/");
ws.Run();
Run Code Online (Sandbox Code Playgroud)
然后方法SendResponseAsync:
public async Task<string> SendResponseAsync(HttpListenerRequest request)
{
string result = "";
string key = request.QueryString.GetKey(0);
if (key == "cmd")
{
if (request.QueryString[0] == "uploadstatus")
{
switch (Youtube_Uploader.uploadstatus)
{
case "uploading file":
return "uploading " + Youtube_Uploader.fileuploadpercentages;
case "status":
return Youtube_Uploader.fileuploadpercentages.ToString();
case "file uploaded successfully":
Youtube_Uploader.uploadstatus = "";
return "upload completed," + Youtube_Uploader.fileuploadpercentages + ","
+ Youtube_Uploader.time;
default:
return "upload unknown state";
}
}
if (request.QueryString[0] == "nothing")
{
return "Connection Success";
}
if (request.QueryString[0] == "start")
{
StartRecrod();
result = "Recording started";
}
if (request.QueryString[0] == "stop")
{
dirchanged = false;
StartRecrod();
result = "Recording stopped and preparing the file to be shared on youtube";
string fileforupload = await WatchDirectory();
await WaitForUnlockedFile(fileforupload);
using (StreamWriter w = new StreamWriter(userVideosDirectory + "\\UploadedVideoFiles.txt", true))
{
w.WriteLine(fileforupload);
}
uploadedFilesList.Add(fileforupload);
Youtube_Uploader youtubeupload = new Youtube_Uploader(uploadedFilesList[0]);
}
}
else
{
result = "Nothing have been done";
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
WatchDirectory:
private async Task<string> WatchDirectory()
{
using (FileSystemWatcher watcher = new FileSystemWatcher())
{
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
watcher.Path = userVideosDirectory;
watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size;
watcher.Filter = "*.mp4";
watcher.Changed += (sender, e) => tcs.SetResult(e.FullPath);
watcher.EnableRaisingEvents = true;
return await tcs.Task;
}
}
Run Code Online (Sandbox Code Playgroud)
并持续WaitForUnlockedFile
private async Task WaitForUnlockedFile(string fileName)
{
while (true)
{
try
{
using (IDisposable stream = File.Open(fileName, FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.None))
{ /* on success, immediately dispose object */ }
break;
}
catch (IOException)
{
// ignore exception
// NOTE: for best results, consider checking the hresult value of
// the exception, to ensure that you are only ignoring the access violation
// exception you're expecting, rather than other exceptions, like
// FileNotFoundException, etc. which could result in a hung process
}
// You might want to consider a longer delay...maybe on the order of
// a second or two at least.
await Task.Delay(100);
}
}
Run Code Online (Sandbox Code Playgroud)
但是在线上得到错误:
Task.Run严重级代码说明项目文件行错误无法将lambda表达式转换为类型'string []',因为它不是委托类型Automatic_Record
并且行上的错误" http:// +:8098 / "严重性代码描述项目文件行错误参数2:无法从'string'转换为'System.Func>
问题是,是否有可能使SendResponse返回字符串,因为我需要它并使用await?
异步是"一直".这意味着一旦开始使用await代码,您的方法签名就会向上传播,遍历整个调用堆栈.这意味着async代码中的任何方法都必须返回a Task或a Task<T>并async添加修饰符,以便编译器检测到这是异步方法并需要转换为状态机.
这意味着这个同步签名:
public string SendResponse(HttpListenerRequest request)
Run Code Online (Sandbox Code Playgroud)
需要变成异步签名:
public async Task<string> SendResponseAync(HttpListenerRequest request)
Run Code Online (Sandbox Code Playgroud)
还有就是使用您的代码同步封锁的选项Task.Result.我不推荐它,因为你不应该阻止异步代码.这只会带来麻烦(通常是死锁).