Получите трассировку стека асинхронных вызовов C # с помощью API, который использует отладчик Visual Studio - PullRequest
1 голос
/ 30 октября 2019

Можно ли получить эквивалентную трассировку стека, предоставляемую отладчиком Visual Studio 2019.

Например, если я устанавливаю точку останова в своем асинхронном коде внутри Visual Studio, я вижу следующую трассировку стека в «Вызове». Окно стека

    company.Common.dll!company.Common.Api.ResourcesDatabase.Lock() Line 58  C#
    company.Common.dll!company.Common.Api.ResourcesDatabase.ResourcesDatabase(bool openAndCreateDB) Line 29 C#
    company.Api.dll!company.Api.GlobalsDownloader.DownloadNewGlobals_UnderLock(System.Func<company.Common.Api.DTO.GlobalsType, System.Threading.Tasks.Task> reloadGlobals, company.Common.Api.DTO.GlobalsType globalsType) Line 124 C#
    [Resuming Async Method] 
    [External Code] 
    [Async Call Stack]  
    [Async] company.Api.dll!company.Api.ApiService.VerifyLogin_UnderLock(bool skipInitTasks, System.Threading.CancellationToken ct) Line 1147   C#
    [Async] company.Api.dll!company.Api.ApiService.VerifyLogin(System.Threading.CancellationToken ct) Line 955  C#
    [Async] company.Api.dll!company.Api.ApiService.Init(System.Action initComplete, bool dontCheckForUpdates) Line 250  C#
    [Async] company.Editor.exe!company.Editor.ViewModel.MainViewModel.Init() Line 524   C#
    [Async] company.Editor.exe!company.Editor.ViewModel.MainViewModel.InitViewModel.AnonymousMethod__31_0() Line 331    C#

Если я позвоню new System.Diagnostics.StackTrace(1,true), я получу следующее

   at company.Common.Api.ResourcesDatabase.Lock()
   at company.Common.Api.ResourcesDatabase..ctor(Boolean openAndCreateDB)
   at company.Api.GlobalsDownloader.<DownloadNewGlobals_UnderLock>d__6.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(Object stateMachine)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c__DisplayClass4_0.<OutputAsyncCausalityEvents>b__0()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
   at System.Runtime.CompilerServices.TaskAwaiter.<>c__DisplayClass11_0.<OutputWaitEtwEvents>b__0()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
   at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(Action action, Boolean allowInlining, Task& currentTask)
   at System.Threading.Tasks.Task.FinishContinuations()
   at System.Threading.Tasks.Task.FinishStageThree()
   ... 3 more layers of async
   at System.Threading.Tasks.Task.FinishContinuations()
   at System.Threading.Tasks.Task.FinishStageThree()
   at System.Threading.Tasks.Task`1.TrySetResult(TResult result)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncTrimPromise`1.Complete(TInstance thisRef, Func`3 endMethod, IAsyncResult asyncResult, Boolean requiresSynchronization)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncTrimPromise`1.CompleteFromAsyncResult(IAsyncResult asyncResult)
   at System.IO.Compression.DeflateStreamAsyncResult.Complete(Object result)
   at System.IO.Compression.DeflateStream.ReadCallback(IAsyncResult baseStreamResult)
   at System.IO.Stream.ReadWriteTask.InvokeAsyncCallback(Object completedTask)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.IO.Stream.ReadWriteTask.System.Threading.Tasks.ITaskCompletionAction.Invoke(Task completingTask)
   at System.Threading.Tasks.Task.FinishContinuations()
   at System.Threading.Tasks.Task.FinishStageThree()
   at System.Threading.Tasks.Task.FinishStageTwo()
   at System.Threading.Tasks.Task.Finish(Boolean bUserDelegateExecuted)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
   at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution)
   at System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()    6.67s       

Что мне действительно нравится в отладчике визуальной студии, так это то, что он может выяснить, что происходит раньшемеханизм асинхронного состояния.

[Resuming Async Method] 
[External Code] 
[Async Call Stack]  

Например, код перед «стеком асинхронных вызовов». Как отладчик Visual Studio получает этот стек вызовов и как я могу получить его в коде?

Я пробовал следующий пакет nuget, который немного очищает стек, но не помогает найти переход до нативного кодапереход.

https://github.com/benaadams/Ben.Demystifier

...