【问题标题】:Method is not executed from running Task方法未从运行任务中执行
【发布时间】:2017-12-15 08:45:52
【问题描述】:

我正在开发 ASP.NET MVC 项目。
我需要一些时间来解释我的疯狂情况。
我正在尝试从 MVC 项目向 Android 和 Apple 设备发送推送通知。
两者的发送逻辑都是正确的,请不要浪费时间考虑这个

我面临的灾难是:静态类中负责发送通知的静态方法没有被调用(我不是新手,我有5年多的C#编程经验)但是我不能调用方法。

为了让您了解问题的上下文,当我在本地机器(开发机器)上执行代码时,调用并执行此方法并将通知到达设备。
当我发布 MVC 项目并将其部署到我们的服务器时,不会调用静态方法。

我怎么知道该方法没有被调用?
因为我正在记录到一个文本文件,并且我在第一行放了一条日志语句 方法和调用方法之前的日志语句。
调用方法之前的日志会被执行并充实到文本文件中,而静态方法开始的日志不会被执行!!!!!!。

这是一些代码,然后我会告诉你我试图解决这个问题的方法。

public interface IHandler<T> where T : IMessage
{
    Task Handle(T args);
}

public class RequestAddedAppMonitorHandler : IHandler<RequestAdded>
{
    public Task Handle(RequestAdded args)
    {
        return Task.Factory.StartNew(() =>
        {
            try
            {
                GoogleNotification notification = CreateAndroidPartnerAppNotification(deviceId);

                // this statment is executed, and the text log file will contains this line
                TracingSystem.TraceInformation("Before Send Google Notification");  

                SendersFacade.PartnerSender.Send(notification).Wait();
            }
            catch (Exception ex)
            {
                TracingSystem.TraceException(ex);
            }
        });
    }

    private GoogleNotification CreateAndroidPartnerAppNotification(string to)
    {
        return new GoogleNotification();    // some initialization and creating for the notification object.
    }
}

门面类

public static class SendersFacade
{
    public static GoogleNotificationSender ClientSender { get; private set; }
    public static GoogleNotificationSender PartnerSender { get; private set; }
    //public static AppleNotificationSender AppleSender { get; private set; }

    static SendersFacade()
    {
        ClientSender = new GoogleNotificationSender("correct api key");
        PartnerSender = new GoogleNotificationSender("correct api key");
        //AppleSender = some intialization.
    }
}

Google 通知发送逻辑

public class GoogleNotificationSender
{
    private string _authorizationToken;
    private string AuthorizationToken
    {
        get { return _authorizationToken; }
        set
        {
            if (string.IsNullOrEmpty(value))
                throw new InvalidOperationException("authorizationToken must not be null");
            _authorizationToken = value;
        }
    }

    public GoogleNotificationSender(string authorizationToken)
    {
        this.AuthorizationToken = authorizationToken;
    }

    public async Task Send(GoogleNotification notification)
    {
        // ATTENTION PLEASE
        // This method is not called, and the following line is not fleshed to the log file
        TracingSystem.TraceInformation("Inside Send Google notification");

        using (HttpClient client = new HttpClient())
        {
            client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + AuthorizationToken);

            string json = notification.GetJson();
            StringContent content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

            using (HttpResponseMessage message = await client.PostAsync("https://fcm.googleapis.com/fcm/send", content))
            {
                message.EnsureSuccessStatusCode();

                string resultAsString = await message.Content.ReadAsStringAsync();
                GoogleNotificationResult result = JsonConvert.DeserializeObject<GoogleNotificationResult>(resultAsString);

                if (result.Failure > 0)
                    throw new Exception($"Sending Failed : {result.Results.FirstOrDefault().Error}");
            }
        }
    }
}

Google 通知类

public class GoogleNotification
{
    [JsonProperty("to")]
    public string To { get; set; }

    [JsonProperty("data")]
    public JObject Data { get; set; }

    [JsonProperty("notification")]
    public JObject Notification { get; set; }

    // some other property which is not used at all

    internal string GetJson()
    {
        return JsonConvert.SerializeObject(this,
            new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
    }
}

前三天我尝试了什么?

1-将用于调试的DLL(不是已发布的DLL,使用Release模式)部署到服务器,这并没有解决问题。

2- 将SendersFacade 设为非静态类,并在其上应用单调设计模式,也不起作用。

public class SendersFacade
{
    public static SendersFacade Instance { get; private set; }

