Basic implementation of temporary HttpClient. Currently only supports GET requests and doesn't return HTTP headers.
This commit is contained in:
parent
8e57261167
commit
891f2a14d0
|
|
@ -0,0 +1,28 @@
|
||||||
|
@using Microsoft.AspNetCore.Blazor.Browser.Services.Temporary
|
||||||
|
@inject HttpClient Http
|
||||||
|
|
||||||
|
<h1>Fetch data</h1>
|
||||||
|
|
||||||
|
<strong>Response: </strong> @responseText
|
||||||
|
|
||||||
|
@functions {
|
||||||
|
private string responseText;
|
||||||
|
|
||||||
|
// TODO: Move to OnInitAsync
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
Http.GetStringAsync("/").ContinueWith(task =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
responseText = task.Result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine(ex.InnerException.Message);
|
||||||
|
Console.Error.WriteLine(ex.InnerException.StackTrace);
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,6 +23,11 @@
|
||||||
<span class='glyphicon glyphicon-education'></span> Counter
|
<span class='glyphicon glyphicon-education'></span> Counter
|
||||||
</c:NavLink>
|
</c:NavLink>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<c:NavLink href=@("/fetchdata")>
|
||||||
|
<span class='glyphicon glyphicon-th-list'></span> Fetch data
|
||||||
|
</c:NavLink>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { platform } from './Environment';
|
import { platform } from './Environment';
|
||||||
import { getAssemblyNameFromUrl } from './Platform/DotNet';
|
import { getAssemblyNameFromUrl } from './Platform/DotNet';
|
||||||
import './Rendering/Renderer';
|
import './Rendering/Renderer';
|
||||||
import './Routing/UriHelper';
|
import './Services/Http';
|
||||||
|
import './Services/UriHelper';
|
||||||
import './GlobalExports';
|
import './GlobalExports';
|
||||||
|
|
||||||
async function boot() {
|
async function boot() {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
export interface Platform {
|
export interface Platform {
|
||||||
start(loadAssemblyUrls: string[]): Promise<void>;
|
start(loadAssemblyUrls: string[]): Promise<void>;
|
||||||
|
|
||||||
callEntryPoint(assemblyName: string, entrypointMethod: string, args: System_Object[]);
|
callEntryPoint(assemblyName: string, entrypointMethod: string, args: (System_Object | null)[]);
|
||||||
findMethod(assemblyName: string, namespace: string, className: string, methodName: string): MethodHandle;
|
findMethod(assemblyName: string, namespace: string, className: string, methodName: string): MethodHandle;
|
||||||
callMethod(method: MethodHandle, target: System_Object | null, args: System_Object[]): System_Object;
|
callMethod(method: MethodHandle, target: System_Object | null, args: (System_Object | null)[]): System_Object;
|
||||||
|
|
||||||
toJavaScriptString(dotNetString: System_String): string;
|
toJavaScriptString(dotNetString: System_String): string;
|
||||||
toDotNetString(javaScriptString: string): System_String;
|
toDotNetString(javaScriptString: string): System_String;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { registerFunction } from '../Interop/RegisteredFunction';
|
||||||
|
import { platform } from '../Environment';
|
||||||
|
import { MethodHandle } from '../Platform/Platform';
|
||||||
|
const httpClientAssembly = 'Microsoft.AspNetCore.Blazor.Browser';
|
||||||
|
const httpClientNamespace = `${httpClientAssembly}.Services.Temporary`;
|
||||||
|
const httpClientTypeName = 'HttpClient';
|
||||||
|
const httpClientFullTypeName = `${httpClientNamespace}.${httpClientTypeName}`;
|
||||||
|
let receiveResponseMethod: MethodHandle;
|
||||||
|
|
||||||
|
registerFunction(`${httpClientFullTypeName}.Send`, (id: number, requestUri: string) => {
|
||||||
|
sendAsync(id, requestUri);
|
||||||
|
});
|
||||||
|
|
||||||
|
async function sendAsync(id: number, requestUri: string) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(requestUri);
|
||||||
|
const responseText = await response.text();
|
||||||
|
dispatchResponse(id, response.status, responseText, null);
|
||||||
|
} catch (ex) {
|
||||||
|
dispatchResponse(id, 0, null, ex.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dispatchResponse(id: number, statusCode: number, responseText: string | null, errorInfo: string | null) {
|
||||||
|
if (!receiveResponseMethod) {
|
||||||
|
receiveResponseMethod = platform.findMethod(
|
||||||
|
httpClientAssembly,
|
||||||
|
httpClientNamespace,
|
||||||
|
httpClientTypeName,
|
||||||
|
'ReceiveResponse'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
platform.callMethod(receiveResponseMethod, null, [
|
||||||
|
platform.toDotNetString(id.toString()),
|
||||||
|
platform.toDotNetString(statusCode.toString()),
|
||||||
|
responseText === null ? null : platform.toDotNetString(responseText),
|
||||||
|
errorInfo === null ? null : platform.toDotNetString(errorInfo.toString())
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Blazor.Browser.Services.Temporary;
|
||||||
using Microsoft.AspNetCore.Blazor.Services;
|
using Microsoft.AspNetCore.Blazor.Services;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -41,6 +42,7 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Services
|
||||||
private void AddDefaultServices(ServiceCollection serviceCollection)
|
private void AddDefaultServices(ServiceCollection serviceCollection)
|
||||||
{
|
{
|
||||||
serviceCollection.AddSingleton<IUriHelper>(new BrowserUriHelper());
|
serviceCollection.AddSingleton<IUriHelper>(new BrowserUriHelper());
|
||||||
|
serviceCollection.AddSingleton(new HttpClient());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Blazor.Browser.Interop;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Blazor.Browser.Services.Temporary
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides mechanisms for sending HTTP requests.
|
||||||
|
///
|
||||||
|
/// This is intended to serve as an equivalent to <see cref="System.Net.Http.HttpClient"/>
|
||||||
|
/// until we're able to use the real <see cref="System.Net.Http.HttpClient"/> inside Mono
|
||||||
|
/// for WebAssembly.
|
||||||
|
/// </summary>
|
||||||
|
public class HttpClient
|
||||||
|
{
|
||||||
|
static object _idLock = new object();
|
||||||
|
static int _nextRequestId = 0;
|
||||||
|
static IDictionary<int, TaskCompletionSource<HttpResponseMessage>> _pendingRequests
|
||||||
|
= new Dictionary<int, TaskCompletionSource<HttpResponseMessage>>();
|
||||||
|
|
||||||
|
// Making the constructor internal to be sure people only get instances from
|
||||||
|
// the service provider. It doesn't make any difference right now, but when
|
||||||
|
// we switch to System.Net.Http.HttpClient, there may be a period where it
|
||||||
|
// only works when you get an instance from the service provider because it
|
||||||
|
// has to be configured with a browser-specific HTTP handler. In the long
|
||||||
|
// term, it should be possible to use System.Net.Http.HttpClient directly
|
||||||
|
// without any browser-specific constructor args.
|
||||||
|
internal HttpClient()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a GET request to the specified URI and returns the response body as
|
||||||
|
/// a string in an asynchronous operation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="requestUri">The URI the request is sent to.</param>
|
||||||
|
/// <returns>A task representing the asynchronous operation.</returns>
|
||||||
|
public async Task<string> GetStringAsync(string requestUri)
|
||||||
|
{
|
||||||
|
var response = await GetAsync(requestUri);
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
throw new HttpRequestException($"The response status code was {response.StatusCode}");
|
||||||
|
}
|
||||||
|
return await response.Content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// <summary>
|
||||||
|
/// Sends a GET request to the specified URI and returns the response as
|
||||||
|
/// an instance of <see cref="HttpResponseMessage"/> in an asynchronous
|
||||||
|
/// operation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="requestUri">The URI the request is sent to.</param>
|
||||||
|
/// <returns>A task representing the asynchronous operation.</returns>
|
||||||
|
public Task<HttpResponseMessage> GetAsync(string requestUri)
|
||||||
|
{
|
||||||
|
var tcs = new TaskCompletionSource<HttpResponseMessage>();
|
||||||
|
int id;
|
||||||
|
lock (_idLock)
|
||||||
|
{
|
||||||
|
id = _nextRequestId++;
|
||||||
|
_pendingRequests.Add(id, tcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisteredFunction.Invoke<object>($"{typeof(HttpClient).FullName}.Send", id, requestUri);
|
||||||
|
|
||||||
|
return tcs.Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ReceiveResponse(string id, string statusCode, string responseText, string errorText)
|
||||||
|
{
|
||||||
|
TaskCompletionSource<HttpResponseMessage> tcs;
|
||||||
|
var idVal = int.Parse(id);
|
||||||
|
lock (_idLock)
|
||||||
|
{
|
||||||
|
tcs = _pendingRequests[idVal];
|
||||||
|
_pendingRequests.Remove(idVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorText == null)
|
||||||
|
{
|
||||||
|
tcs.SetResult(new HttpResponseMessage
|
||||||
|
{
|
||||||
|
StatusCode = (HttpStatusCode)int.Parse(statusCode),
|
||||||
|
Content = new StringContent(responseText)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tcs.SetException(new HttpRequestException(errorText));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue