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

2023-12-07

我有这个返回的方法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;

}

问题是在这个方法中我使用了两行await:

string fileforupload = await WatchDirectory();
await WaitForUnlockedFile(fileforupload);

并在这两行上出现错误。这两个错误是相同的:

错误“await”运算符只能在异步方法中使用。 考虑使用“async”修饰符标记此方法并更改 它的返回类型为'Task<string>'.

问题是否有可能使SendResponse()方法返回字符串,因为我需要它并且还使用await?

这就是我需要使用的两种方法await in the SendResponse() method:

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);
    }
}

UPDATE:

我改变了方法SendResponse() to be async Task<string>但随后在WebServer类构造函数我有这个并在这一行出现错误:

WebServer ws = new WebServer(SendResponseAsync, "http://+:8098/");

(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();
        }
    }
}

UPDATE 2

我尝试了 Peter 解决方案,所以我将 WebServer 类代码更改为 Peter 在这个问题解决方案中显示的代码。

然后在 form1 构造函数中我做了:

var ws = new WebServer(
            () => Task.Run(request => SendResponseAsync(request)),
            "http://+:8098/");
            ws.Run();

然后是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;

        }

手表目录:

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;
            }
        }

最后是 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);
            }
    }

但线上出现错误:

任务.运行 严重性代码 说明 项目文件行错误 无法将 lambda 表达式转换为类型“string[]”,因为它不是委托类型 Automatic_Record

并且线上也出现错误“http://+:8098/” 严重性代码说明项目文件行错误参数 2:无法从“string”转换为“System.Func>”


问题是否可以使 SendResponse 返回 字符串,因为我需要它并且还使用等待?

异步是“一路”。这意味着一旦您开始使用await在您的代码中,您的方法签名向上传播,遍历整个调用堆栈。 这意味着任何async代码中的方法必须返回Task or a Task<T>并拥有async添加修饰符,以便编译器检测到这是一个异步方法并且需要转换为状态机。

这意味着这个同步签名:

public string SendResponse(HttpListenerRequest request)

需要转成异步签名:

public async Task<string> SendResponseAync(HttpListenerRequest request)

There is使用同步阻塞代码的选项Task.Result。我不会推荐它,因为你不应该阻止异步代码。这只会带来麻烦(通常是死锁)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 async Task 方法并返回字符串,然后如何将该方法的委托传递给构造函数并稍后使用它? 的相关文章

随机推荐