    public GoogleNotificationSender ClientSender { get; private set; }
    public GoogleNotificationSender PartnerSender { get; private set; }
    //public static AppleNotificationSender AppleSender { get; private set; }

    static SendersFacade()
    {
        if (Instance != null)
            Instance = new SendersFacade();
    }
    public SendersFacade()
    {
        ClientSender = new GoogleNotificationSender("correct api key");
        PartnerSender = new GoogleNotificationSender("correct api key");
        //AppleSender = some intialization.
    }
}

3- 尝试将发送的逻辑放在它自己的 Handler 类中,这很有效,我能够从服务器发送通知,但是为什么,在地狱,下面的代码工作正常,但以前的代码不工作??????????

public interface IHandler<T> where T : IMessage
{
    Task Handle(T args);
}

public class RequestAddedAppMonitorHandler : IHandler<RequestAdded>
{
    public Task Handle(RequestAdded args)
    {
        return Task.Factory.StartNew(() =>
        {
            try
            {
                GoogleNotification notification = CreateAndroidPartnerAppNotification(deviceId);

                // this statment is executed, and the text log file will contains this line
                TracingSystem.TraceInformation("Before Send Google Notification");  

                SendersFacade.PartnerSender.Send(notification).Wait();
            }
            catch (Exception ex)
            {
                TracingSystem.TraceException(ex);
            }
        });
    }

    private GoogleNotification CreateAndroidPartnerAppNotification(string to)
    {
        return new GoogleNotification();    // some initialization and creating for the notification object.
    }

    private void Send(GoogleNotification notification, string authorizationToken)
    {
        TracingSystem.TraceInformation("Inside Send Google notification");

        using (HttpClient client = new HttpClient())
        {
            client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + authorizationToken);

            string json = notification.GetJson();
            StringContent content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

            using (HttpResponseMessage message = client.PostAsync("https://fcm.googleapis.com/fcm/send", content).Result)
            {
                message.EnsureSuccessStatusCode();

                string resultAsString = message.Content.ReadAsStringAsync().Result;
                GoogleNotificationResult result = JsonConvert.DeserializeObject<GoogleNotificationResult>(resultAsString);

                if (result.Failure > 0)
                    throw new Exception($"Sending Failed : {result.Results.FirstOrDefault().Error}");
            }
        }
    }
}

只需将 send 方法的逻辑添加到 RequestAddedAppMonitorHandler 类即可解决问题,但我不想这样做,为什么会发生这种情况? 只是调用一个方法

3-尝试使发送方法串行方法(不使用async),它也没有工作

public void Send(GoogleNotification notification)
{
    TracingSystem.TraceInformation("Inside Send Google notification");

    using (HttpClient client = new HttpClient())
    {
        client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + AuthorizationToken);

        string json = notification.GetJson();
        StringContent content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

        using (HttpResponseMessage message = client.PostAsync(BASE_URL, content).Result)
        {
            message.EnsureSuccessStatusCode();

            string resultAsString = message.Content.ReadAsStringAsync().Result;
            GoogleNotificationResult result = JsonConvert.DeserializeObject<GoogleNotificationResult>(resultAsString);

            if (result.Failure > 0)
                throw new Exception($"Sending Failed : {result.Results.FirstOrDefault().Error}");
        }
    }
}

注意1: 我注意到我在服务器上遇到问题(在我的本地机器上根本没有出现),这是该网站特定的应用程序池经常停止,这导致请求网站时 503 服务不可用。

注意 2: 我怀疑问题的最可能原因是线程。 但我无法得出明确的解决方案

注意 3:请不要认为这个问题有答案,它对我一点帮助都没有。

我从三天开始就在做这个,我真的很绝望,任何想法谢谢。


更新 @Nkosi 的回答真的很有帮助,至少我现在知道出了什么问题,我决定一路同步。并避免将async/await 与阻塞调用混合。

所以这是我达到的结果

