aspnetcore/src/Microsoft.AspNetCore.Compon.../src/Services/Http.ts

115 lines
3.6 KiB
TypeScript

import { platform } from '../Environment';
import { MethodHandle, System_String, System_Array } from '../Platform/Platform';
const httpClientAssembly = 'Microsoft.AspNetCore.Components.Browser';
const httpClientNamespace = `${httpClientAssembly}.Http`;
const httpClientTypeName = 'BrowserHttpMessageHandler';
const httpClientFullTypeName = `${httpClientNamespace}.${httpClientTypeName}`;
let receiveResponseMethod: MethodHandle;
let allocateArrayMethod: MethodHandle;
// These are the functions we're making available for invocation from .NET
export const internalFunctions = {
sendAsync
}
async function sendAsync(id: number, body: System_Array<any>, jsonFetchArgs: System_String) {
let response: Response;
let responseData: ArrayBuffer;
const fetchOptions: FetchOptions = JSON.parse(platform.toJavaScriptString(jsonFetchArgs));
const requestInit: RequestInit = Object.assign(fetchOptions.requestInit, fetchOptions.requestInitOverrides);
if (body) {
requestInit.body = platform.toUint8Array(body);
}
try {
response = await fetch(fetchOptions.requestUri, requestInit);
responseData = await response.arrayBuffer();
} catch (ex) {
dispatchErrorResponse(id, ex.toString());
return;
}
dispatchSuccessResponse(id, response, responseData);
}
function dispatchSuccessResponse(id: number, response: Response, responseData: ArrayBuffer) {
const responseDescriptor: ResponseDescriptor = {
statusCode: response.status,
statusText: response.statusText,
headers: []
};
response.headers.forEach((value, name) => {
responseDescriptor.headers.push([name, value]);
});
if (!allocateArrayMethod) {
allocateArrayMethod = platform.findMethod(
httpClientAssembly,
httpClientNamespace,
httpClientTypeName,
'AllocateArray'
);
}
// allocate a managed byte[] of the right size
const dotNetArray = platform.callMethod(allocateArrayMethod, null, [platform.toDotNetString(responseData.byteLength.toString())]) as System_Array<any>;
// get an Uint8Array view of it
const array = platform.toUint8Array(dotNetArray);
// copy the responseData to our managed byte[]
array.set(new Uint8Array(responseData));
dispatchResponse(
id,
platform.toDotNetString(JSON.stringify(responseDescriptor)),
dotNetArray,
/* errorMessage */ null
);
}
function dispatchErrorResponse(id: number, errorMessage: string) {
dispatchResponse(
id,
/* responseDescriptor */ null,
/* responseText */ null,
platform.toDotNetString(errorMessage)
);
}
function dispatchResponse(id: number, responseDescriptor: System_String | null, responseData: System_Array<any> | null, errorMessage: System_String | null) {
if (!receiveResponseMethod) {
receiveResponseMethod = platform.findMethod(
httpClientAssembly,
httpClientNamespace,
httpClientTypeName,
'ReceiveResponse'
);
}
platform.callMethod(receiveResponseMethod, null, [
platform.toDotNetString(id.toString()),
responseDescriptor,
responseData,
errorMessage,
]);
}
// Keep these in sync with the .NET equivalent in BrowserHttpMessageHandler.cs
interface FetchOptions {
requestUri: string;
requestInit: RequestInit;
requestInitOverrides: RequestInit;
}
interface ResponseDescriptor {
// We don't have BodyText in here because if we did, then in the JSON-response case (which
// is the most common case), we'd be double-encoding it, since the entire ResponseDescriptor
// also gets JSON encoded. It would work but is twice the amount of string processing.
statusCode: number;
statusText: string;
headers: string[][];
}