SlideShare a Scribd company logo
1 of 41
Download to read offline
About me
- Software Developer at JetBrains
- Mainly working on Rider’s
- .NET WASM debugging infrastructure
- EF / EF Core tooling
- Run / Debug configurations
- Recent open-source projects
- wasmer-dotnet: .NET bindings for Wasmer WebAssembly Runtime
- rider-efcore: EF Core plugin for Rider
- rider-monogame: MonoGame plugin for Rider
- GitHub: @seclerp
- Twitter: @seclerp
- Blog: blog.seclerp.me
Prologue: About .NET WebAssembly
.NET WebAssembly Family
- Blazor WebAssembly
- DevServer-hosted
- ASP.NET Core-hosted
- wasi-experimental workload
- browser-wasi RID
- Wasi.Sdk
- NativeAOT-LLVM WASM/WASI
- wasm-experimental workload
- browser-wasm RID
- console-wasm RID
Chapter 1: .NET WebAssembly App’s Anatomy
.NET WebAssembly App’s Anatomy: Blazor
> cat wwwroot/index.html
<!DOCTYPE html>
//.
<body>
<div id="app">
//.
//div>
//.
<script
src="_framework/blazor.webassembly.js"></script>
//body>
//html>
> dotnet new blazorwasm
/-name BlazorApp1
> cd BlazorApp1/BlazorApp1
.NET WebAssembly App’s Anatomy: Blazor
> dotnet build
> cd
bin/Debug/net7.0/wwwroot/_framework
> ls
blazor.boot.json <- 1
blazor.webassembly.js <- 2
BlazorApp1.dll <- 3
BlazorApp1.pdb
dotnet.wasm <- 4
mscorlib.dll
//.
> cat blazor.boot.json
{
//.
"entryAssembly": "BlazorApp1",
"resources": {
"runtime": {
"dotnet.wasm":
"sha256-6u4NhRISP<<.",
},
"runtimeAssets": {
"dotnet.wasm": {
"behavior": "dotnetwasm",
"hash": "sha256-6u4NhRISP//."
}
//.
}
}
.NET WebAssembly App’s Anatomy: Blazor
> cd /.//.//.//./
> dotnet run
Process tree:
dotnet: run
└── dotnet:
"~.nugetpackagesmicrosoft.aspnetcore.components.webassembly.devserver7.0.5/
tools/blazor-devserver.dll" <-applicationpath
"//.BlazorApp1binDebugnet7.0BlazorApp1.dll"
.NET WebAssembly App’s Anatomy: wasm-experimental
> cat index.html
<!DOCTYPE html>
<html>
<head>
//.
<script type='module' src="./main.js"></script>
//head>
<body>
<span id="out">//span>
//body>
//html>
> dotnet workload install
wasm-tools
wasm-experimental
> dotnet new wasmbrowser
/-name WasmApp1
> cd WasmApp1/WasmApp1
.NET WebAssembly App’s Anatomy: wasm-experimental
> cat main.js
import { dotnet } from './dotnet.js'
//.
await dotnet.run();
.NET WebAssembly App’s Anatomy: wasm-experimental
> dotnet build
> cd bin/Debug/net7.0/AppBundle
> ls
managed/ <- 3
dotnet.js <- 2
dotnet.js.symbols
dotnet.wasm /- 4
index.html
main.js
mono-config.json <- 1
WasmApp1.runtimeconfig.json <- 1
//.
> cat mono-config.json
{
"mainAssemblyName": "WasmApp1.dll",
"assemblyRootFolder": "managed",
"debugLevel": -1,
"remoteSources": [],
//.
"assetsHash": "sha256-zTDnY1om//."
}
.NET WebAssembly App’s Anatomy: wasm-experimental
> cat WasmApp1.runtimeconfig.json
{
"runtimeOptions": {
"tfm": "net8.0",
"wasmHostProperties": {
"perHostConfig": [
{
"name": "browser",
"html-path": "index.html",
"Host": "browser"
}
],
"runtimeArgs": [],
"mainAssembly": "WasmApp1.dll"
},
}
}
.NET WebAssembly App’s Anatomy: wasm-experimental
> cd /.//.//.//./
> dotnet run
WasmAppHost /-runtime-config
binDebugnet8.0browser-wasmAppBundleWasmApp1.runtimeconfig.json
App url: //.
Process tree:
dotnet: run
└── dotnet: exec "C:Program
FilesdotnetpacksMicrosoft.NET.Runtime.WebAssembly.Sdk8.0.0-preview.4.23259.
5WasmAppHostWasmAppHost.dll" /-runtime-config
"D:PlaygroundWasmApp1WasmApp1binDebugnet8.0browser-wasmAppBundleWasmAp
p1.runtimeconfig.json"
Quick intermediate summary
.NET WebAssembly app:
- Runs on Mono runtime*
- Has some JS glue code between the app and runtime
- Has different hosting models and toolchains:
- DevServer
- WasmAppHost
- ASP.NET Core
- How debugger communicates with the runtime? 🤔
- How the runtime communicates with the browser and vice-versa? 🤔
* Except NativeAOT-LLVM WASM, but it’s out-of-scope for this talk, it’s very experimental right now
Debugging of regular .NET Apps
Debugging of .NET WASM Apps
Chapter 2: The Debug Proxy
Meet Mono Proxy aka Debug Proxy
Process tree:
Rider.Backend.exe: …
└── winpty-agent.exe: …
└── dotnet:
~/.nuget/packages/microsoft.aspnetcore.components.webassembly.devserver/7.0.5/
tools/blazor-devserver.dll /-applicationpath binDebugnet7.0BlazorApp1.dll
└── dotnet: exec
"~.nugetpackagesmicrosoft.aspnetcore.components.webassembly.devserver7.0.5
toolsBlazorDebugProxyBrowserDebugHost.dll" /-OwnerPid 16152 /-DevToolsUrl
http://127.0.0.1:64069
Meet Mono Proxy aka Debug Proxy
* for simplicity we will call it just “Debug Proxy”
Meet Mono Proxy aka Debug Proxy
- Debugger Client doesn’t have a direct connection to a browser page
- Debug Proxy acts a mediator role in communication flow
- Debug Proxy proxifies JS app-related events from a browser page to a debugger client
and JS related function calls from the debugger client to a browser page
- Debug Proxy listens for Mono JS events from Mono runtime and controls it’s behavior by
calls via dotnet.js API
- Debug Proxy API is not documented and it’s quite unstable
Meet Mono Proxy aka Debug Proxy
How communication between there 3 parts is organized? Which protocol is used? 🤔
Chapter 3: The Protocol
A Handshake Process
1. Debugger: starts a WasmApp1 process (DevServer or
ASP.NET Core, depending on the hosting option), which
also starts Debug Proxy as a child process
Debugger
(Client)
Browser
Debug
Proxy
> chrome
“about:blank?…”
> dotnet run
GET
/_framework/
debug/ws-proxy?…
2. Debugger: starts a compatible browser (Chrome/Edge),
with a special placeholder URL (about:blank?realUrl=//.)
3. Browser: dumps it’s debugging port and path to a special
file in user’s profile folder.
4. Debugger: constructs debugging endpoint like that:
ws://127.0.0.1:{port}/{path}
5. Debugger: sends a debugging endpoint to a special
private URL called inspect url:
GET http://localhost:5170/_framework/debug/ws-proxy?
browser=ws://127.0.0.1:{port}/{path}
runtimeReady
A Handshake Process
6. Debug Proxy: initializes a WebSocket connection to
the browser by given browser debugging endpoint,
returns a new proxy debugging endpoint (with similar
shape but with a new port) as a 302 Redirect status code
Debugger
(Client)
Browser
navigate … navigate …
Debug
Proxy
302 Found
> chrome
“about:blank?…”
> dotnet run
Establishes a WS
connection
GET
/_framework/
debug/ws-proxy?…
Establishes a WS
connection
setBreakpoints…
7. Debugger: initializes a WebSocket connection to the
debug proxy by a received proxy debugging endpoint
8. Debugger: sends breakpoint requests to be resolved
by Mono runtime once ready
9. Debugger: “resolves” a real URL from a placeholder
URL (about:blank?…) and navigates a page to it
10. Debug Proxy: sends special event indicating that
Mono runtime is ready to accept .NET specific requests
Quick intermediate summary
- Handshake process is quite complex because of a lot of moving parts
- A hack with placeholder URLs exists because we need some controlled time between Debug Proxy
initialization and Mono runtime initialization to make preparations (like setting breakpoints before
they will be reached)
- It’s impossible to run more than 1 instance of Chromium browser under the same user profile folder
(because in such a case they will have conflict because of use of identical port)
For which communication process WebSocket connections are established?
🤔
CDP aka Chrome DevTools Protocol: Definition
- Defined by a set of modules, “domains”
- Each domain may contain:
- Types: transferred data records
- Methods: client-issued calls to the
CDP server (browser, Mono Proxy,
etc.)
Events: server-issued notifications to
the client
Examples
CDP aka Chrome DevTools Protocol: Explore
API Explorer
- Official:
chromedevtools.github.io
/devtools-protocol
- Alternative:
vanilla.aslushnikov.com
- Debug Proxy specific:
mono-cdp.seclerp.me
CDP aka Chrome DevTools Protocol: Transport
- Works over WebSocket
- Based on JSON-RPC 2.0*
- Messages are strictly ordered
- Supports buffering
- Supports 3 types of messages:
- Requests (client /> server, ordered)
- Responses (client /> server, ordered)
- Events (server /> client, unordered)
- Supports sessions (in our case, session per
browser tab)
Examples
- Request:
{"id":10, "method": "Page.navigate",
"params":{"url":"http://localhost:5170/"
}}
- Response:
{"id":10, “result”:
{"frameId":"…","loaderId":"…"}}
- Event:
{"method":
"Network.requestServedFromCache",
"params":{"requestId":"98279.21"}}
CDP aka Chrome DevTools Protocol: Targets
- Target defines anything that debugger
could be attached to. Examples:
- A browser
- A page
- A service worker
- A background page
- …
- One target session could be created from
another (e.g. page target session from
browser target session)
Chapter 4: Implementation
CDP Client
// Creating connection
var connection = new DefaultProtocolClient(new Uri("ws://localhost:5151"), logger);
await connection.ConnectAsync(cancellationToken);
// Sending commands
var response = await connection.SendCommandAsync(
Domains.DotnetDebugger.SetDebuggerProperty(
JustMyCodeStepping: true
)
);
// Firing commands (when we're not interested in response)
await connection.FireCommandAsync(Domains.Debugger.StepOut());
CDP Client
// Listening for events
pageClient.ListenEvent<Domains.Debugger.BreakpointResolved>(async e />
{
ResolveBreakpoint(e.BreakpointId.Value);
});
// Creating scoped clients (clients for specific sessions)
var scopedClient = connection.CreateScoped(sessionId);
Sample: Page connection initialization
var result = await connection.SendCommandAsync(
Domains.Target.AttachToTarget(
TargetId: placeholderTarget.TargetId,
// Non-flatten mode will be deprecated in the future
Flatten: true));
var pageConnection = connection.CreateScoped(result.SessionId.Value);
logger.LogInformation("Initializing debugger-related domains//.");
await Task.WhenAll(
pageConnection.SendCommandAsync(Domains.Debugger.Enable()),
pageConnection.SendCommandAsync(Domains.Log.Enable()),
pageConnection.SendCommandAsync(Domains.Runtime.Enable()),
pageConnection.SendCommandAsync(Domains.Page.Enable()),
pageConnection.SendCommandAsync(Domains.Network.Enable())
);
Sending Messages
private readonly BlockingCollection<ProtocolRequest<ICommand/> _outgoingMessages = …
public async Task<TResponse> SendCommandAsync<TResponse>(ICommand<TResponse> command,
string? sessionId = null,
CancellationToken? token = default) where TResponse : IType
{
var id = Interlocked.Increment(ref _currentId);
var resolver = new TaskCompletionSource<JObject>();
if (_responseResolvers.TryAdd(id, resolver))
{
await FireInternalAsync(id, GetMethodName(command.GetType()), command, sessionId);
var responseRaw = await resolver.Task;
var response = responseRaw.ToObject//.
return response;
}
throw new Exception("Unable to enqueue message to send");
}
private async Task FireInternalAsync(int id, string methodName, ICommand command, string? sessionId)
{
var request = new ProtocolRequest<ICommand>(id, methodName, command, sessionId);
if (!_outgoingMessages.TryAdd(request)) throw new Exception("Can't schedule outgoing message for sending.");
}
private async Task
StartOutgoingWorker(CancellationToken token)
{
_logger.LogInformation("Starting outgoing
messages pump//.");
while (!token.IsCancellationRequested)
{
var message = _outgoingMessages.Take();
await ProcessOutgoingRequest(message);
}
}
Retrieving Messages
private Task ProcessIncoming(string message) />
DeserializeMessage(message) switch
{
ProtocolResponse<JObject> response /> ProcessIncomingResponse(response),
ProtocolEvent<JObject> @event /> ProcessIncomingEvent(@event),
_ /> Task.CompletedTask
};
private async Task ProcessIncomingEvent(ProtocolEvent<JObject> @event)
{
OnEventReceived?.Invoke(this, @event);
if (_eventHandlers.TryGetValue(@event.Method, out var handler))
await handler.Invoke(@event);
}
private async Task ProcessIncomingResponse(ProtocolResponse<JObject> response)
{
OnResponseReceived?.Invoke(this, response);
_responseResolvers.TryRemove(response.Id, out var resolver);
if (response.Error is { } error) resolver?.SetException(new ProtocolErrorException(error));
if (response.Result is { } result) resolver?.SetResult(result);
}
Sample: Set, Remove & Resolve Breakpoints
pageClient.ListenEvent<Domains.Debugger.BreakpointResolved>(async e />
{
ResolveBreakpoint(e.BreakpointId.Value);
});
private void ResolveBreakpoint(string breakpointId)
{
if (_breakpointsStorage.TryGetBreakEventInfo(breakpointId, out var info))
{
var bindingBreakEvent = new WasmBindingBreakEvent(info.BreakEvent, WasmModule.Instance);
if (!info.AddBindingBreakEvent(bindingBreakEvent))
{
_logger.LogInformation($"{bindingBreakEvent} is not added to {info}");
info.SetStatus(BreakEventStatus.NotBound, $"Could not insert breakpoint {info.BreakEvent}");
}
else
info.SetStatus(BreakEventStatus.Bound, null);
}
}
Sample: Set, Remove & Resolve Breakpoints
async Task HandleAddBreakpointRequest(BreakEventInfo<WasmModule> info)
{
// //.
// Map 'C:Foobar' to 'file:///C:/Foo/bar'
var fileUrl = new Uri(url.Path).ToString();
var (protocolLine, protocolColumn) =
WasmProxyLocationMapper.ToMonoProxyUnits(line, column);
var (breakpointId, locations) = await pageClient.SendCommandAsync(
Domains.Debugger.SetBreakpointByUrl(
LineNumber: protocolLine, ColumnNumber: protocolColumn, Url: fileUrl
));
if (!_breakpointsStorage.TryAdd(breakpointId.Value, info))
_logger.LogWarning("Can't add breakpoint '{Info}' with ID '{BreakpointId}'", info, breakpointId.Value);
// Check maybe we already know script with resolved script ID
foreach (var location in locations)
if (_scriptsStorage.IsLoaded(location.ScriptId.Value))
ResolveBreakpoint(breakpointId.Value);
}
Bonus: Few words about Hot-Reload
Hot-Reload
- Without debugging: dotnet watch and related infrastructure
- With debugging (EnC): Available in Debug Proxy since .NET SDK 7
(not yet in Rider 🥵)
- EnC follows the following algorithm:
1. User pauses execution for some reason (breakpoint, manually, …)
2. User changes things in code…
3. User hits Continue or Apply changes
4. Delta is computed (IL delta, metadata delta and PDB delta)
5. Debugger sends delta to the runtime (via Debug Proxy or other mechanism)
6. Runtime applies deltas
7. Debugger resets breakpoints (as lines in code have possibly been changed)
8. Debugger resumes execution
Thanks for your attention!
Links
- WebAssembly
- WebAssembly System Interface: wasi.dev
- Chrome DevTools Protocol
- API Explorer: chromedevtools.github.io/devtools-protocol
- API Explorer (alternative): vanilla.aslushnikov.com
- Mono Extension Explorer: mono-cdp.seclerp.me
- Blog posts
- The Future of .NET with WASM by Khalid Abuhakmeh
- Videos
- Blazor United prototype by Steven Sanderson
- Experiments with the new WASI workload in .NET 8 Preview 4 by Steven Sanderson

More Related Content

Similar to "Hidden difficulties of debugger implementation for .NET WASM apps", Andrii Rublov

Phonegap android angualr material design
Phonegap android angualr material designPhonegap android angualr material design
Phonegap android angualr material designSrinadh Kanugala
 
PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents
PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agentsPVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents
PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agentsAndrey Karpov
 
Porting Rails Apps to High Availability Systems
Porting Rails Apps to High Availability SystemsPorting Rails Apps to High Availability Systems
Porting Rails Apps to High Availability SystemsMarcelo Pinheiro
 
Building websites with Node.ACS
Building websites with Node.ACSBuilding websites with Node.ACS
Building websites with Node.ACSralcocer
 
Building websites with Node.ACS
Building websites with Node.ACSBuilding websites with Node.ACS
Building websites with Node.ACSRicardo Alcocer
 
Making a small QA system with Docker
Making a small QA system with DockerMaking a small QA system with Docker
Making a small QA system with DockerNaoki AINOYA
 
Reactive Application Using METEOR
Reactive Application Using METEORReactive Application Using METEOR
Reactive Application Using METEORNodeXperts
 
Node.js on microsoft azure april 2014
Node.js on microsoft azure april 2014Node.js on microsoft azure april 2014
Node.js on microsoft azure april 2014Brian Benz
 
58615764 net-and-j2 ee-web-services
58615764 net-and-j2 ee-web-services58615764 net-and-j2 ee-web-services
58615764 net-and-j2 ee-web-serviceshomeworkping3
 
(ARC402) Deployment Automation: From Developers' Keyboards to End Users' Scre...
(ARC402) Deployment Automation: From Developers' Keyboards to End Users' Scre...(ARC402) Deployment Automation: From Developers' Keyboards to End Users' Scre...
(ARC402) Deployment Automation: From Developers' Keyboards to End Users' Scre...Amazon Web Services
 
DevOPS training - Day 2/2
DevOPS training - Day 2/2DevOPS training - Day 2/2
DevOPS training - Day 2/2Vincent Mercier
 
ДМИТРО БУДИМ «Mobile Automation Infrastructure from scratch» Online QADay 202...
ДМИТРО БУДИМ «Mobile Automation Infrastructure from scratch» Online QADay 202...ДМИТРО БУДИМ «Mobile Automation Infrastructure from scratch» Online QADay 202...
ДМИТРО БУДИМ «Mobile Automation Infrastructure from scratch» Online QADay 202...GoQA
 
Docker Enterprise Workshop - Technical
Docker Enterprise Workshop - TechnicalDocker Enterprise Workshop - Technical
Docker Enterprise Workshop - TechnicalPatrick Chanezon
 
Server(less) Swift at SwiftCloudWorkshop 3
Server(less) Swift at SwiftCloudWorkshop 3Server(less) Swift at SwiftCloudWorkshop 3
Server(less) Swift at SwiftCloudWorkshop 3kognate
 
Scaling Docker Containers using Kubernetes and Azure Container Service
Scaling Docker Containers using Kubernetes and Azure Container ServiceScaling Docker Containers using Kubernetes and Azure Container Service
Scaling Docker Containers using Kubernetes and Azure Container ServiceBen Hall
 
Building Mobile Friendly APIs in Rails
Building Mobile Friendly APIs in RailsBuilding Mobile Friendly APIs in Rails
Building Mobile Friendly APIs in RailsJim Jeffers
 

Similar to "Hidden difficulties of debugger implementation for .NET WASM apps", Andrii Rublov (20)

Phonegap android angualr material design
Phonegap android angualr material designPhonegap android angualr material design
Phonegap android angualr material design
 
PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents
PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agentsPVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents
PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents
 
Porting Rails Apps to High Availability Systems
Porting Rails Apps to High Availability SystemsPorting Rails Apps to High Availability Systems
Porting Rails Apps to High Availability Systems
 
Building websites with Node.ACS
Building websites with Node.ACSBuilding websites with Node.ACS
Building websites with Node.ACS
 
Building websites with Node.ACS
Building websites with Node.ACSBuilding websites with Node.ACS
Building websites with Node.ACS
 
Node js
Node jsNode js
Node js
 
Making a small QA system with Docker
Making a small QA system with DockerMaking a small QA system with Docker
Making a small QA system with Docker
 
Reactive Application Using METEOR
Reactive Application Using METEORReactive Application Using METEOR
Reactive Application Using METEOR
 
Node.js on microsoft azure april 2014
Node.js on microsoft azure april 2014Node.js on microsoft azure april 2014
Node.js on microsoft azure april 2014
 
58615764 net-and-j2 ee-web-services
58615764 net-and-j2 ee-web-services58615764 net-and-j2 ee-web-services
58615764 net-and-j2 ee-web-services
 
(ARC402) Deployment Automation: From Developers' Keyboards to End Users' Scre...
(ARC402) Deployment Automation: From Developers' Keyboards to End Users' Scre...(ARC402) Deployment Automation: From Developers' Keyboards to End Users' Scre...
(ARC402) Deployment Automation: From Developers' Keyboards to End Users' Scre...
 
Node J pdf.docx
Node J pdf.docxNode J pdf.docx
Node J pdf.docx
 
Node J pdf.docx
Node J pdf.docxNode J pdf.docx
Node J pdf.docx
 
DevOPS training - Day 2/2
DevOPS training - Day 2/2DevOPS training - Day 2/2
DevOPS training - Day 2/2
 
Love at first Vue
Love at first VueLove at first Vue
Love at first Vue
 
ДМИТРО БУДИМ «Mobile Automation Infrastructure from scratch» Online QADay 202...
ДМИТРО БУДИМ «Mobile Automation Infrastructure from scratch» Online QADay 202...ДМИТРО БУДИМ «Mobile Automation Infrastructure from scratch» Online QADay 202...
ДМИТРО БУДИМ «Mobile Automation Infrastructure from scratch» Online QADay 202...
 
Docker Enterprise Workshop - Technical
Docker Enterprise Workshop - TechnicalDocker Enterprise Workshop - Technical
Docker Enterprise Workshop - Technical
 
Server(less) Swift at SwiftCloudWorkshop 3
Server(less) Swift at SwiftCloudWorkshop 3Server(less) Swift at SwiftCloudWorkshop 3
Server(less) Swift at SwiftCloudWorkshop 3
 
Scaling Docker Containers using Kubernetes and Azure Container Service
Scaling Docker Containers using Kubernetes and Azure Container ServiceScaling Docker Containers using Kubernetes and Azure Container Service
Scaling Docker Containers using Kubernetes and Azure Container Service
 
Building Mobile Friendly APIs in Rails
Building Mobile Friendly APIs in RailsBuilding Mobile Friendly APIs in Rails
Building Mobile Friendly APIs in Rails
 

More from Fwdays

"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y..."How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...Fwdays
 
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil TopchiiFwdays
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro Spodarets"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro SpodaretsFwdays
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
"Distributed graphs and microservices in Prom.ua", Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua", Maksym KindritskyiFwdays
 
"Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl..."Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl...Fwdays
 
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T..."How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...Fwdays
 
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ..."The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...Fwdays
 
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu..."[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...Fwdays
 
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care..."[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...Fwdays
 
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"..."4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...Fwdays
 
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout", Anast...
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout",  Anast..."Reconnecting with Purpose: Rediscovering Job Interest after Burnout",  Anast...
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout", Anast...Fwdays
 
"Mentoring 101: How to effectively invest experience in the success of others...
"Mentoring 101: How to effectively invest experience in the success of others..."Mentoring 101: How to effectively invest experience in the success of others...
"Mentoring 101: How to effectively invest experience in the success of others...Fwdays
 
"Mission (im) possible: How to get an offer in 2024?", Oleksandra Myronova
"Mission (im) possible: How to get an offer in 2024?",  Oleksandra Myronova"Mission (im) possible: How to get an offer in 2024?",  Oleksandra Myronova
"Mission (im) possible: How to get an offer in 2024?", Oleksandra MyronovaFwdays
 
"Why have we learned how to package products, but not how to 'package ourselv...
"Why have we learned how to package products, but not how to 'package ourselv..."Why have we learned how to package products, but not how to 'package ourselv...
"Why have we learned how to package products, but not how to 'package ourselv...Fwdays
 
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin..."How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...Fwdays
 

More from Fwdays (20)

"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y..."How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
"How Preply reduced ML model development time from 1 month to 1 day",Yevhen Y...
 
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
"GenAI Apps: Our Journey from Ideas to Production Excellence",Danil Topchii
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro Spodarets"What is a RAG system and how to build it",Dmytro Spodarets
"What is a RAG system and how to build it",Dmytro Spodarets
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
"Distributed graphs and microservices in Prom.ua", Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi"Distributed graphs and microservices in Prom.ua",  Maksym Kindritskyi
"Distributed graphs and microservices in Prom.ua", Maksym Kindritskyi
 
"Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl..."Rethinking the existing data loading and processing process as an ETL exampl...
"Rethinking the existing data loading and processing process as an ETL exampl...
 
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T..."How Ukrainian IT specialist can go on vacation abroad without crossing the T...
"How Ukrainian IT specialist can go on vacation abroad without crossing the T...
 
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ..."The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
"The Strength of Being Vulnerable: the experience from CIA, Tesla and Uber", ...
 
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu..."[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
"[QUICK TALK] Radical candor: how to achieve results faster thanks to a cultu...
 
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care..."[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
"[QUICK TALK] PDP Plan, the only one door to raise your salary and boost care...
 
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"..."4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
"4 horsemen of the apocalypse of working relationships (+ antidotes to them)"...
 
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout", Anast...
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout",  Anast..."Reconnecting with Purpose: Rediscovering Job Interest after Burnout",  Anast...
"Reconnecting with Purpose: Rediscovering Job Interest after Burnout", Anast...
 
"Mentoring 101: How to effectively invest experience in the success of others...
"Mentoring 101: How to effectively invest experience in the success of others..."Mentoring 101: How to effectively invest experience in the success of others...
"Mentoring 101: How to effectively invest experience in the success of others...
 
"Mission (im) possible: How to get an offer in 2024?", Oleksandra Myronova
"Mission (im) possible: How to get an offer in 2024?",  Oleksandra Myronova"Mission (im) possible: How to get an offer in 2024?",  Oleksandra Myronova
"Mission (im) possible: How to get an offer in 2024?", Oleksandra Myronova
 
"Why have we learned how to package products, but not how to 'package ourselv...
"Why have we learned how to package products, but not how to 'package ourselv..."Why have we learned how to package products, but not how to 'package ourselv...
"Why have we learned how to package products, but not how to 'package ourselv...
 
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin..."How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
"How to tame the dragon, or leadership with imposter syndrome", Oleksandr Zin...
 

Recently uploaded

My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Hyundai Motor Group
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxnull - The Open Security Community
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAndikSusilo4
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 

Recently uploaded (20)

My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & Application
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
The transition to renewables in India.pdf
The transition to renewables in India.pdfThe transition to renewables in India.pdf
The transition to renewables in India.pdf
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 

"Hidden difficulties of debugger implementation for .NET WASM apps", Andrii Rublov

  • 1.
  • 2. About me - Software Developer at JetBrains - Mainly working on Rider’s - .NET WASM debugging infrastructure - EF / EF Core tooling - Run / Debug configurations - Recent open-source projects - wasmer-dotnet: .NET bindings for Wasmer WebAssembly Runtime - rider-efcore: EF Core plugin for Rider - rider-monogame: MonoGame plugin for Rider - GitHub: @seclerp - Twitter: @seclerp - Blog: blog.seclerp.me
  • 3. Prologue: About .NET WebAssembly
  • 4. .NET WebAssembly Family - Blazor WebAssembly - DevServer-hosted - ASP.NET Core-hosted - wasi-experimental workload - browser-wasi RID - Wasi.Sdk - NativeAOT-LLVM WASM/WASI - wasm-experimental workload - browser-wasm RID - console-wasm RID
  • 5. Chapter 1: .NET WebAssembly App’s Anatomy
  • 6. .NET WebAssembly App’s Anatomy: Blazor > cat wwwroot/index.html <!DOCTYPE html> //. <body> <div id="app"> //. //div> //. <script src="_framework/blazor.webassembly.js"></script> //body> //html> > dotnet new blazorwasm /-name BlazorApp1 > cd BlazorApp1/BlazorApp1
  • 7. .NET WebAssembly App’s Anatomy: Blazor > dotnet build > cd bin/Debug/net7.0/wwwroot/_framework > ls blazor.boot.json <- 1 blazor.webassembly.js <- 2 BlazorApp1.dll <- 3 BlazorApp1.pdb dotnet.wasm <- 4 mscorlib.dll //. > cat blazor.boot.json { //. "entryAssembly": "BlazorApp1", "resources": { "runtime": { "dotnet.wasm": "sha256-6u4NhRISP<<.", }, "runtimeAssets": { "dotnet.wasm": { "behavior": "dotnetwasm", "hash": "sha256-6u4NhRISP//." } //. } }
  • 8. .NET WebAssembly App’s Anatomy: Blazor > cd /.//.//.//./ > dotnet run Process tree: dotnet: run └── dotnet: "~.nugetpackagesmicrosoft.aspnetcore.components.webassembly.devserver7.0.5/ tools/blazor-devserver.dll" <-applicationpath "//.BlazorApp1binDebugnet7.0BlazorApp1.dll"
  • 9. .NET WebAssembly App’s Anatomy: wasm-experimental > cat index.html <!DOCTYPE html> <html> <head> //. <script type='module' src="./main.js"></script> //head> <body> <span id="out">//span> //body> //html> > dotnet workload install wasm-tools wasm-experimental > dotnet new wasmbrowser /-name WasmApp1 > cd WasmApp1/WasmApp1
  • 10. .NET WebAssembly App’s Anatomy: wasm-experimental > cat main.js import { dotnet } from './dotnet.js' //. await dotnet.run();
  • 11. .NET WebAssembly App’s Anatomy: wasm-experimental > dotnet build > cd bin/Debug/net7.0/AppBundle > ls managed/ <- 3 dotnet.js <- 2 dotnet.js.symbols dotnet.wasm /- 4 index.html main.js mono-config.json <- 1 WasmApp1.runtimeconfig.json <- 1 //. > cat mono-config.json { "mainAssemblyName": "WasmApp1.dll", "assemblyRootFolder": "managed", "debugLevel": -1, "remoteSources": [], //. "assetsHash": "sha256-zTDnY1om//." }
  • 12. .NET WebAssembly App’s Anatomy: wasm-experimental > cat WasmApp1.runtimeconfig.json { "runtimeOptions": { "tfm": "net8.0", "wasmHostProperties": { "perHostConfig": [ { "name": "browser", "html-path": "index.html", "Host": "browser" } ], "runtimeArgs": [], "mainAssembly": "WasmApp1.dll" }, } }
  • 13. .NET WebAssembly App’s Anatomy: wasm-experimental > cd /.//.//.//./ > dotnet run WasmAppHost /-runtime-config binDebugnet8.0browser-wasmAppBundleWasmApp1.runtimeconfig.json App url: //. Process tree: dotnet: run └── dotnet: exec "C:Program FilesdotnetpacksMicrosoft.NET.Runtime.WebAssembly.Sdk8.0.0-preview.4.23259. 5WasmAppHostWasmAppHost.dll" /-runtime-config "D:PlaygroundWasmApp1WasmApp1binDebugnet8.0browser-wasmAppBundleWasmAp p1.runtimeconfig.json"
  • 14. Quick intermediate summary .NET WebAssembly app: - Runs on Mono runtime* - Has some JS glue code between the app and runtime - Has different hosting models and toolchains: - DevServer - WasmAppHost - ASP.NET Core - How debugger communicates with the runtime? 🤔 - How the runtime communicates with the browser and vice-versa? 🤔 * Except NativeAOT-LLVM WASM, but it’s out-of-scope for this talk, it’s very experimental right now
  • 15. Debugging of regular .NET Apps
  • 16. Debugging of .NET WASM Apps
  • 17. Chapter 2: The Debug Proxy
  • 18. Meet Mono Proxy aka Debug Proxy Process tree: Rider.Backend.exe: … └── winpty-agent.exe: … └── dotnet: ~/.nuget/packages/microsoft.aspnetcore.components.webassembly.devserver/7.0.5/ tools/blazor-devserver.dll /-applicationpath binDebugnet7.0BlazorApp1.dll └── dotnet: exec "~.nugetpackagesmicrosoft.aspnetcore.components.webassembly.devserver7.0.5 toolsBlazorDebugProxyBrowserDebugHost.dll" /-OwnerPid 16152 /-DevToolsUrl http://127.0.0.1:64069
  • 19. Meet Mono Proxy aka Debug Proxy * for simplicity we will call it just “Debug Proxy”
  • 20. Meet Mono Proxy aka Debug Proxy - Debugger Client doesn’t have a direct connection to a browser page - Debug Proxy acts a mediator role in communication flow - Debug Proxy proxifies JS app-related events from a browser page to a debugger client and JS related function calls from the debugger client to a browser page - Debug Proxy listens for Mono JS events from Mono runtime and controls it’s behavior by calls via dotnet.js API - Debug Proxy API is not documented and it’s quite unstable
  • 21. Meet Mono Proxy aka Debug Proxy How communication between there 3 parts is organized? Which protocol is used? 🤔
  • 22. Chapter 3: The Protocol
  • 23. A Handshake Process 1. Debugger: starts a WasmApp1 process (DevServer or ASP.NET Core, depending on the hosting option), which also starts Debug Proxy as a child process Debugger (Client) Browser Debug Proxy > chrome “about:blank?…” > dotnet run GET /_framework/ debug/ws-proxy?… 2. Debugger: starts a compatible browser (Chrome/Edge), with a special placeholder URL (about:blank?realUrl=//.) 3. Browser: dumps it’s debugging port and path to a special file in user’s profile folder. 4. Debugger: constructs debugging endpoint like that: ws://127.0.0.1:{port}/{path} 5. Debugger: sends a debugging endpoint to a special private URL called inspect url: GET http://localhost:5170/_framework/debug/ws-proxy? browser=ws://127.0.0.1:{port}/{path}
  • 24. runtimeReady A Handshake Process 6. Debug Proxy: initializes a WebSocket connection to the browser by given browser debugging endpoint, returns a new proxy debugging endpoint (with similar shape but with a new port) as a 302 Redirect status code Debugger (Client) Browser navigate … navigate … Debug Proxy 302 Found > chrome “about:blank?…” > dotnet run Establishes a WS connection GET /_framework/ debug/ws-proxy?… Establishes a WS connection setBreakpoints… 7. Debugger: initializes a WebSocket connection to the debug proxy by a received proxy debugging endpoint 8. Debugger: sends breakpoint requests to be resolved by Mono runtime once ready 9. Debugger: “resolves” a real URL from a placeholder URL (about:blank?…) and navigates a page to it 10. Debug Proxy: sends special event indicating that Mono runtime is ready to accept .NET specific requests
  • 25. Quick intermediate summary - Handshake process is quite complex because of a lot of moving parts - A hack with placeholder URLs exists because we need some controlled time between Debug Proxy initialization and Mono runtime initialization to make preparations (like setting breakpoints before they will be reached) - It’s impossible to run more than 1 instance of Chromium browser under the same user profile folder (because in such a case they will have conflict because of use of identical port) For which communication process WebSocket connections are established? 🤔
  • 26. CDP aka Chrome DevTools Protocol: Definition - Defined by a set of modules, “domains” - Each domain may contain: - Types: transferred data records - Methods: client-issued calls to the CDP server (browser, Mono Proxy, etc.) Events: server-issued notifications to the client Examples
  • 27. CDP aka Chrome DevTools Protocol: Explore API Explorer - Official: chromedevtools.github.io /devtools-protocol - Alternative: vanilla.aslushnikov.com - Debug Proxy specific: mono-cdp.seclerp.me
  • 28. CDP aka Chrome DevTools Protocol: Transport - Works over WebSocket - Based on JSON-RPC 2.0* - Messages are strictly ordered - Supports buffering - Supports 3 types of messages: - Requests (client /> server, ordered) - Responses (client /> server, ordered) - Events (server /> client, unordered) - Supports sessions (in our case, session per browser tab) Examples - Request: {"id":10, "method": "Page.navigate", "params":{"url":"http://localhost:5170/" }} - Response: {"id":10, “result”: {"frameId":"…","loaderId":"…"}} - Event: {"method": "Network.requestServedFromCache", "params":{"requestId":"98279.21"}}
  • 29. CDP aka Chrome DevTools Protocol: Targets - Target defines anything that debugger could be attached to. Examples: - A browser - A page - A service worker - A background page - … - One target session could be created from another (e.g. page target session from browser target session)
  • 31. CDP Client // Creating connection var connection = new DefaultProtocolClient(new Uri("ws://localhost:5151"), logger); await connection.ConnectAsync(cancellationToken); // Sending commands var response = await connection.SendCommandAsync( Domains.DotnetDebugger.SetDebuggerProperty( JustMyCodeStepping: true ) ); // Firing commands (when we're not interested in response) await connection.FireCommandAsync(Domains.Debugger.StepOut());
  • 32. CDP Client // Listening for events pageClient.ListenEvent<Domains.Debugger.BreakpointResolved>(async e /> { ResolveBreakpoint(e.BreakpointId.Value); }); // Creating scoped clients (clients for specific sessions) var scopedClient = connection.CreateScoped(sessionId);
  • 33. Sample: Page connection initialization var result = await connection.SendCommandAsync( Domains.Target.AttachToTarget( TargetId: placeholderTarget.TargetId, // Non-flatten mode will be deprecated in the future Flatten: true)); var pageConnection = connection.CreateScoped(result.SessionId.Value); logger.LogInformation("Initializing debugger-related domains//."); await Task.WhenAll( pageConnection.SendCommandAsync(Domains.Debugger.Enable()), pageConnection.SendCommandAsync(Domains.Log.Enable()), pageConnection.SendCommandAsync(Domains.Runtime.Enable()), pageConnection.SendCommandAsync(Domains.Page.Enable()), pageConnection.SendCommandAsync(Domains.Network.Enable()) );
  • 34. Sending Messages private readonly BlockingCollection<ProtocolRequest<ICommand/> _outgoingMessages = … public async Task<TResponse> SendCommandAsync<TResponse>(ICommand<TResponse> command, string? sessionId = null, CancellationToken? token = default) where TResponse : IType { var id = Interlocked.Increment(ref _currentId); var resolver = new TaskCompletionSource<JObject>(); if (_responseResolvers.TryAdd(id, resolver)) { await FireInternalAsync(id, GetMethodName(command.GetType()), command, sessionId); var responseRaw = await resolver.Task; var response = responseRaw.ToObject//. return response; } throw new Exception("Unable to enqueue message to send"); } private async Task FireInternalAsync(int id, string methodName, ICommand command, string? sessionId) { var request = new ProtocolRequest<ICommand>(id, methodName, command, sessionId); if (!_outgoingMessages.TryAdd(request)) throw new Exception("Can't schedule outgoing message for sending."); } private async Task StartOutgoingWorker(CancellationToken token) { _logger.LogInformation("Starting outgoing messages pump//."); while (!token.IsCancellationRequested) { var message = _outgoingMessages.Take(); await ProcessOutgoingRequest(message); } }
  • 35. Retrieving Messages private Task ProcessIncoming(string message) /> DeserializeMessage(message) switch { ProtocolResponse<JObject> response /> ProcessIncomingResponse(response), ProtocolEvent<JObject> @event /> ProcessIncomingEvent(@event), _ /> Task.CompletedTask }; private async Task ProcessIncomingEvent(ProtocolEvent<JObject> @event) { OnEventReceived?.Invoke(this, @event); if (_eventHandlers.TryGetValue(@event.Method, out var handler)) await handler.Invoke(@event); } private async Task ProcessIncomingResponse(ProtocolResponse<JObject> response) { OnResponseReceived?.Invoke(this, response); _responseResolvers.TryRemove(response.Id, out var resolver); if (response.Error is { } error) resolver?.SetException(new ProtocolErrorException(error)); if (response.Result is { } result) resolver?.SetResult(result); }
  • 36. Sample: Set, Remove & Resolve Breakpoints pageClient.ListenEvent<Domains.Debugger.BreakpointResolved>(async e /> { ResolveBreakpoint(e.BreakpointId.Value); }); private void ResolveBreakpoint(string breakpointId) { if (_breakpointsStorage.TryGetBreakEventInfo(breakpointId, out var info)) { var bindingBreakEvent = new WasmBindingBreakEvent(info.BreakEvent, WasmModule.Instance); if (!info.AddBindingBreakEvent(bindingBreakEvent)) { _logger.LogInformation($"{bindingBreakEvent} is not added to {info}"); info.SetStatus(BreakEventStatus.NotBound, $"Could not insert breakpoint {info.BreakEvent}"); } else info.SetStatus(BreakEventStatus.Bound, null); } }
  • 37. Sample: Set, Remove & Resolve Breakpoints async Task HandleAddBreakpointRequest(BreakEventInfo<WasmModule> info) { // //. // Map 'C:Foobar' to 'file:///C:/Foo/bar' var fileUrl = new Uri(url.Path).ToString(); var (protocolLine, protocolColumn) = WasmProxyLocationMapper.ToMonoProxyUnits(line, column); var (breakpointId, locations) = await pageClient.SendCommandAsync( Domains.Debugger.SetBreakpointByUrl( LineNumber: protocolLine, ColumnNumber: protocolColumn, Url: fileUrl )); if (!_breakpointsStorage.TryAdd(breakpointId.Value, info)) _logger.LogWarning("Can't add breakpoint '{Info}' with ID '{BreakpointId}'", info, breakpointId.Value); // Check maybe we already know script with resolved script ID foreach (var location in locations) if (_scriptsStorage.IsLoaded(location.ScriptId.Value)) ResolveBreakpoint(breakpointId.Value); }
  • 38. Bonus: Few words about Hot-Reload
  • 39. Hot-Reload - Without debugging: dotnet watch and related infrastructure - With debugging (EnC): Available in Debug Proxy since .NET SDK 7 (not yet in Rider 🥵) - EnC follows the following algorithm: 1. User pauses execution for some reason (breakpoint, manually, …) 2. User changes things in code… 3. User hits Continue or Apply changes 4. Delta is computed (IL delta, metadata delta and PDB delta) 5. Debugger sends delta to the runtime (via Debug Proxy or other mechanism) 6. Runtime applies deltas 7. Debugger resets breakpoints (as lines in code have possibly been changed) 8. Debugger resumes execution
  • 40. Thanks for your attention!
  • 41. Links - WebAssembly - WebAssembly System Interface: wasi.dev - Chrome DevTools Protocol - API Explorer: chromedevtools.github.io/devtools-protocol - API Explorer (alternative): vanilla.aslushnikov.com - Mono Extension Explorer: mono-cdp.seclerp.me - Blog posts - The Future of .NET with WASM by Khalid Abuhakmeh - Videos - Blazor United prototype by Steven Sanderson - Experiments with the new WASI workload in .NET 8 Preview 4 by Steven Sanderson