public class RequestAddedAppMonitorHandler : IHandler<RequestAdded>
{
    public Task Handle(RequestAdded args)
    {
        return Task.Factory.StartNew(() =>
        {
            try
            {
                if (deviceOS.Value == DeviceOSEnum.Android.ToString())
                {
                   GoogleNotification notification = CreateAndroidUpdateRequestMessage(args.CustomerRequest, deviceId.Value, notificationString.Title_RequestStared, message);
                   SendGoogleNotification(notification, "some id");
                }
                else if (deviceOS.Value == DeviceOSEnum.IOS.ToString())
                {
                   AppleNotification notification = CreateAppleNotification(deviceId.Value, notificationString.Title_RequestStared, message);
                   AppleNotificationSender sender = new AppleNotificationSender();
                   sender.SendAppleNotification(notification);
                }
            }
            catch (Exception ex)
            {
                TracingSystem.TraceException(ex);
            }
        });
    }

AppleNotificationSender

public class AppleNotificationSender
{
    private TcpClient client;
    private string host = "gateway.push.apple.com";
    private int port = 2195;
    private X509Certificate2 certificate;

    public AppleNotificationSender()
    {
        string path = HostingEnvironment.MapPath("~/Certificates.p12");
        certificate = new X509Certificate2(path, "some correct password");
    }

    private void SetSocketKeepAliveValues(Socket socket, int KeepAliveTime, int KeepAliveInterval)
    {
        //KeepAliveTime: default value is 2hr
        //KeepAliveInterval: default value is 1s and Detect 5 times

        uint dummy = 0; //lenth = 4
        byte[] inOptionValues = new byte[System.Runtime.InteropServices.Marshal.SizeOf(dummy) * 3]; //size = lenth * 3 = 12

        BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0);
        BitConverter.GetBytes((uint)KeepAliveTime).CopyTo(inOptionValues, System.Runtime.InteropServices.Marshal.SizeOf(dummy));
        BitConverter.GetBytes((uint)KeepAliveInterval).CopyTo(inOptionValues, System.Runtime.InteropServices.Marshal.SizeOf(dummy) * 2);
        // of course there are other ways to marshal up this byte array, this is just one way
        // call WSAIoctl via IOControl

        // .net 3.5 type
        socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
    }

    private bool SocketCanWrite(SslStream stream)
    {
        if (client == null)
            return false;

        if (stream == null || !stream.CanWrite)
            return false;

        if (!client.Client.Connected)
            return false;

        return client.Client.Poll(1000, SelectMode.SelectWrite);
    }

    private void Connect()
    {
        try
        {
            if (client == null)
                client = new TcpClient();

            client.Connect(host, port);

            //Set keep alive on the socket may help maintain our APNS connection
            try { client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); }
            catch { }

            // Really not sure if this will work on MONO....
            // This may help windows azure users
            try
            {
                SetSocketKeepAliveValues(client.Client, (int)TimeSpan.FromMinutes(20).TotalMilliseconds, (int)TimeSpan.FromSeconds(30).TotalMilliseconds);
            }
            catch { }
        }
        catch (Exception ex)
        {
            throw new Exception("Failed to Connect, check your firewall settings!", ex);
        }
    }

    public void SendAppleNotification(AppleNotification notification)
    {
        SslStream stream = null;
        try
        {
            Connect();

            stream = new SslStream(client.GetStream(),
                false,
                (sender, cert, chain, policyErrors) => true,
                (sender, targetHost, localCerts, remoteCert, acceptableIssuers) => certificate);

            try
            {
                X509CertificateCollection collection = new X509CertificateCollection();
                collection.Add(certificate);
                stream.AuthenticateAsClient(host, collection, System.Security.Authentication.SslProtocols.Tls, false);
            }
            catch (System.Security.Authentication.AuthenticationException ex)
            {
                throw new Exception("SSL Stream Failed to Authenticate as Client", ex);
            }

            if (!stream.IsMutuallyAuthenticated)
                throw new Exception("SSL Stream Failed to Authenticate", null);

            if (!stream.CanWrite)
                throw new Exception("SSL Stream is not Writable", null);

            if (!SocketCanWrite(stream))
                Connect();

            byte[] data = notification.ToBytes();
            stream.Write(data, 0, data.Length);
            //TracingSystem.TraceInformation("Write to stream ended.");
        }
        catch (Exception)
        {
            TracingSystem.TraceError("Error in sending Apple notification");
            throw;
        }
        finally
        {
            try { stream?.Close(); } catch { }
            try { stream?.Dispose(); } catch { }
            try { client?.Client?.Shutdown(SocketShutdown.Both); } catch { }
            try { client?.Client?.Dispose(); } catch { }
            try { client?.Close(); } catch { }
            client = null;
        }
    }
}

