admin
2020-06-10 a610f2ab6e543d2cb78c1ef212ac6a74ddc067d9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// Copyright © 2015 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
 
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Schedulers;
 
namespace CefSharp.Internals
{
    public sealed class MethodRunnerQueue : IMethodRunnerQueue
    {
        //Limit to 1 task per methodRunnerQueue
        //https://social.msdn.microsoft.com/Forums/vstudio/en-US/d0bcb415-fb1e-42e4-90f8-c43a088537fb/aborting-a-long-running-task-in-tpl?forum=parallelextensions
        private readonly TaskFactory methodRunnerQueueTaskFactory = new TaskFactory(new LimitedConcurrencyLevelTaskScheduler(1));
        private readonly JavascriptObjectRepository repository;
        private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
 
        public event EventHandler<MethodInvocationCompleteArgs> MethodInvocationComplete;
 
        public MethodRunnerQueue(JavascriptObjectRepository repository)
        {
            this.repository = repository;
        }
 
        public void Dispose()
        {
            //Cancel all tasks associated with this MethoRunnerQueue
            cancellationTokenSource.Cancel();
        }
 
        public void Enqueue(MethodInvocation methodInvocation)
        {
            methodRunnerQueueTaskFactory.StartNew(() =>
            {
                var result = ExecuteMethodInvocation(methodInvocation);
 
                var handler = MethodInvocationComplete;
                if (!cancellationTokenSource.Token.IsCancellationRequested && handler != null)
                {
                    handler(this, new MethodInvocationCompleteArgs(result));
                }
            }, cancellationTokenSource.Token);
        }
 
        private MethodInvocationResult ExecuteMethodInvocation(MethodInvocation methodInvocation)
        {
            object result = null;
            string exception;
            var success = false;
 
            //make sure we don't throw exceptions in the executor task
            try
            {
                success = repository.TryCallMethod(methodInvocation.ObjectId, methodInvocation.MethodName, methodInvocation.Parameters.ToArray(), out result, out exception);
 
                //We don't support Tasks by default
                if (success && result != null && (typeof(Task).IsAssignableFrom(result.GetType())))
                {
                    //Use StringBuilder to improve the formatting/readability of the error message
                    //I'm sure there's a better way I just cannot remember of the top of my head so going
                    //with this for now, as it's only for error scenaiors I'm not concerned about performance.
                    var builder = new System.Text.StringBuilder();
                    builder.AppendLine("Your method returned a Task which is not supported by default you must set CefSharpSettings.ConcurrentTaskExecution = true; before creating your first ChromiumWebBrowser instance.");
                    builder.AppendLine("This will likely change to the default at some point in the near future, subscribe to the issue link below to be notified of any changes.");
                    builder.AppendLine("See https://github.com/cefsharp/CefSharp/issues/2758 for more details, please report any issues you have there, make sure you have an example ready that reproduces your problem.");
 
                    success = false;
                    result = null;
                    exception = builder.ToString();
                }
 
            }
            catch (Exception e)
            {
                exception = e.Message;
            }
 
            return new MethodInvocationResult
            {
                BrowserId = methodInvocation.BrowserId,
                CallbackId = methodInvocation.CallbackId,
                FrameId = methodInvocation.FrameId,
                Message = exception,
                Result = result,
                Success = success
            };
        }
    }
}