Skip to content

Commit f420ccc

Browse files
Made sure that all types are documented and that IJSWrapper types implement IJSCreatable.
1 parent 71fedbd commit f420ccc

18 files changed

+330
-182
lines changed
Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,48 @@
1-
using Microsoft.JSInterop;
1+
using KristofferStrube.Blazor.WebIDL;
2+
using Microsoft.JSInterop;
23

34
namespace KristofferStrube.Blazor.FileAPI;
45

5-
public abstract class BaseJSWrapper : IAsyncDisposable
6+
/// <summary>
7+
/// A base class for all wrappers in Blazor.FileAPI.
8+
/// </summary>
9+
public abstract class BaseJSWrapper : IJSWrapper
610
{
7-
public readonly IJSObjectReference JSReference;
11+
/// <summary>
12+
/// A lazily loaded task that evaluates to a helper module instance from the Blazor.FileAPI library.
13+
/// </summary>
814
protected readonly Lazy<Task<IJSObjectReference>> helperTask;
9-
protected readonly IJSRuntime jSRuntime;
15+
16+
/// <inheritdoc/>
17+
public IJSRuntime JSRuntime { get; }
18+
/// <inheritdoc/>
19+
public IJSObjectReference JSReference { get; }
20+
/// <inheritdoc/>
21+
public bool DisposesJSReference { get; }
1022

1123
/// <summary>
1224
/// Constructs a wrapper instance for an equivalent JS instance.
1325
/// </summary>
1426
/// <param name="jSRuntime">An <see cref="IJSRuntime"/> instance.</param>
1527
/// <param name="jSReference">A JS reference to an existing JS instance that should be wrapped.</param>
16-
internal BaseJSWrapper(IJSRuntime jSRuntime, IJSObjectReference jSReference)
28+
/// <param name="options">The options for constructing this wrapper.</param>
29+
internal BaseJSWrapper(IJSRuntime jSRuntime, IJSObjectReference jSReference, CreationOptions options)
1730
{
1831
helperTask = new(jSRuntime.GetHelperAsync);
32+
JSRuntime = jSRuntime;
1933
JSReference = jSReference;
20-
this.jSRuntime = jSRuntime;
34+
DisposesJSReference = options.DisposesJSReference;
2135
}
2236

37+
/// <inheritdoc/>
2338
public async ValueTask DisposeAsync()
2439
{
2540
if (helperTask.IsValueCreated)
2641
{
2742
IJSObjectReference module = await helperTask.Value;
2843
await module.DisposeAsync();
2944
}
45+
await IJSWrapper.DisposeJSReference(this);
3046
GC.SuppressFinalize(this);
3147
}
3248
}
Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,34 @@
11
using KristofferStrube.Blazor.Streams;
2+
using KristofferStrube.Blazor.WebIDL;
23
using Microsoft.JSInterop;
34

45
namespace KristofferStrube.Blazor.FileAPI;
56

67
/// <summary>
78
/// <see href="https://www.w3.org/TR/FileAPI/#blob-section">Blob browser specs</see>
89
/// </summary>
9-
public class BlobInProcess : Blob
10+
[IJSWrapperConverter]
11+
public class BlobInProcess : Blob, IJSInProcessCreatable<BlobInProcess, Blob>
1012
{
11-
public new IJSInProcessObjectReference JSReference;
12-
protected readonly IJSInProcessObjectReference inProcessHelper;
13+
/// <inheritdoc />
14+
public new IJSInProcessObjectReference JSReference { get; }
1315

1416
/// <summary>
15-
/// Constructs a wrapper instance for a given JS Instance of a <see cref="Blob"/>.
17+
/// A lazily loaded task that evaluates to a helper module instance from the Blazor.FileAPI library.
1618
/// </summary>
17-
/// <param name="jSRuntime">An <see cref="IJSRuntime"/> instance.</param>
18-
/// <param name="jSReference">A JS reference to an existing <see cref="Blob"/>.</param>
19-
/// <returns>A wrapper instance for a <see cref="Blob"/>.</returns>
19+
protected IJSInProcessObjectReference InProcessHelper { get; }
20+
21+
/// <inheritdoc/>
2022
public static async Task<BlobInProcess> CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference)
23+
{
24+
return await CreateAsync(jSRuntime, jSReference, new());
25+
}
26+
27+
/// <inheritdoc/>
28+
public static async Task<BlobInProcess> CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference, CreationOptions options)
2129
{
2230
IJSInProcessObjectReference inProcessHelper = await jSRuntime.GetInProcessHelperAsync();
23-
return new BlobInProcess(jSRuntime, inProcessHelper, jSReference);
31+
return new BlobInProcess(jSRuntime, inProcessHelper, jSReference, options);
2432
}
2533

