我如何使用方法async Task <string>并返回字符串,然后如何将该方法的委托传递给构造函数并在以后使用它?

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

这是我需要awaitSendResponse()方法中使用的两种方法:

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>

Yuv*_*kov 5

问题是,是否有可能使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.我不推荐它,因为你不应该阻止异步代码.这只会带来麻烦(通常是死锁).