现在我解决了死锁问题,但我遇到了另一个问题。发送苹果通知时,触发这个Handle方法的MVC动作被调用了两次,这将导致业务规则异常(如果这个动作触发了两次,这是正常的事情)。并且根本没有收到 Apple 通知。
注意:当我在本地机器上调试发送Apple Notification的代码时,一切都很好,并且通知到达,并且仅调用了一次Action,在部署此代码后出现前面描述的问题到服务器。
注意:发送 Google 通知时根本不会出现此问题

这里顺便说一下Handle方法的触发

public class MessageBus : ICommandSender
{
    public static MessageBus Instance { get; private set; }

    private MessageBus()
    {
        handlers = new List<Delegate>();
    }

    static MessageBus()
    {
        if (Instance == null)
            Instance = new MessageBus();
    }

    private List<Delegate> handlers;

    public void Send<T>(T command) where T : ICommand
    {
        List<Task> tasks = new List<Task>();
        foreach (Func<T, Task> handle in handlers.OfType<Func<T, Task>>())
        {
            try { tasks.Add(handle(command)); }
            catch (Exception ex) { TracingSystem.TraceException(ex); }
        }

        try { Task.WaitAll(tasks.ToArray()); }
        catch (BusinessRuleException buzEx) { TracingSystem.TraceException(buzEx); throw buzEx; }
        catch (Exception ex) { TracingSystem.TraceException(ex); }
    }     
}

【问题讨论】:

  • 有没有一种简单的方法可以让我们重新创建代码并查看问题? stackoverflow.com/help/mcve
  • 我需要一些时间来解释我的疯狂情况。”紧随其后的是“很简单”......红灯闪烁!
  • 疯狂的情况来自于根本不起作用的简单@InBetween
  • 我觉得一点都不简单......
  • 看起来你正在使用 ASP.NET 实现 fire-and-forgetty。如果是这种情况,这可能会给您一些见解:stackoverflow.com/questions/18502745/…。检查答案中链接的博客...

标签: c# asp.net-mvc


【解决方案1】:

看起来你遇到了僵局。您需要阅读有关同步上下文和 ConfigureAwait 的信息。

我建议你使用:

await SendersFacade.PartnerSender.SendAsync(notification);

代替:

SendersFacade.PartnerSender.Send(notification).Wait();

UPD:

如果您无法使您的 Send 方法异步,您需要将 ConfigureAwait(false) 添加到可等待方法:

await client.PostAsync("https://fcm.googleapis.com/fcm/send", content).ConfigureAwait(false);

await message.Content.ReadAsStringAsync().ConfigureAwait(false);

这样可以避免死锁。

【讨论】:

  • 1: 我不能在我的方法中使用await,因为它不是async,这会产生编译错误,2: 没有SendAsync 的版本Send 本身就是一个异步方法,3: 调用wait 和把await 放在调用之前没有真正的区别, 4:您没有详细描述问题的解决方案
  • 1:只需将您的(匿名)方法标记为async2:正如您所说,Send 已经是async你不需要SendAsyncSend 的异步版本),3:呃……不,这两个(await vs wait)实际上是不同的,(见here... 和here),4:虽然它可能不是一个完整的解决方案,但@Aliaksandr 实际上确实描述了您问题的最可能的罪魁祸首......
  • @IronGeek 将匿名方法标记为async 并使用await 而不是调用wait() 不能解决问题,我也尝试了ConfigureAwait(false) 也不能解决问题.
  • @HakamFostok 就像我说的,这不是一个完整的解决方案。 TBH,我个人无法在不了解您的问题的整体情况的情况下为您提供完整 解决方案——这可能比您在此处描述的更复杂。照原样,我所能做的就是猜测。我最好的选择是:1:就像其他人指出的那样,您遇到了涉及使用.Wait() 和或.Result 的死锁情况,并且2:您是fire-and-forget(不是为 ASP.NET 原生设计的)
