Convert the static UriHelper into a service, IUriHelper, and inject where needed

This commit is contained in:
Steve Sanderson 2018-02-23 10:35:28 +00:00
parent 68f6ede3a7
commit 82bcf9172a
8 changed files with 103 additions and 60 deletions

View File

@ -34,7 +34,7 @@ export const monoPlatform: Platform = {
const typeHandle = find_class(assemblyHandle, namespace, className);
if (!typeHandle) {
throw new Error(`Could not find type "${className}'" in namespace "${namespace}" in assembly "${assemblyName}"`);
throw new Error(`Could not find type "${className}" in namespace "${namespace}" in assembly "${assemblyName}"`);
}
const methodHandle = find_method(typeHandle, methodName, -1);

View File

@ -1,7 +1,7 @@
import { registerFunction } from '../Interop/RegisteredFunction';
import { platform } from '../Environment';
import { MethodHandle } from '../Platform/Platform';
const registeredFunctionPrefix = 'Microsoft.AspNetCore.Blazor.Browser.Routing.UriHelper';
const registeredFunctionPrefix = 'Microsoft.AspNetCore.Blazor.Browser.Services.BrowserUriHelper';
let notifyLocationChangedMethod: MethodHandle;
let hasRegisteredEventListeners = false;
@ -37,8 +37,8 @@ function handleInternalNavigation() {
if (!notifyLocationChangedMethod) {
notifyLocationChangedMethod = platform.findMethod(
'Microsoft.AspNetCore.Blazor.Browser',
'Microsoft.AspNetCore.Blazor.Browser.Routing',
'UriHelper',
'Microsoft.AspNetCore.Blazor.Browser.Services',
'BrowserUriHelper',
'NotifyLocationChanged'
);
}

View File

@ -7,6 +7,7 @@ using System.Reflection;
using Microsoft.AspNetCore.Blazor.Components;
using Microsoft.AspNetCore.Blazor.Layouts;
using Microsoft.AspNetCore.Blazor.RenderTree;
using Microsoft.AspNetCore.Blazor.Services;
namespace Microsoft.AspNetCore.Blazor.Browser.Routing
{
@ -22,6 +23,8 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Routing
string _baseUriPrefix;
string _locationAbsolute;
[Inject] private IUriHelper UriHelper { get; set; }
/// <summary>
/// Gets or sets the assembly that should be searched, along with its referenced
/// assemblies, for components matching the URI.

View File

@ -3,6 +3,7 @@
using Microsoft.AspNetCore.Blazor.Components;
using Microsoft.AspNetCore.Blazor.RenderTree;
using Microsoft.AspNetCore.Blazor.Services;
using System;
using System.Collections.Generic;
using System.Linq;
@ -32,6 +33,8 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Routing
private string _hrefAbsolute;
private IReadOnlyDictionary<string, object> _allAttributes;
[Inject] private IUriHelper UriHelper { get; set; }
public void Init(RenderHandle renderHandle)
{
_renderHandle = renderHandle;

View File

@ -2,28 +2,31 @@
// 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 Microsoft.AspNetCore.Blazor.Services;
using System;
namespace Microsoft.AspNetCore.Blazor.Browser.Routing
namespace Microsoft.AspNetCore.Blazor.Browser.Services
{
// TODO: Make this not static, and wrap it in an interface that can be injected through DI.
/// <summary>
/// Helpers for working with URIs and navigation state.
/// Default browser implementation of <see cref="IUriHelper"/>.
/// </summary>
public static class UriHelper
public class BrowserUriHelper : IUriHelper
{
static readonly string _functionPrefix = typeof(UriHelper).FullName;
// Since there's only one browser (and hence only one navigation state), the internal state
// is all static. In typical usage the DI system will register BrowserUriHelper as a singleton
// so it makes no difference, but if you manually instantiate more than one BrowserUriHelper
// that's fine too - they will just share their internal state.
// This class will never be used during server-side prerendering, so we don't have thread-
// safety concerns due to the static state.
static readonly string _functionPrefix = typeof(BrowserUriHelper).FullName;
static bool _hasEnabledNavigationInterception;
static string _currentAbsoluteUri;
static EventHandler<string> _onLocationChanged;
static string _baseUriString;
static Uri _baseUri;
static EventHandler<string> _onLocationChanged;
static bool _hasEnabledNavigationInterception;
/// <summary>
/// An event that fires when the navigation location has changed.
/// </summary>
public static event EventHandler<string> OnLocationChanged
/// <inheritdoc />
public event EventHandler<string> OnLocationChanged
{
add
{
@ -38,63 +41,34 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Routing
}
}
/// <summary>
/// Gets the URI prefix that can be prepended before URI paths to produce an absolute URI.
/// Typically this corresponds to the 'href' attribute on the document's &lt;base&gt; element.
/// </summary>
/// <returns>The URI prefix.</returns>
public static string GetBaseUriPrefix()
/// <inheritdoc />
public string GetBaseUriPrefix()
{
EnsureBaseUriPopulated();
return _baseUriString;
}
private static void EnsureBaseUriPopulated()
{
// The <base href> is fixed for the lifetime of the page, so just cache it
if (_baseUriString == null)
{
var baseUri = RegisteredFunction.InvokeUnmarshalled<string>(
$"{_functionPrefix}.getBaseURI");
_baseUriString = ToBaseUriPrefix(baseUri);
_baseUri = new Uri(_baseUriString);
}
}
/// <summary>
/// Gets the browser's current absolute URI.
/// </summary>
/// <returns>The browser's current absolute URI.</returns>
public static string GetAbsoluteUri()
/// <inheritdoc />
public string GetAbsoluteUri()
{
if (_currentAbsoluteUri == null)
{
_currentAbsoluteUri = RegisteredFunction.InvokeUnmarshalled<string>(
$"{_functionPrefix}.getLocationHref");
$"{_functionPrefix}.getLocationHref");
}
return _currentAbsoluteUri;
}
/// <summary>
/// Converts a relative URI into an absolute one.
/// </summary>
/// <param name="relativeUri">The relative URI.</param>
/// <returns>The absolute URI.</returns>
public static Uri ToAbsoluteUri(string relativeUri)
/// <inheritdoc />
public Uri ToAbsoluteUri(string relativeUri)
{
EnsureBaseUriPopulated();
return new Uri(_baseUri, relativeUri);
}
/// <summary>
/// Given a base URI prefix (e.g., one previously returned by <see cref="GetBaseUriPrefix"/>),
/// converts an absolute URI into one relative to the base URI prefix.
/// </summary>
/// <param name="baseUriPrefix">The base URI prefix (e.g., previously returned by <see cref="GetBaseUriPrefix"/>).</param>
/// <param name="absoluteUri">An absolute URI that is within the space of the base URI prefix.</param>
/// <returns>A relative URI path.</returns>
public static string ToBaseRelativePath(string baseUriPrefix, string absoluteUri)
/// <inheritdoc />
public string ToBaseRelativePath(string baseUriPrefix, string absoluteUri)
{
if (absoluteUri.Equals(baseUriPrefix, StringComparison.Ordinal))
{
@ -117,6 +91,18 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Routing
throw new ArgumentException($"The URI '{absoluteUri}' is not contained by the base URI '{baseUriPrefix}'.");
}
private static void EnsureBaseUriPopulated()
{
// The <base href> is fixed for the lifetime of the page, so just cache it
if (_baseUriString == null)
{
var baseUri = RegisteredFunction.InvokeUnmarshalled<string>(
$"{_functionPrefix}.getBaseURI");
_baseUriString = ToBaseUriPrefix(baseUri);
_baseUri = new Uri(_baseUriString);
}
}
private static void NotifyLocationChanged(string newAbsoluteUri)
{
_currentAbsoluteUri = newAbsoluteUri;

View File

@ -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.Services;
using Microsoft.Extensions.DependencyInjection;
using System;
@ -39,7 +40,7 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Services
private void AddDefaultServices(ServiceCollection serviceCollection)
{
// TODO: Add default services for HttpClient, IUrlHelper, etc.
serviceCollection.AddSingleton<IUriHelper>(new BrowserUriHelper());
}
}
}

View File

@ -0,0 +1,48 @@
// 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 System;
namespace Microsoft.AspNetCore.Blazor.Services
{
/// <summary>
/// Helpers for working with URIs and navigation state.
/// </summary>
public interface IUriHelper
{
/// <summary>
/// Gets the current absolute URI.
/// </summary>
/// <returns>The browser's current absolute URI.</returns>
string GetAbsoluteUri();
/// <summary>
/// An event that fires when the navigation location has changed.
/// </summary>
event EventHandler<string> OnLocationChanged;
/// <summary>
/// Converts a relative URI into an absolute one (by resolving it
/// relative to the current absolute URI).
/// </summary>
/// <param name="relativeUri">The relative URI.</param>
/// <returns>The absolute URI.</returns>
Uri ToAbsoluteUri(string href);
/// <summary>
/// Gets the URI prefix that can be prepended before URI paths to produce an absolute URI.
/// Typically this corresponds to the 'href' attribute on the document's &lt;base&gt; element.
/// </summary>
/// <returns>The URI prefix.</returns>
string GetBaseUriPrefix();
/// <summary>
/// Given a base URI prefix (e.g., one previously returned by <see cref="GetBaseUriPrefix"/>),
/// converts an absolute URI into one relative to the base URI prefix.
/// </summary>
/// <param name="baseUriPrefix">The base URI prefix (e.g., previously returned by <see cref="GetBaseUriPrefix"/>).</param>
/// <param name="absoluteUri">An absolute URI that is within the space of the base URI prefix.</param>
/// <returns>A relative URI path.</returns>
string ToBaseRelativePath(string baseUriPrefix, string locationAbsolute);
}
}

View File

@ -1,14 +1,16 @@
// 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.Routing;
using Microsoft.AspNetCore.Blazor.Browser.Services;
using System;
using Xunit;
namespace Microsoft.AspNetCore.Blazor.Browser.Test
{
public class UriHelperTest
public class BrowserUriHelperTest
{
private BrowserUriHelper _browserUriHelper = new BrowserUriHelper();
[Theory]
[InlineData("scheme://host/", "scheme://host")]
[InlineData("scheme://host:123/", "scheme://host:123")]
@ -17,7 +19,7 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Test
[InlineData("scheme://host/path/page?query=string&another=here", "scheme://host/path")]
public void ComputesCorrectBaseUriPrefix(string baseUri, string expectedResult)
{
var actualResult = UriHelper.ToBaseUriPrefix(baseUri);
var actualResult = BrowserUriHelper.ToBaseUriPrefix(baseUri);
Assert.Equal(expectedResult, actualResult);
}
@ -29,7 +31,7 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Test
[InlineData("scheme://host/path", "scheme://host/path", "/")]
public void ComputesCorrectValidBaseRelativePaths(string baseUriPrefix, string absoluteUri, string expectedResult)
{
var actualResult = UriHelper.ToBaseRelativePath(baseUriPrefix, absoluteUri);
var actualResult = _browserUriHelper.ToBaseRelativePath(baseUriPrefix, absoluteUri);
Assert.Equal(expectedResult, actualResult);
}
@ -40,7 +42,7 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Test
{
var ex = Assert.Throws<ArgumentException>(() =>
{
UriHelper.ToBaseRelativePath(baseUriPrefix, absoluteUri);
_browserUriHelper.ToBaseRelativePath(baseUriPrefix, absoluteUri);
});
Assert.Equal(