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
|
||||
</c:NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<c:NavLink href=@("/fetchdata")>
|
||||
<span class='glyphicon glyphicon-th-list'></span> Fetch data
|
||||
</c:NavLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { platform } from './Environment';
|
||||
import { getAssemblyNameFromUrl } from './Platform/DotNet';
|
||||
import './Rendering/Renderer';
|
||||
import './Routing/UriHelper';
|
||||
import './Services/Http';
|
||||
import './Services/UriHelper';
|
||||
import './GlobalExports';
|
||||
|
||||
async function boot() {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
export interface Platform {
|
||||
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;
|
||||
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;
|
||||
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.
|
||||
// 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.Extensions.DependencyInjection;
|
||||
using System;
|
||||
|
|
@ -41,6 +42,7 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Services
|
|||
private void AddDefaultServices(ServiceCollection serviceCollection)
|
||||
{
|
||||
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