2634
/// <summary>
@@ -41,19 +49,14 @@ public static async Task<BlobInProcess> CreateAsync(IJSRuntime jSRuntime, IJSInP
4149
})
4250
.ToArray();
4351
IJSInProcessObjectReference jSInstance = await inProcessHelper.InvokeAsync<IJSInProcessObjectReference>("constructBlob", jsBlobParts, options);
44-
return new BlobInProcess(jSRuntime, inProcessHelper, jSInstance);
52+
return new BlobInProcess(jSRuntime, inProcessHelper, jSInstance, new() { DisposesJSReference = true });
4553
}
4654

47-
/// <summary>
48-
/// Constructs a wrapper instance for a given JS Instance of a <see cref="Blob"/>.
49-
/// </summary>
50-
/// <param name="jSRuntime">An <see cref="IJSRuntime"/> instance.</param>
51-
/// <param name="inProcessHelper">An in process helper instance.</param>
52-
/// <param name="jSReference">A JS reference to an existing <see cref="Blob"/>.</param>
53-
internal BlobInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference) : base(jSRuntime, jSReference)
55+
/// <inheritdoc cref="CreateAsync(IJSRuntime, IJSInProcessObjectReference, CreationOptions)"/>
56+
protected internal BlobInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference, CreationOptions options) : base(jSRuntime, jSReference, options)
5457
{
55-
this.inProcessHelper = inProcessHelper;
5658
JSReference = jSReference;
59+
InProcessHelper = inProcessHelper;
5760
}
5861

5962
/// <summary>
@@ -63,20 +66,20 @@ internal BlobInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProce
6366
public new async Task<ReadableStreamInProcess> StreamAsync()
6467
{
6568
IJSInProcessObjectReference jSInstance = JSReference.Invoke<IJSInProcessObjectReference>("stream");
66-
return await ReadableStreamInProcess.CreateAsync(jSRuntime, jSInstance);
69+
return await ReadableStreamInProcess.CreateAsync(JSRuntime, jSInstance);
6770
}
6871

6972
/// <summary>
7073
/// The size of this blob.
7174
/// </summary>
7275
/// <returns>A <see langword="ulong"/> representing the size of the blob in bytes.</returns>
73-
public ulong Size => inProcessHelper.Invoke<ulong>("getAttribute", JSReference, "size");
76+
public ulong Size => InProcessHelper.Invoke<ulong>("getAttribute", JSReference, "size");
7477

7578
/// <summary>
7679
/// The media type of this blob. This is either a parseable MIME type or an empty string.
7780
/// </summary>
7881
/// <returns>The MIME type of this blob.</returns>
79-
public string Type => inProcessHelper.Invoke<string>("getAttribute", JSReference, "type");
82+
public string Type => InProcessHelper.Invoke<string>("getAttribute", JSReference, "type");
8083

8184
/// <summary>
8285
/// Gets some range of the content of a <see cref="Blob"/> as a new <see cref="Blob"/>.
@@ -90,6 +93,6 @@ public BlobInProcess Slice(long? start = null, long? end = null, string? content
9093
start ??= 0;
9194
end ??= (long)Size;
9295
IJSInProcessObjectReference jSInstance = JSReference.Invoke<IJSInProcessObjectReference>("slice", start, end, contentType);
93-
return new BlobInProcess(jSRuntime, inProcessHelper, jSInstance);
96+
return new BlobInProcess(JSRuntime, InProcessHelper, jSInstance, new() { DisposesJSReference = true });
9497
}
9598
}

src/KristofferStrube.Blazor.FileAPI/Blob.cs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,37 @@
11
using KristofferStrube.Blazor.Streams;
2+
using KristofferStrube.Blazor.WebIDL;
23
using Microsoft.JSInterop;
34

