diff --git a/build/dependencies.props b/build/dependencies.props
index bb260a366..b5274ed65 100644
--- a/build/dependencies.props
+++ b/build/dependencies.props
@@ -6,7 +6,7 @@
3.23.1
2.55.0
2.46.6
- 2.57.0
+ 2.59.0
8.0.0-rc.1.23378.7
7.0.5
6.0.11
diff --git a/examples/Spar/Server/ClientApp/package-lock.json b/examples/Spar/Server/ClientApp/package-lock.json
index cf74ae03a..237267ff8 100644
--- a/examples/Spar/Server/ClientApp/package-lock.json
+++ b/examples/Spar/Server/ClientApp/package-lock.json
@@ -36,12 +36,13 @@
}
},
"node_modules/@babel/code-frame": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
- "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+ "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"dependencies": {
- "@babel/highlight": "^7.16.7"
+ "@babel/highlight": "^7.22.13",
+ "chalk": "^2.4.2"
},
"engines": {
"node": ">=6.9.0"
@@ -108,28 +109,20 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.17.3",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz",
- "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+ "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.17.0",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
+ "@babel/types": "^7.23.0",
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "@jridgewell/trace-mapping": "^0.3.17",
+ "jsesc": "^2.5.1"
},
"engines": {
"node": ">=6.9.0"
}
},
- "node_modules/@babel/generator/node_modules/source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/@babel/helper-annotate-as-pure": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz",
@@ -248,13 +241,10 @@
}
},
"node_modules/@babel/helper-environment-visitor": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz",
- "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+ "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"dev": true,
- "dependencies": {
- "@babel/types": "^7.16.7"
- },
"engines": {
"node": ">=6.9.0"
}
@@ -272,38 +262,25 @@
}
},
"node_modules/@babel/helper-function-name": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz",
- "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+ "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"dependencies": {
- "@babel/helper-get-function-arity": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/types": "^7.16.7"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-get-function-arity": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz",
- "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.16.7"
+ "@babel/template": "^7.22.15",
+ "@babel/types": "^7.23.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-hoist-variables": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
- "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==",
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
+ "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.16.7"
+ "@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
@@ -428,21 +405,30 @@
}
},
"node_modules/@babel/helper-split-export-declaration": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
- "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==",
+ "version": "7.22.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
+ "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.16.7"
+ "@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
+ "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
- "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@@ -487,13 +473,13 @@
}
},
"node_modules/@babel/highlight": {
- "version": "7.16.10",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz",
- "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
+ "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dev": true,
"dependencies": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "chalk": "^2.0.0",
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "chalk": "^2.4.2",
"js-tokens": "^4.0.0"
},
"engines": {
@@ -501,9 +487,9 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.17.3",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz",
- "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
+ "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@@ -1666,33 +1652,33 @@
}
},
"node_modules/@babel/template": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
- "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dev": true,
"dependencies": {
- "@babel/code-frame": "^7.16.7",
- "@babel/parser": "^7.16.7",
- "@babel/types": "^7.16.7"
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
- "version": "7.17.3",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz",
- "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.17.3",
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-function-name": "^7.16.7",
- "@babel/helper-hoist-variables": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/parser": "^7.17.3",
- "@babel/types": "^7.17.0",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+ "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.0",
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-function-name": "^7.23.0",
+ "@babel/helper-hoist-variables": "^7.22.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/parser": "^7.23.0",
+ "@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@@ -1701,12 +1687,13 @@
}
},
"node_modules/@babel/types": {
- "version": "7.17.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz",
- "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
+ "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dev": true,
"dependencies": {
- "@babel/helper-validator-identifier": "^7.16.7",
+ "@babel/helper-string-parser": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
@@ -1719,29 +1706,52 @@
"integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==",
"dev": true
},
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
+ "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/set-array": "^1.0.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.9"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/@jridgewell/resolve-uri": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz",
- "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
+ "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/set-array": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.4.11",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz",
- "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==",
+ "version": "1.4.15",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.4",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz",
- "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==",
+ "version": "0.3.19",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
+ "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
"dev": true,
"dependencies": {
- "@jridgewell/resolve-uri": "^3.0.3",
- "@jridgewell/sourcemap-codec": "^1.4.10"
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@mrmlnc/readdir-enhanced": {
@@ -9376,12 +9386,13 @@
}
},
"@babel/code-frame": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
- "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+ "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"requires": {
- "@babel/highlight": "^7.16.7"
+ "@babel/highlight": "^7.22.13",
+ "chalk": "^2.4.2"
}
},
"@babel/compat-data": {
@@ -9428,22 +9439,15 @@
}
},
"@babel/generator": {
- "version": "7.17.3",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz",
- "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+ "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"dev": true,
"requires": {
- "@babel/types": "^7.17.0",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- },
- "dependencies": {
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- }
+ "@babel/types": "^7.23.0",
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "@jridgewell/trace-mapping": "^0.3.17",
+ "jsesc": "^2.5.1"
}
},
"@babel/helper-annotate-as-pure": {
@@ -9535,13 +9539,10 @@
}
},
"@babel/helper-environment-visitor": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz",
- "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+ "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
+ "dev": true
},
"@babel/helper-explode-assignable-expression": {
"version": "7.16.7",
@@ -9553,32 +9554,22 @@
}
},
"@babel/helper-function-name": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz",
- "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==",
- "dev": true,
- "requires": {
- "@babel/helper-get-function-arity": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-get-function-arity": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz",
- "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+ "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"requires": {
- "@babel/types": "^7.16.7"
+ "@babel/template": "^7.22.15",
+ "@babel/types": "^7.23.0"
}
},
"@babel/helper-hoist-variables": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
- "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==",
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
+ "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
"dev": true,
"requires": {
- "@babel/types": "^7.16.7"
+ "@babel/types": "^7.22.5"
}
},
"@babel/helper-member-expression-to-functions": {
@@ -9673,18 +9664,24 @@
}
},
"@babel/helper-split-export-declaration": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
- "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==",
+ "version": "7.22.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
+ "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"requires": {
- "@babel/types": "^7.16.7"
+ "@babel/types": "^7.22.5"
}
},
+ "@babel/helper-string-parser": {
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
+ "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
+ "dev": true
+ },
"@babel/helper-validator-identifier": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
- "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true
},
"@babel/helper-validator-option": {
@@ -9717,20 +9714,20 @@
}
},
"@babel/highlight": {
- "version": "7.16.10",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz",
- "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
+ "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dev": true,
"requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "chalk": "^2.0.0",
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "chalk": "^2.4.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
- "version": "7.17.3",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz",
- "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
+ "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"dev": true
},
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
@@ -10505,41 +10502,42 @@
}
},
"@babel/template": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
- "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/parser": "^7.16.7",
- "@babel/types": "^7.16.7"
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
}
},
"@babel/traverse": {
- "version": "7.17.3",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz",
- "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.17.3",
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-function-name": "^7.16.7",
- "@babel/helper-hoist-variables": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/parser": "^7.17.3",
- "@babel/types": "^7.17.0",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+ "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.0",
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-function-name": "^7.23.0",
+ "@babel/helper-hoist-variables": "^7.22.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/parser": "^7.23.0",
+ "@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
}
},
"@babel/types": {
- "version": "7.17.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz",
- "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
+ "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dev": true,
"requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
+ "@babel/helper-string-parser": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
}
},
@@ -10549,26 +10547,43 @@
"integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==",
"dev": true
},
+ "@jridgewell/gen-mapping": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
+ "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/set-array": "^1.0.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.9"
+ }
+ },
"@jridgewell/resolve-uri": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz",
- "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
+ "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
+ "dev": true
+ },
+ "@jridgewell/set-array": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"dev": true
},
"@jridgewell/sourcemap-codec": {
- "version": "1.4.11",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz",
- "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==",
+ "version": "1.4.15",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
},
"@jridgewell/trace-mapping": {
- "version": "0.3.4",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz",
- "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==",
+ "version": "0.3.19",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
+ "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
"dev": true,
"requires": {
- "@jridgewell/resolve-uri": "^3.0.3",
- "@jridgewell/sourcemap-codec": "^1.4.10"
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"@mrmlnc/readdir-enhanced": {
diff --git a/src/Grpc.AspNetCore.Server/Internal/GrpcProtocolHelpers.cs b/src/Grpc.AspNetCore.Server/Internal/GrpcProtocolHelpers.cs
index 11aa0d1a7..ef5a7b191 100644
--- a/src/Grpc.AspNetCore.Server/Internal/GrpcProtocolHelpers.cs
+++ b/src/Grpc.AspNetCore.Server/Internal/GrpcProtocolHelpers.cs
@@ -1,4 +1,4 @@
-#region Copyright notice and license
+#region Copyright notice and license
// Copyright 2019 The gRPC Authors
//
@@ -234,4 +234,17 @@ internal static bool ShouldSkipHeader(string name)
{
return name.StartsWith(':') || GrpcProtocolConstants.FilteredHeaders.Contains(name);
}
+
+ internal static IHttpRequestLifetimeFeature GetRequestLifetimeFeature(HttpContext httpContext)
+ {
+ var lifetimeFeature = httpContext.Features.Get();
+ if (lifetimeFeature is null)
+ {
+ // This should only run in tests where the HttpContext is manually created.
+ lifetimeFeature = new HttpRequestLifetimeFeature();
+ httpContext.Features.Set(lifetimeFeature);
+ }
+
+ return lifetimeFeature;
+ }
}
diff --git a/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamReader.cs b/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamReader.cs
index 3525cf37a..528aeed87 100644
--- a/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamReader.cs
+++ b/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamReader.cs
@@ -17,8 +17,10 @@
#endregion
using System.Diagnostics;
+using System.IO.Pipelines;
using Grpc.Core;
using Grpc.Shared;
+using Microsoft.AspNetCore.Http.Features;
namespace Grpc.AspNetCore.Server.Internal;
@@ -28,6 +30,8 @@ internal class HttpContextStreamReader : IAsyncStreamReader
{
private readonly HttpContextServerCallContext _serverCallContext;
private readonly Func _deserializer;
+ private readonly PipeReader _bodyReader;
+ private readonly IHttpRequestLifetimeFeature _requestLifetimeFeature;
private bool _completed;
private long _readCount;
private bool _endOfStream;
@@ -36,6 +40,12 @@ public HttpContextStreamReader(HttpContextServerCallContext serverCallContext, F
{
_serverCallContext = serverCallContext;
_deserializer = deserializer;
+
+ // Copy HttpContext values.
+ // This is done to avoid a race condition when reading them from HttpContext later when running in a separate thread.
+ _bodyReader = _serverCallContext.HttpContext.Request.BodyReader;
+ // Copy lifetime feature because HttpContext.RequestAborted on .NET 6 doesn't return the real cancellation token.
+ _requestLifetimeFeature = GrpcProtocolHelpers.GetRequestLifetimeFeature(_serverCallContext.HttpContext);
}
public TRequest Current { get; private set; } = default!;
@@ -54,7 +64,7 @@ async Task MoveNextAsync(ValueTask readStreamTask)
return Task.FromCanceled(cancellationToken);
}
- if (_completed || _serverCallContext.CancellationToken.IsCancellationRequested)
+ if (_completed || _requestLifetimeFeature.RequestAborted.IsCancellationRequested)
{
return Task.FromException(new InvalidOperationException("Can't read messages after the request is complete."));
}
@@ -63,7 +73,7 @@ async Task MoveNextAsync(ValueTask readStreamTask)
// In a long running stream this can allow the previous value to be GCed.
Current = null!;
- var request = _serverCallContext.HttpContext.Request.BodyReader.ReadStreamMessageAsync(_serverCallContext, _deserializer, cancellationToken);
+ var request = _bodyReader.ReadStreamMessageAsync(_serverCallContext, _deserializer, cancellationToken);
if (!request.IsCompletedSuccessfully)
{
return MoveNextAsync(request);
diff --git a/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamWriter.cs b/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamWriter.cs
index 1518fc9eb..b6a67f9fd 100644
--- a/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamWriter.cs
+++ b/src/Grpc.AspNetCore.Server/Internal/HttpContextStreamWriter.cs
@@ -17,8 +17,10 @@
#endregion
using System.Diagnostics;
+using System.IO.Pipelines;
using Grpc.Core;
using Grpc.Shared;
+using Microsoft.AspNetCore.Http.Features;
namespace Grpc.AspNetCore.Server.Internal;
@@ -29,6 +31,8 @@ internal class HttpContextStreamWriter : IServerStreamWriter _serializer;
+ private readonly PipeWriter _bodyWriter;
+ private readonly IHttpRequestLifetimeFeature _requestLifetimeFeature;
private readonly object _writeLock;
private Task? _writeTask;
private bool _completed;
@@ -39,6 +43,12 @@ public HttpContextStreamWriter(HttpContextServerCallContext context, Actiontrue
true
- net462;netstandard1.5;netstandard2.0
+ net462;netstandard2.0
README.md
diff --git a/src/Grpc.Core.Api/Grpc.Core.Api.csproj b/src/Grpc.Core.Api/Grpc.Core.Api.csproj
index 6cf865ff7..bb6756d1e 100755
--- a/src/Grpc.Core.Api/Grpc.Core.Api.csproj
+++ b/src/Grpc.Core.Api/Grpc.Core.Api.csproj
@@ -5,7 +5,7 @@
true
true
- net462;netstandard1.5;netstandard2.0;netstandard2.1
+ net462;netstandard2.0;netstandard2.1
README.md
true
diff --git a/src/Grpc.Core.Api/Internal/ClientDebuggerHelpers.cs b/src/Grpc.Core.Api/Internal/ClientDebuggerHelpers.cs
index f309fd8ce..3ca7b0dba 100644
--- a/src/Grpc.Core.Api/Internal/ClientDebuggerHelpers.cs
+++ b/src/Grpc.Core.Api/Internal/ClientDebuggerHelpers.cs
@@ -25,11 +25,7 @@ namespace Grpc.Core.Internal;
internal static class ClientDebuggerHelpers
{
-#if NETSTANDARD1_5
- private static TypeInfo? GetParentType(Type clientType)
-#else
private static Type? GetParentType(Type clientType)
-#endif
{
// Attempt to get the parent type for a generated client.
// A generated client is always nested inside a static type that contains information about the client.
@@ -48,11 +44,7 @@ internal static class ClientDebuggerHelpers
return null;
}
-#if NETSTANDARD1_5
- var parentType = clientType.DeclaringType.GetTypeInfo();
-#else
var parentType = clientType.DeclaringType;
-#endif
// Check parent type is static. A C# static type is sealed and abstract.
if (parentType == null || (!parentType.IsSealed && !parentType.IsAbstract))
{
@@ -101,10 +93,6 @@ internal static class ClientDebuggerHelpers
return methods;
static bool IsMethodField(FieldInfo field) =>
-#if NETSTANDARD1_5
- typeof(IMethod).GetTypeInfo().IsAssignableFrom(field.FieldType);
-#else
typeof(IMethod).IsAssignableFrom(field.FieldType);
-#endif
}
}
diff --git a/src/Grpc.Core.Api/Status.cs b/src/Grpc.Core.Api/Status.cs
index 01055cd9e..45d795562 100644
--- a/src/Grpc.Core.Api/Status.cs
+++ b/src/Grpc.Core.Api/Status.cs
@@ -15,6 +15,7 @@
#endregion
using System;
+using System.Diagnostics;
namespace Grpc.Core;
@@ -22,6 +23,7 @@ namespace Grpc.Core;
///
/// Represents RPC result, which consists of and an optional detail string.
///
+[DebuggerDisplay("{DebuggerToString(),nq}")]
public struct Status
{
///
@@ -93,4 +95,19 @@ public override string ToString()
}
return $"Status(StatusCode=\"{StatusCode}\", Detail=\"{Detail}\")";
}
+
+ private string DebuggerToString()
+ {
+ var text = $"StatusCode = {StatusCode}";
+ if (!string.IsNullOrEmpty(Detail))
+ {
+ text += $@", Detail = ""{Detail}""";
+ }
+ if (DebugException != null)
+ {
+ text += $@", DebugException = ""{DebugException.GetType()}: {DebugException.Message}""";
+ }
+
+ return text;
+ }
}
diff --git a/src/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/Grpc.HealthCheck/Grpc.HealthCheck.csproj
index c6a40f099..d3e02fc34 100755
--- a/src/Grpc.HealthCheck/Grpc.HealthCheck.csproj
+++ b/src/Grpc.HealthCheck/Grpc.HealthCheck.csproj
@@ -5,7 +5,7 @@
true
true
- net462;netstandard1.5;netstandard2.0
+ net462;netstandard2.0
README.md
diff --git a/src/Grpc.Net.Client/Balancer/Internal/SocketConnectivitySubchannelTransport.cs b/src/Grpc.Net.Client/Balancer/Internal/SocketConnectivitySubchannelTransport.cs
index b602843f2..85669a691 100644
--- a/src/Grpc.Net.Client/Balancer/Internal/SocketConnectivitySubchannelTransport.cs
+++ b/src/Grpc.Net.Client/Balancer/Internal/SocketConnectivitySubchannelTransport.cs
@@ -190,6 +190,9 @@ public async ValueTask TryConnectAsync(ConnectContext context)
}
catch (Exception ex)
{
+ // Socket is recreated every connect attempt. Explicitly dispose failed socket before next attempt.
+ socket.Dispose();
+
SocketConnectivitySubchannelTransportLog.ErrorConnectingSocket(_logger, _subchannel.Id, currentEndPoint, ex);
if (firstConnectionError == null)
diff --git a/src/Grpc.Net.Client/GrpcChannel.cs b/src/Grpc.Net.Client/GrpcChannel.cs
index 71adcda91..47a782ad0 100644
--- a/src/Grpc.Net.Client/GrpcChannel.cs
+++ b/src/Grpc.Net.Client/GrpcChannel.cs
@@ -266,17 +266,9 @@ private static HttpHandlerContext CalculateHandlerContext(ILogger logger, Uri ad
}
if (HttpRequestHelpers.HasHttpHandlerType(channelOptions.HttpHandler, "System.Net.Http.SocketsHttpHandler"))
{
- HttpHandlerType type;
- TimeSpan? connectTimeout;
- TimeSpan? connectionIdleTimeout;
-
#if NET5_0_OR_GREATER
var socketsHttpHandler = HttpRequestHelpers.GetHttpHandlerType(channelOptions.HttpHandler)!;
- type = HttpHandlerType.SocketsHttpHandler;
- connectTimeout = socketsHttpHandler.ConnectTimeout;
- connectionIdleTimeout = GetConnectionIdleTimeout(socketsHttpHandler);
-
// Check if the SocketsHttpHandler is being shared by channels.
// It has already been setup by another channel (i.e. ConnectCallback is set) then
// additional channels can use advanced connectivity features.
@@ -286,33 +278,34 @@ private static HttpHandlerContext CalculateHandlerContext(ILogger logger, Uri ad
// This channel can't support advanced connectivity features.
if (socketsHttpHandler.ConnectCallback != null)
{
- type = HttpHandlerType.Custom;
- connectTimeout = null;
- connectionIdleTimeout = null;
+ return new HttpHandlerContext(HttpHandlerType.Custom);
}
}
+ // Load balancing has been disabled on the SocketsHttpHandler.
+ if (socketsHttpHandler.Properties.TryGetValue("__GrpcLoadBalancingDisabled", out var value)
+ && value is bool loadBalancingDisabled && loadBalancingDisabled)
+ {
+ return new HttpHandlerContext(HttpHandlerType.Custom);
+ }
+
// If a proxy is specified then requests could be sent via an SSL tunnel.
// A CONNECT request is made to the proxy to establish the transport stream and then
// gRPC calls are sent via stream. This feature isn't supported by load balancer.
// Proxy can be specified via:
// - SocketsHttpHandler.Proxy. Set via app code.
// - HttpClient.DefaultProxy. Set via environment variables, e.g. HTTPS_PROXY.
- if (type == HttpHandlerType.SocketsHttpHandler)
+ if (IsProxied(socketsHttpHandler, address, isSecure))
{
- if (IsProxied(socketsHttpHandler, address, isSecure))
- {
- logger.LogInformation("Proxy configuration is detected. How the gRPC client creates connections can cause unexpected behavior when a proxy is configured. " +
- "To ensure the client correctly uses a proxy, configure GrpcChannelOptions.HttpHandler to use HttpClientHandler. " +
- "Note that HttpClientHandler isn't compatible with load balancing.");
- }
+ logger.LogInformation("Proxy configuration is detected. How the gRPC client creates connections can cause unexpected behavior when a proxy is configured. " +
+ "To ensure the client correctly uses a proxy, configure GrpcChannelOptions.HttpHandler to use HttpClientHandler. " +
+ "Note that HttpClientHandler isn't compatible with load balancing.");
}
+
+ return new HttpHandlerContext(HttpHandlerType.SocketsHttpHandler, socketsHttpHandler.ConnectTimeout, GetConnectionIdleTimeout(socketsHttpHandler));
#else
- type = HttpHandlerType.SocketsHttpHandler;
- connectTimeout = null;
- connectionIdleTimeout = null;
+ return new HttpHandlerContext(HttpHandlerType.SocketsHttpHandler);
#endif
- return new HttpHandlerContext(type, connectTimeout, connectionIdleTimeout);
}
if (HttpRequestHelpers.GetHttpHandlerType(channelOptions.HttpHandler) != null)
{
diff --git a/src/Grpc.Reflection/Grpc.Reflection.csproj b/src/Grpc.Reflection/Grpc.Reflection.csproj
index 0a52e1642..63b23d665 100755
--- a/src/Grpc.Reflection/Grpc.Reflection.csproj
+++ b/src/Grpc.Reflection/Grpc.Reflection.csproj
@@ -5,7 +5,7 @@
true
true
- net462;netstandard1.5;netstandard2.0
+ net462;netstandard2.0
README.md
diff --git a/src/Shared/HttpRequestHelpers.cs b/src/Shared/HttpRequestHelpers.cs
index 2f75e9c68..a08accd5e 100644
--- a/src/Shared/HttpRequestHelpers.cs
+++ b/src/Shared/HttpRequestHelpers.cs
@@ -1,4 +1,4 @@
-#region Copyright notice and license
+#region Copyright notice and license
// Copyright 2019 The gRPC Authors
//
@@ -53,7 +53,7 @@ public static bool HasHttpHandlerType(HttpMessageHandler handler, string handler
public static HttpMessageHandler? GetHttpHandlerType(HttpMessageHandler handler, string handlerTypeName)
{
- if (handler?.GetType().FullName == handlerTypeName)
+ if (IsType(handler.GetType(), handlerTypeName))
{
return handler;
}
@@ -62,8 +62,7 @@ public static bool HasHttpHandlerType(HttpMessageHandler handler, string handler
while (currentHandler is DelegatingHandler delegatingHandler)
{
currentHandler = delegatingHandler.InnerHandler;
-
- if (currentHandler?.GetType().FullName == handlerTypeName)
+ if (currentHandler != null && IsType(currentHandler.GetType(), handlerTypeName))
{
return currentHandler;
}
@@ -72,6 +71,21 @@ public static bool HasHttpHandlerType(HttpMessageHandler handler, string handler
return null;
}
+ private static bool IsType(Type type, string handlerTypeName)
+ {
+ Type? currentType = type;
+ do
+ {
+ if (currentType.FullName == handlerTypeName)
+ {
+ return true;
+ }
+
+ } while ((currentType = currentType.BaseType) != null);
+
+ return false;
+ }
+
public static bool HasHttpHandlerType(HttpMessageHandler handler) where T : HttpMessageHandler
{
return GetHttpHandlerType(handler) != null;
diff --git a/test/Grpc.AspNetCore.Server.Tests/DuplexStreamingServerCallHandlerTests.cs b/test/Grpc.AspNetCore.Server.Tests/DuplexStreamingServerCallHandlerTests.cs
new file mode 100644
index 000000000..c2bd64e12
--- /dev/null
+++ b/test/Grpc.AspNetCore.Server.Tests/DuplexStreamingServerCallHandlerTests.cs
@@ -0,0 +1,67 @@
+#region Copyright notice and license
+
+// Copyright 2019 The gRPC Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using Grpc.AspNetCore.Server.Internal.CallHandlers;
+using Grpc.AspNetCore.Server.Tests.TestObjects;
+using Grpc.Core;
+using Grpc.Shared.Server;
+using Grpc.Tests.Shared;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.Extensions.Logging.Abstractions;
+using NUnit.Framework;
+
+namespace Grpc.AspNetCore.Server.Tests;
+
+[TestFixture]
+public class DuplexStreamingServerCallHandlerTests
+{
+ private static readonly Marshaller _marshaller = new Marshaller((message, context) => { context.Complete(Array.Empty()); }, context => new TestMessage());
+
+ [Test]
+ public async Task HandleCallAsync_ConcurrentReadAndWrite_Success()
+ {
+ // Arrange
+ var invoker = new DuplexStreamingServerMethodInvoker(
+ (service, reader, writer, context) =>
+ {
+ var message = new TestMessage();
+ var readTask = Task.Run(() => reader.MoveNext());
+ var writeTask = Task.Run(() => writer.WriteAsync(message));
+ return Task.WhenAll(readTask, writeTask);
+ },
+ new Method(MethodType.DuplexStreaming, "test", "test", _marshaller, _marshaller),
+ HttpContextServerCallContextHelper.CreateMethodOptions(),
+ new TestGrpcServiceActivator());
+ var handler = new DuplexStreamingServerCallHandler(invoker, NullLoggerFactory.Instance);
+
+ // Verify there isn't a race condition when reading/writing on seperate threads.
+ // This test primarily exists to ensure that the stream reader and stream writer aren't accessing non-thread safe APIs on HttpContext.
+ for (var i = 0; i < 10_000; i++)
+ {
+ var httpContext = HttpContextHelpers.CreateContext();
+
+ // Act
+ await handler.HandleCallAsync(httpContext);
+
+ // Assert
+ var trailers = httpContext.Features.Get()!.Trailers;
+ Assert.AreEqual("0", trailers["grpc-status"].ToString());
+ }
+ }
+}
diff --git a/test/Grpc.Net.Client.Tests/GrpcChannelTests.cs b/test/Grpc.Net.Client.Tests/GrpcChannelTests.cs
index c2c3f2aa3..15a9abb12 100644
--- a/test/Grpc.Net.Client.Tests/GrpcChannelTests.cs
+++ b/test/Grpc.Net.Client.Tests/GrpcChannelTests.cs
@@ -649,8 +649,11 @@ public void WinHttpHandler_UnsupportedWindows_Throw()
"For more information, see https://aka.ms/aspnet/grpc/netframework.");
}
- [Test]
- public void WinHttpHandler_SupportedWindows_Success()
+#pragma warning disable CS0436 // Just need to have a type called WinHttpHandler to activate new behavior.
+ [TestCase(typeof(WinHttpHandler))]
+#pragma warning restore CS0436
+ [TestCase(typeof(WinHttpHandlerInherited))]
+ public void WinHttpHandler_SupportedWindows_Success(Type handlerType)
{
// Arrange
var services = new ServiceCollection();
@@ -660,9 +663,7 @@ public void WinHttpHandler_SupportedWindows_Success()
OSVersion = Version.Parse("10.0.20348.169")
});
-#pragma warning disable CS0436 // Just need to have a type called WinHttpHandler to activate new behavior.
- var winHttpHandler = new WinHttpHandler(new TestHttpMessageHandler());
-#pragma warning restore CS0436
+ var winHttpHandler = (HttpMessageHandler)Activator.CreateInstance(handlerType, new TestHttpMessageHandler())!;
// Act
var channel = GrpcChannel.ForAddress("https://localhost", new GrpcChannelOptions
@@ -675,6 +676,15 @@ public void WinHttpHandler_SupportedWindows_Success()
Assert.AreEqual(HttpHandlerType.WinHttpHandler, channel.HttpHandlerType);
}
+#pragma warning disable CS0436 // Just need to have a type called WinHttpHandler to activate new behavior.
+ private class WinHttpHandlerInherited : WinHttpHandler
+ {
+ public WinHttpHandlerInherited(HttpMessageHandler innerHandler) : base(innerHandler)
+ {
+ }
+ }
+#pragma warning restore CS0436
+
#if SUPPORT_LOAD_BALANCING
[Test]
public void Resolver_SocketHttpHandlerWithConnectCallback_Error()