【解决方案2】:

但是为什么,下面的代码可以工作,而前面的代码却不能工作?

工作代码有效,因为它全部被同步调用,并且没有混合 async/await 和阻塞调用。

在前面的代码中,您将async/await.Result.Wait() 之类的阻塞调用混合在一起,这可能会导致死锁。你要么一直异步,要么一直同步。

我建议你重构GoogleNotificationSender,确保它一直是异步的

public class GoogleNotificationSender {
    private HttpClient client;
    private string authorizationToken;

    public GoogleNotificationSender(string authorizationToken) {
        this.AuthorizationToken = authorizationToken;
    }

    private string AuthorizationToken {
        get { return authorizationToken; }
        set {
            if (string.IsNullOrEmpty(value))
                throw new InvalidOperationException("authorizationToken must not be null");
            authorizationToken = value;
        }
    }

    private HttpClient Client {
        get {
            if (client == null) {
                client = new HttpClient();
                client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + AuthorizationToken);
            }
            return client;
        }
    }

    public async Task SendAsync(GoogleNotification notification) {
        TracingSystem.TraceInformation("Inside Send Google notification");

        var json = notification.GetJson();
        var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
        var requestUri = "https://fcm.googleapis.com/fcm/send";

        using (var message = await Client.PostAsync(requestUri, content)) {
            message.EnsureSuccessStatusCode();

            var result = await message.Content.ReadAsAsync<GoogleNotificationResult>();
            if (result.Failure > 0)
                throw new Exception($"Sending Failed : {result.Results.FirstOrDefault().Error}");
        }
    }
}

注意将Send 重命名为SendAsync 以正确表达意图。另外,请尽量不要在每次通话时创建新的HttpClient。这可能会产生副作用,但这超出了本问答的范围。 SO上已经有很多答案可以解释这一点。

接下来确保 Handler 也被正确地实现为异步

public class RequestAddedAppMonitorHandler : IHandler<RequestAdded> {
    public async Task Handle(RequestAdded args) {
        try {
            string deviceId = args.DeviceId;//This is an assumption here
            var notification = CreateAndroidPartnerAppNotification(deviceId);

            // this statment is executed, and the text log file will contains this line
            TracingSystem.TraceInformation("Before Send Google Notification");

            await SendersFacade.PartnerSender.SendAsync(notification);
        } catch (Exception ex) {
            TracingSystem.TraceException(ex);
        }
    }

    private GoogleNotification CreateAndroidPartnerAppNotification(string to) {
        // some initialization and creating for the notification object.
        return new GoogleNotification() {
            To = to
        };
    }
}

最后尝试确保调用堆栈中没有更高的阻塞调用,因为这只会让您重新陷入您遇到的死锁问题。即:曾经调用Task IHandler&lt;T&gt;.Handle(T args) 的内容不应混合使用异步调用和阻塞调用。

如果无法完全理解 async/await,你真的应该考虑阅读

Async/Await - Best Practices in Asynchronous Programming

为了更好地理解主题。

【讨论】:

  • 我知道这是一个很好的答案,我非常感谢您为帮助我所做的努力,我对您的答案投了赞成票。但我真的不完全理解异步/等待,因此我不喜欢它,我真的尝试了你的例子,但我仍然遇到同样的问题。我也试图让每件事都同步但没有奏效,我真的很挣扎并陷入了困境。
  • 感谢您对一路走async或一路同步的指示,其实我选择一路同步。我解决了死锁问题,但我遇到了另一个问题,请查看我对这个问题的最后更新。再次感谢您,我将致力于接受此答案并给予赏金,再次感谢您。
【解决方案3】:

我个人建议尝试一下 PushSharp。它为向 iOS、Android、Chrome 和 Windows Phone 推送通知提供了出色的代理异步解决方案。

发现自己使用并报告失败的推送尝试要容易得多。所有来自https://github.com/Redth/PushSharp 或通过 NuGet 的开源

【讨论】:

  • 我对 PushSharp 的尝试超出了您的想象,我尝试按原样使用它,我还在 github 上创建了一个 fork 并尝试使用该 fork,但没有任何帮助。还是谢谢
  • 同意此评论,将其用于 IOS 和 Android 通知 - 确实有一些问题,但没有什么大不了的。
