From b412228ed69aae0a388906370a871e44a4867cd8 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Mon, 5 Dec 2022 18:35:42 -0300 Subject: [PATCH] Blazor WebAssembly Debug extension is not working with .net7 (#7929) * We cannot use the BrowserDebugProxy from the extension folder, that one only works with .net6 app, and it should work with .net6 and .net7, so we should use the inspectURI which will start the correct browserDebugProxy version. * try to get the inspectUri from the launchSettings.json file, if it cannot be found then use the default one, this will make possible debug the new browserwasm template * avoiding exception if profiles doesn't exist --- .gitignore | 1 - .../README.dev.md | 2 - .../package.json | 8 +- .../scripts/retrieveDebugProxy.js | 75 ---------------- .../src/acquireDotnetInstall.ts | 34 -------- .../src/extension.ts | 86 +++---------------- .../src/getAvailablePort.ts | 27 ------ .../BlazorDebugConfigurationProvider.ts | 13 +-- 8 files changed, 14 insertions(+), 232 deletions(-) delete mode 100644 src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/scripts/retrieveDebugProxy.js delete mode 100644 src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/src/acquireDotnetInstall.ts delete mode 100644 src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/src/getAvailablePort.ts diff --git a/.gitignore b/.gitignore index c9e8119b20..64c2c1352d 100644 --- a/.gitignore +++ b/.gitignore @@ -154,5 +154,4 @@ yarn-*.log *.svclog # Bundled extension assets -src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/BlazorDebugProxy/ *.vsix diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/README.dev.md b/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/README.dev.md index e257a80e86..41f45c0c6d 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/README.dev.md +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/README.dev.md @@ -22,8 +22,6 @@ To that end, we need a way to launch the debugging proxy on the user's host mach In order to publish the extension, you will need to have access to the `ms.dotnet-tools` publisher account on the VS Code marketplace. If you don't already have this access, reach out to @captainsafia for info. -This extension bundles the debugging proxy assets that are needed inside the `BlazorDebugProxy` directory. These assets are not committed to repository so they will need to be included as part of the publish process. - 1. Generate a personal access token per the instructions in [the VS Code publishing guide](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page). 2. Store the token from #1 in the `VSCODE_MARKETPLACE_TOKEN` environment variable. 3. Increment the `patch` version of the package in the `package.json` file. diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/package.json b/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/package.json index 5fb1641bea..d7e79562c4 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/package.json +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/package.json @@ -22,17 +22,13 @@ ], "publisher": "ms-dotnettools", "activationEvents": [ - "onCommand:blazorwasm-companion.launchDebugProxy", - "onCommand:blazorwasm-companion.killDebugProxy" + "onCommand:blazorwasm-companion.launchDebugProxy" ], "main": "./dist/extension.js", "extensionDependencies": [ "ms-dotnettools.vscode-dotnet-runtime", "ms-dotnettools.csharp" ], - "files": [ - "BlazorDebugProxy/" - ], "capabilities": { "untrustedWorkspaces": { "supported": true @@ -42,7 +38,7 @@ "scripts": { "vscode:prepublish": "yarn run build", "clean": "rimraf dist", - "build": "yarn run clean && yarn run lint && yarn run compile && node scripts/retrieveDebugProxy.js", + "build": "yarn run clean && yarn run lint && yarn run compile", "compile": "tsc -p ./", "watch": "tsc -watch -p ./", "pretest": "yarn run compile && yarn run lint", diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/scripts/retrieveDebugProxy.js b/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/scripts/retrieveDebugProxy.js deleted file mode 100644 index 1fe73c959f..0000000000 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/scripts/retrieveDebugProxy.js +++ /dev/null @@ -1,75 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -const fetch = require('node-fetch'); -const stream = require('stream'); -const extract = require('extract-zip'); -const fs = require('fs'); -const util = require('util'); -const path = require('path'); -const os = require('os'); - -const finished = util.promisify(stream.finished); - -const formatLog = (text) => `[${new Date()}] ${text}`; -const log = (text) => console.log(formatLog(text)); -const logError = (text) => console.error(formatLog(text)); - -async function downloadProxyPackage(version) { - const tmpDirectory = path.join(os.tmpdir(), 'blazorwasm-companion-tmp'); - if (!fs.existsSync(tmpDirectory)) { - fs.mkdirSync(tmpDirectory); - } - - // nuget.org requires the package name be lower-case - const nugetUrl = 'https://api.nuget.org/v3-flatcontainer'; - const packageName = 'Microsoft.AspNetCore.Components.WebAssembly.DevServer'.toLowerCase(); - const versionedPackageName = `${packageName}.${version}.nupkg`; - const downloadUrl = `${nugetUrl}/${packageName}/${version}/${versionedPackageName}`; - - // Download and save nupkg to disk - log(`Fetching package from ${downloadUrl}...`); - const response = await fetch(downloadUrl); - - if (!response.ok) { - logError(`Failed to download ${downloadUrl}`); - throw new Error(`Unable to download BlazorDebugProxy: ${response.status} ${response.statusText}`); - } - - const downloadPath = path.join(tmpDirectory, versionedPackageName); - const outputStream = fs.createWriteStream(downloadPath); - response.body.pipe(outputStream); - await finished(outputStream); - - // Extract nupkg to extraction directory - log(`Extracting NuGet package with directory...`) - const extractTarget = path.join(tmpDirectory, `extracted-${packageName}.${version}`); - await extract(downloadPath, { dir: extractTarget }); - return extractTarget; -} - -async function copyDebugProxyAssets(version) { - const targetDirectory = path.join(__dirname, '..', 'BlazorDebugProxy', version); - if (fs.existsSync(targetDirectory)) { - log(`BlazorDebugProxy ${version} is already downloaded, nothing to do.`); - return; - } - - log(`Downloading BlazorDebugProxy ${version}...`); - const extracted = await downloadProxyPackage(version); - - log(`Using ${targetDirectory} as targetDirectory...`); - fs.mkdirSync(targetDirectory, { recursive: true }); - - const srcDirectory = path.join(extracted, 'tools', 'BlazorDebugProxy'); - log(`Copying BlazorDebugProxy assets from ${srcDirectory} to ${targetDirectory}...`); - fs.readdirSync(srcDirectory).forEach(function(file) { - log(`Copying ${file} to target directory...`); - fs.copyFileSync(path.join(srcDirectory, file), path.join(targetDirectory, file)); - }); -} - -const debugProxyVersion = require('../package.json').debugProxyVersion; -copyDebugProxyAssets(debugProxyVersion); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/src/acquireDotnetInstall.ts b/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/src/acquireDotnetInstall.ts deleted file mode 100644 index c5d466fa71..0000000000 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/src/acquireDotnetInstall.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import { commands, extensions, OutputChannel } from 'vscode'; - -interface IDotnetAcquireResult { - dotnetPath: string; -} - -export async function acquireDotnetInstall(outputChannel: OutputChannel): Promise { - const extension = extensions.getExtension('ms-dotnettools.blazorwasm-companion'); - const requestingExtensionId = 'blazorwasm-companion'; - - const version: string = extension && extension.packageJSON ? extension.packageJSON.dotnetRuntimeVersion : '6.0'; - if (version.split('.').length !== 2) { - throw new Error('Version should be a valid major.minor version (the latest patch will automatically be selected).'); - } - - try { - const dotnetResult = await commands.executeCommand('dotnet.acquire', { version, requestingExtensionId }); - const dotnetPath = dotnetResult?.dotnetPath; - if (!dotnetPath) { - throw new Error('Install step returned an undefined path.'); - } - await commands.executeCommand('dotnet.ensureDotnetDependencies', { command: dotnetPath, arguments: ['--info'] }); - return dotnetPath; - } catch (error) { - outputChannel.appendLine(`This extension requires .NET Core to run but we were unable to install it due to the following error:`); - outputChannel.appendLine((error as Error).message); - throw error; - } -} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/src/extension.ts b/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/src/extension.ts index b9bc721c34..544b897d71 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/src/extension.ts +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/src/extension.ts @@ -3,89 +3,23 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import * as cp from 'child_process'; +import { readFileSync } from 'fs'; +import { join } from 'path'; +import { fileURLToPath } from 'url'; import * as vscode from 'vscode'; -import { acquireDotnetInstall } from './acquireDotnetInstall'; -import { getAvailablePort } from './getAvailablePort'; export async function activate(context: vscode.ExtensionContext) { - const outputChannel = vscode.window.createOutputChannel('Blazor WASM Debug Proxy'); - const pidsByUrl = new Map(); - - const launchDebugProxy = vscode.commands.registerCommand('blazorwasm-companion.launchDebugProxy', async () => { - try { - const debuggingPort = await getAvailablePort(9222); - const debuggingHost = `http://localhost:${debuggingPort}`; - - const extension = vscode.extensions.getExtension('ms-dotnettools.blazorwasm-companion'); - const version: string = extension?.packageJSON.debugProxyVersion; - - const debugProxyLocalPath = `${context.extensionPath}/BlazorDebugProxy/${version}/BrowserDebugHost.dll`; - const spawnedProxyArgs = [debugProxyLocalPath , '--DevToolsUrl', debuggingHost]; - - const dotnet = await acquireDotnetInstall(outputChannel); - - outputChannel.appendLine(`Launching debugging proxy from ${debugProxyLocalPath}`); - const spawnedProxy = cp.spawn(dotnet, spawnedProxyArgs); - - try { - let chunksProcessed = 0; - for await (const output of spawnedProxy.stdout) { - // If we haven't found the URL in the first ten chunks processed - // then bail out. - if (chunksProcessed++ > 10) { - return; - } - outputChannel.appendLine(output); - // The debug proxy server outputs the port it is listening on in the - // standard output of the launched application. We need to pass this URL - // back to the debugger so we extract the URL from stdout using a regex. - // The debug proxy will not exit until killed via the `killDebugProxy` - // method so parsing stdout is necessary to extract the URL. - const matchExpr = 'Now listening on: (?.*)'; - const found = `${output}`.match(matchExpr); - const url = found?.groups?.url; - if (url) { - outputChannel.appendLine(`Debugging proxy is running at: ${url}`); - pidsByUrl.set(url, spawnedProxy.pid); - return { - url, - inspectUri: `${url}{browserInspectUriPath}`, - debuggingPort, - }; - } - } - - for await (const error of spawnedProxy.stderr) { - outputChannel.appendLine(`ERROR: ${error}`); - } - } catch (error: any) { - if (spawnedProxy.pid) { - outputChannel.appendLine(`Error occured while spawning debug proxy. Terminating debug proxy server.`); - process.kill(spawnedProxy.pid); - } - throw error; - } - } catch (error: any) { - outputChannel.appendLine(`ERROR: ${error}`); + const launchDebugProxy = vscode.commands.registerCommand('blazorwasm-companion.launchDebugProxy', async (folder: vscode.WorkspaceFolder) => { + const launchSettings = JSON.parse(readFileSync(join(fileURLToPath(folder.uri.toString()), 'Properties', 'launchSettings.json'), 'utf8')); + if (launchSettings?.profiles && launchSettings?.profiles[Object.keys(launchSettings.profiles)[0]]?.inspectUri) { + return { + inspectUri: launchSettings.profiles[Object.keys(launchSettings.profiles)[0]].inspectUri, + }; } - return { inspectUri: '{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}', }; }); - const killDebugProxy = vscode.commands.registerCommand('blazorwasm-companion.killDebugProxy', (url: string) => { - const pid = pidsByUrl.get(url); - - if (!pid) { - outputChannel.appendLine(`Unable to find PID for server running at ${url}.`); - return; - } - - outputChannel.appendLine(`Terminating debug proxy server running at ${url} with PID ${pid}.`); - process.kill(pid); - }); - - context.subscriptions.push(launchDebugProxy, killDebugProxy); + context.subscriptions.push(launchDebugProxy); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/src/getAvailablePort.ts b/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/src/getAvailablePort.ts deleted file mode 100644 index 14f5080300..0000000000 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode.BlazorWasmDebuggingExtension/src/getAvailablePort.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import * as net from 'net'; - -export function getAvailablePort(initialPort: number) { - function getNextAvailablePort(currentPort: number, cb: (port: number) => void) { - const server = net.createServer(); - server.listen(currentPort, () => { - server.once('close', () => { - cb(currentPort); - }); - server.close(); - }); - server.on('error', () => { - if (currentPort <= 65535 /* total number of ports available */) { - getNextAvailablePort(++currentPort, cb); - } - }); - } - - return new Promise(resolve => { - getNextAvailablePort(initialPort, resolve); - }); -} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode/src/BlazorDebug/BlazorDebugConfigurationProvider.ts b/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode/src/BlazorDebug/BlazorDebugConfigurationProvider.ts index 5acce235cb..6f73be069f 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode/src/BlazorDebug/BlazorDebugConfigurationProvider.ts +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.VSCode/src/BlazorDebug/BlazorDebugConfigurationProvider.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import { RazorLogger } from '../RazorLogger'; import { JS_DEBUG_NAME, SERVER_APP_NAME } from './Constants'; -import { isValidEvent, onDidTerminateDebugSession } from './TerminateDebugHandler'; +import { onDidTerminateDebugSession } from './TerminateDebugHandler'; export class BlazorDebugConfigurationProvider implements vscode.DebugConfigurationProvider { @@ -27,7 +27,7 @@ export class BlazorDebugConfigurationProvider implements vscode.DebugConfigurati url: string, inspectUri: string, debuggingPort: number, - }>('blazorwasm-companion.launchDebugProxy'); + }>('blazorwasm-companion.launchDebugProxy', folder); await this.launchBrowser( folder, @@ -35,15 +35,6 @@ export class BlazorDebugConfigurationProvider implements vscode.DebugConfigurati result ? result.inspectUri : undefined, result ? result.debuggingPort : undefined); - if (result && result.url) { - const terminateDebugProxy = this.vscodeType.debug.onDidTerminateDebugSession(async event => { - if (isValidEvent(event.name)) { - await vscode.commands.executeCommand('blazorwasm-companion.killDebugProxy', result.url); - terminateDebugProxy.dispose(); - } - }); - } - /** * If `resolveDebugConfiguration` returns undefined, then the debugger * launch is canceled. Here, we opt to manually launch the browser