45
namespace KristofferStrube.Blazor.FileAPI;
56

67
/// <summary>
78
/// <see href="https://www.w3.org/TR/FileAPI/#blob-section">Blob browser specs</see>
89
/// </summary>
9-
public class Blob : BaseJSWrapper
10+
[IJSWrapperConverter]
11+
public class Blob : BaseJSWrapper, IJSCreatable<Blob>
1012
{
13+
/// <inheritdoc/>
14+
public static async Task<Blob> CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference)
15+
{
16+
return await CreateAsync(jSRuntime, jSReference, new());
17+
}
18+
19+
/// <inheritdoc/>
20+
public static Task<Blob> CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference, CreationOptions options)
21+
{
22+
return Task.FromResult(new Blob(jSRuntime, jSReference, options));
23+
}
24+
1125
/// <summary>
1226
/// Constructs a wrapper instance for a given JS Instance of a <see cref="Blob"/>.
1327
/// </summary>
1428
/// <param name="jSRuntime">An <see cref="IJSRuntime"/> instance.</param>
1529
/// <param name="jSReference">A JS reference to an existing <see cref="Blob"/>.</param>
1630
/// <returns>A wrapper instance for a <see cref="Blob"/>.</returns>
31+
[Obsolete("This will be removed in the next major release as all creator methods should be asynchronous for uniformity. Use CreateAsync instead.")]
1732
public static Blob Create(IJSRuntime jSRuntime, IJSObjectReference jSReference)
1833
{
19-
return new Blob(jSRuntime, jSReference);
34+
return new Blob(jSRuntime, jSReference, new());
2035
}
2136

2237
/// <summary>
@@ -37,15 +52,11 @@ public static async Task<Blob> CreateAsync(IJSRuntime jSRuntime, IList<BlobPart>
3752
})
3853
.ToArray();
3954
IJSObjectReference jSInstance = await helper.InvokeAsync<IJSObjectReference>("constructBlob", jsBlobParts, options);
40-
return new Blob(jSRuntime, jSInstance);
55+
return new Blob(jSRuntime, jSInstance, new() { DisposesJSReference = true });
4156
}
4257

43-
/// <summary>
44-
/// Constructs a wrapper instance for a given JS Instance of a <see cref="Blob"/>.
45-
/// </summary>
46-
/// <param name="jSRuntime">An <see cref="IJSRuntime"/> instance.</param>
47-
/// <param name="jSReference">A JS reference to an existing <see cref="Blob"/>.</param>
48-
internal Blob(IJSRuntime jSRuntime, IJSObjectReference jSReference) : base(jSRuntime, jSReference) { }
58+
/// <inheritdoc cref="CreateAsync(IJSRuntime, IJSObjectReference, CreationOptions)"/>
59+
protected Blob(IJSRuntime jSRuntime, IJSObjectReference jSReference, CreationOptions options) : base(jSRuntime, jSReference, options) { }
4960

5061
/// <summary>
5162
/// The size of this blob.
@@ -79,7 +90,7 @@ public async Task<Blob> SliceAsync(long? start = null, long? end = null, string?
7990
start ??= 0;
8091
end ??= (long)await GetSizeAsync();
8192
IJSObjectReference jSInstance = await JSReference.InvokeAsync<IJSObjectReference>("slice", start, end, contentType);
82-
return new Blob(jSRuntime, jSInstance);
93+
return new Blob(JSRuntime, jSInstance, new() { DisposesJSReference = true });
8394
}
8495