【解决方案4】:

我觉得这里是死锁的罪魁祸首,检查HttpResponseMessage message = client.PostAsync("https://fcm.googleapis.com/fcm/send", content).Result 相对于https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html 的行

async 和 await 与调用 .Wait() 方法和 .Result 属性的组合,而不是一直在 async Task 方法中等待任务,可能会导致死锁,如此处所述。 https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

顺便说一句,我认为您对Task.Factory.StartNew 的使用不正确。尝试操作线程(或任务)而不是将其留在框架上是否有任何特殊原因。下面的代码有问题吗?

public class RequestAddedAppMonitorHandler : IHandler<RequestAdded>
{
    public async Task Handle(RequestAdded args)
    {
        try
        {
            GoogleNotification notification = CreateAndroidPartnerAppNotification(deviceId);

            // this statment is executed, and the text log file will contains this line
            TracingSystem.TraceInformation("Before Send Google Notification");  

            await SendersFacade.PartnerSender.Send(notification);
        }
        catch (Exception ex)
        {
            TracingSystem.TraceException(ex);
        }
    }
}

【讨论】:

    【解决方案5】:

    我认为这个问题是您在此处的调用中获得了async Task 的返回类型:

    public async Task Send(GoogleNotification notification)
    

    ...但是您实际上从未使用Task.Run 开始该任务。你可以在这里打电话给.Wait()

    SendersFacade.PartnerSender.Send(notification).Wait();
    

    ...但这不是它的工作原理,实际上,您必须启动任务才能等待它,它只会像那样永远等待.

    如果您将 Send 方法更改为具有这样的签名和正文,它将起作用:

        public Task Send(GoogleNotification notification)
        {
            return Task.Run(()=>
            {
                TracingSystem.TraceInformation("Inside Send Google notification");
    
                using (HttpClient client = new HttpClient())
                {
                    client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + AuthorizationToken);
    
                    string json = notification.GetJson();
                    StringContent content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
    
                    using (HttpResponseMessage message =client.PostAsync("https://fcm.googleapis.com/fcm/send", content).Result)
                    {
                        message.EnsureSuccessStatusCode();
    
                        string resultAsString = message.Content.ReadAsStringAsync().Result;
                        GoogleNotificationResult result = JsonConvert.DeserializeObject<GoogleNotificationResult>(resultAsString);
    
                        if (result.Failure > 0)
                            throw new Exception($"Sending Failed : {result.Results.FirstOrDefault().Error}");
                    }
                }
            });
        }
    

    请注意,我还删除了方法主体中的 await 关键字 - 我想保持简单并在父任务中同步运行,毕竟我们总体上是异步的,所以它不会产生身体内部的差异。

    这是一个完整的示例,将其打入控制台应用程序并试一试...

        static void Main(string[] args)
        {
            Console.WriteLine("Press any key to run.");
            Example thing = new Example();
            while (Console.ReadKey() != null)
                thing.Send();
        }
    
        class Example
        {
            Task<DisposableThing> DoTask()
            {
                return Task.Run(() => { Console.WriteLine("DoTask()"); return new DisposableThing(); });
            }
            Task<DisposableThing> DoTaskWillNotWork()
            {
                return new Task<DisposableThing>(() => { Console.WriteLine("DoTaskWillNotWork()"); return new DisposableThing(); });
            }
    
            async Task<DisposableThing> DoAsync()
            {
                Func<DisposableThing> action = new Func<DisposableThing>(() =>
                {
                    Console.WriteLine("DoAsync()");
                    return new DisposableThing();
                });
                return await Task.Run(action);
            }
    
            public Task Send()
            {
                return Task.Run(() =>
                {
                    using (DisposableThing client = new DisposableThing())
                    {
                        using (DisposableThing message = DoAsync().Result)
                        {
                            DisposableThing resultAsString = DoTask().Result;
                            DisposableThing resultAsString2 = DoTaskWillNotWork().Result;
                        }
                    }
                });
            }
        }
    
        class DisposableThing : IDisposable
        {
            public void Dispose()
            {
                //not much to do
            }
        }
    

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-02
      • 1970-01-01
      • 2016-08-04
      相关资源
      最近更新 更多