8596
/// <summary>
@@ -89,7 +100,7 @@ public async Task<Blob> SliceAsync(long? start = null, long? end = null, string?
89100
public async Task<ReadableStream> StreamAsync()
90101
{
91102
IJSObjectReference jSInstance = await JSReference.InvokeAsync<IJSObjectReference>("stream");
92-
return await ReadableStream.CreateAsync(jSRuntime, jSInstance);
103+
return await ReadableStream.CreateAsync(JSRuntime, jSInstance);
93104
}
94105

95106
/// <summary>

src/KristofferStrube.Blazor.FileAPI/Converters/DateTimeConverter.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ internal class DateTimeConverter : JsonConverter<DateTime>
77
{
88
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
99
{
10-
if (reader.TryGetUInt64(out ulong jsonValue))
11-
{
12-
return DateTime.UnixEpoch.AddMilliseconds(jsonValue);
13-
}
14-
throw new JsonException($"string {reader.GetString()} could not be parsed as a long.");
10+
return reader.TryGetUInt64(out ulong jsonValue)
11+
? DateTime.UnixEpoch.AddMilliseconds(jsonValue)
12+
: throw new JsonException($"string {reader.GetString()} could not be parsed as a long.");
1513
}
1614

1715
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)

src/KristofferStrube.Blazor.FileAPI/Converters/EnumDescriptionConverter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerial
1717

1818
foreach (FieldInfo? fi in typeToConvert.GetFields())
1919
{
20-
DescriptionAttribute description = (DescriptionAttribute)fi.GetCustomAttribute(typeof(DescriptionAttribute), false);
20+
var description = (DescriptionAttribute)fi.GetCustomAttribute(typeof(DescriptionAttribute), false);
2121

2222
if (description != null)
2323
{
@@ -34,7 +34,7 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions
3434
{
3535
FieldInfo fi = value.GetType().GetField(value.ToString());
3636

37-
DescriptionAttribute description = (DescriptionAttribute)fi.GetCustomAttribute(typeof(DescriptionAttribute), false);
37+
var description = (DescriptionAttribute)fi.GetCustomAttribute(typeof(DescriptionAttribute), false);
3838

3939
writer.WriteStringValue(description.Description);
4040
}

src/KristofferStrube.Blazor.FileAPI/Enums/EndingType.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,23 @@
44
namespace KristofferStrube.Blazor.FileAPI;
55

66
/// <summary>
7-
/// <see href="https://www.w3.org/TR/FileAPI/#enumdef-endingtype">EndingType browser specs</see>
7+
/// It controls how line endings are handled in <see cref="string"/> elements within <see cref="BlobPart"/>s
88
/// </summary>
9+
/// <remarks>
10+
/// <see href="https://www.w3.org/TR/FileAPI/#enumdef-endingtype">EndingType browser specs</see>
11+
/// </remarks>
912
[JsonConverter(typeof(EnumDescriptionConverter<EndingType>))]
1013
public enum EndingType
1114
{
15+
/// <summary>
16+
/// Line endings in <see cref="string"/> elements within <see cref="BlobPart"/>s remain unchanged, with no conversion applied, preserving the original format.
17+
/// </summary>
1218
[Description("transparent")]
1319
Transparent,
20+
21+
/// <summary>
22+
/// Line endings in <see cref="string"/> elements within <see cref="BlobPart"/>s are converted to the platform's native format (<c>\n</c> or <c>\r\n</c>), ensuring consistency with the system's convention.
23+
/// </summary>
1424
[Description("native")]
1525
Native,
1626
}

src/KristofferStrube.Blazor.FileAPI/Extensions/IServiceCollectionExtensions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,24 @@
33

44
namespace KristofferStrube.Blazor.FileAPI;
55

6+
/// <summary>
7+
/// Contains extension methods for adding services to a <see cref="IServiceCollection"/>.
8+
/// </summary>
69
public static class IServiceCollectionExtensions
710
{
11+
/// <summary>
12+
/// Adds an <see cref="IURLService"/> to the service collection.
13+
/// </summary>
14+
/// <param name="serviceCollection">The service collection.</param>
815
public static IServiceCollection AddURLService(this IServiceCollection serviceCollection)
916
{
1017
return serviceCollection.AddScoped<IURLService, URLService>();
1118
}
1219

20+
/// <summary>
21+
/// Adds an <see cref="IURLServiceInProcess"/> to the service collection.
22+
/// </summary>
23+
/// <param name="serviceCollection">The service collection.</param>
1324
public static IServiceCollection AddURLServiceInProcess(this IServiceCollection serviceCollection)
1425
{
1526
return serviceCollection.AddScoped<IURLServiceInProcess>(sp => new URLServiceInProcess((IJSInProcessRuntime)sp.GetRequiredService<IJSRuntime>()));

0 commit comments

Comments
 (0)