Skip to content

Commit 9f19d8b

Browse files
Added more comments to methods and attributes.
1 parent bce3aba commit 9f19d8b

10 files changed

Lines changed: 321 additions & 54 deletions

File tree

samples/KristofferStrube.Blazor.FileAPI.WasmExample/Pages/FileReaderSample.razor

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
In this sample we download an image using the <code>HttpClient</code> and create a new <code>Blob</code> from that.
1111
We then use the methods of the <code>FileReader</code> interface to read the <code>Blob</code> in different ways and convert those different results to an image.
1212
<br />
13-
<div class="px-1 py-1">
13+
<div class="m-1">
1414
<button class="btn btn-primary" @onclick=ReadAsArrayBufferAsync>Read as byte array</button>
15+
<button class="btn btn-primary" @onclick=ReadAsArrayBufferInProcessAsync>Read as byte array InProcess</button>
1516
<button class="btn btn-primary" @onclick=ReadAsBinaryStringAsync>Read as binary string</button>
16-
<button class="btn btn-primary" @onclick=ReadAsTextAsync>Read as text</button>
17+
<button class="btn btn-primary" @onclick=ReadAsText>Read as text</button>
1718
<button class="btn btn-primary" @onclick=ReadAsDataURLAsync>Read as data URL</button>
1819
</div>
1920
<textarea @bind=@log style="height:30vh;width:100%;">
@@ -24,7 +25,7 @@ We then use the methods of the <code>FileReader</code> interface to read the <co
2425
@code {
2526
string log = "";
2627
private string imageUrl = "";
27-
private Blob? blob;
28+
private Blob blob;
2829

2930
protected override async Task OnInitializedAsync()
3031
{
@@ -36,6 +37,14 @@ We then use the methods of the <code>FileReader</code> interface to read the <co
3637
);
3738
}
3839

40+
private void GetProgress(ProgressEventInProcess eventArgs, string prepend)
41+
{
42+
var progress = eventArgs.LengthComputable ? $"({eventArgs.Loaded}/{eventArgs.Total})" : "";
43+
log += $"{prepend}: {progress}\n";
44+
StateHasChanged();
45+
}
46+
47+
3948
private async Task GetProgressAsync(ProgressEvent eventArgs, string prepend)
4049
{
4150
var progress = await eventArgs.GetLengthComputableAsync() ? $"({await eventArgs.GetLoadedAsync()}/{await eventArgs.GetTotalAsync()})" : "";
@@ -47,38 +56,55 @@ We then use the methods of the <code>FileReader</code> interface to read the <co
4756
{
4857
log = "";
4958
var fileReader = await FileReader.CreateAsync(JSRuntime);
50-
fileReader.OnLoadStart = async (e) => GetProgressAsync(e, "OnLoadStart");
51-
fileReader.OnProgress = async (e) => GetProgressAsync(e, "OnProgress");
52-
fileReader.OnLoad = async (e) => GetProgressAsync(e, "OnLoad");
53-
fileReader.OnAbort = async (e) => GetProgressAsync(e, "OnAbort");
54-
fileReader.OnError = async (e) => GetProgressAsync(e, "OnError");
59+
fileReader.OnLoadStart = async (e) => await GetProgressAsync(e, "OnLoadStart");
60+
fileReader.OnProgress = async (e) => await GetProgressAsync(e, "OnProgress");
61+
fileReader.OnLoad = async (e) => await GetProgressAsync(e, "OnLoad");
62+
fileReader.OnAbort = async (e) => await GetProgressAsync(e, "OnAbort");
63+
fileReader.OnError = async (e) => await GetProgressAsync(e, "OnError");
5564
fileReader.OnLoadEnd = async (e) =>
5665
{
57-
imageUrl = "data:image/png;base64," + Convert.ToBase64String(await fileReader.GetResultAsByteArrayAsync());
58-
GetProgressAsync(e, "OnLoadEnd");
66+
imageUrl = "data:image/png;base64," + Convert.ToBase64String(await fileReader.GetResultAsByteArrayAsync() ?? new byte[0]);
67+
await GetProgressAsync(e, "OnLoadEnd");
5968
};
6069
await fileReader.ReadAsArrayBufferAsync(blob);
6170
}
6271

72+
public async Task ReadAsArrayBufferInProcessAsync()
73+
{
74+
log = "";
75+
var fileReader = await FileReaderInProcess.CreateAsync(JSRuntime);
76+
fileReader.OnLoadStart = (e) => GetProgress(e, "OnLoadStart");
77+
fileReader.OnProgress = (e) => GetProgress(e, "OnProgress");
78+
fileReader.OnLoad = (e) => GetProgress(e, "OnLoad");
79+
fileReader.OnAbort = (e) => GetProgress(e, "OnAbort");
80+
fileReader.OnError = (e) => GetProgress(e, "OnError");
81+
fileReader.OnLoadEnd = (e) =>
82+
{
83+
imageUrl = "data:image/png;base64," + Convert.ToBase64String(fileReader.ResultAsByteArray ?? new byte[0]);
84+
GetProgress(e, "OnLoadEnd");
85+
};
86+
fileReader.ReadAsArrayBuffer(blob);
87+
}
88+
6389
public async Task ReadAsBinaryStringAsync()
6490
{
6591
log = "";
6692
var fileReader = await FileReader.CreateAsync(JSRuntime);
67-
fileReader.OnLoadStart = async (e) => GetProgressAsync(e, "OnLoadStart");
68-
fileReader.OnProgress = async (e) => GetProgressAsync(e, "OnProgress");
69-
fileReader.OnLoad = async (e) => GetProgressAsync(e, "OnLoad");
70-
fileReader.OnAbort = async (e) => GetProgressAsync(e, "OnAbort");
71-
fileReader.OnError = async (e) => GetProgressAsync(e, "OnError");
93+
fileReader.OnLoadStart = async (e) => await GetProgressAsync(e, "OnLoadStart");
94+
fileReader.OnProgress = async (e) => await GetProgressAsync(e, "OnProgress");
95+
fileReader.OnLoad = async (e) => await GetProgressAsync(e, "OnLoad");
96+
fileReader.OnAbort = async (e) => await GetProgressAsync(e, "OnAbort");
97+
fileReader.OnError = async (e) => await GetProgressAsync(e, "OnError");
7298
fileReader.OnLoadEnd = async (e) =>
7399
{
74-
var bytes = (await fileReader.GetResultAsStringAsync()).Select(c => (byte)c).ToArray();
100+
var bytes = (await fileReader.GetResultAsStringAsync() ?? "").Select(c => (byte)c).ToArray();
75101
imageUrl = "data:image/png;base64," + Convert.ToBase64String(bytes);
76-
GetProgressAsync(e, "OnLoadEnd");
102+
await GetProgressAsync(e, "OnLoadEnd");
77103
};
78104
await fileReader.ReadAsBinaryStringAsync(blob);
79105
}
80106

81-
public async Task ReadAsTextAsync()
107+
public void ReadAsText()
82108
{
83109
log = "We can't read an image as text. ;)";
84110
imageUrl = "";
@@ -89,15 +115,15 @@ We then use the methods of the <code>FileReader</code> interface to read the <co
89115
{
90116
log = "";
91117
var fileReader = await FileReader.CreateAsync(JSRuntime);
92-
fileReader.OnLoadStart = async (e) => GetProgressAsync(e, "OnLoadStart");
93-
fileReader.OnProgress = async (e) => GetProgressAsync(e, "OnProgress");
94-
fileReader.OnLoad = async (e) => GetProgressAsync(e, "OnLoad");
95-
fileReader.OnAbort = async (e) => GetProgressAsync(e, "OnAbort");
96-
fileReader.OnError = async (e) => GetProgressAsync(e, "OnError");
118+
fileReader.OnLoadStart = async (e) => await GetProgressAsync(e, "OnLoadStart");
119+
fileReader.OnProgress = async (e) => await GetProgressAsync(e, "OnProgress");
120+
fileReader.OnLoad = async (e) => await GetProgressAsync(e, "OnLoad");
121+
fileReader.OnAbort = async (e) => await GetProgressAsync(e, "OnAbort");
122+
fileReader.OnError = async (e) => await GetProgressAsync(e, "OnError");
97123
fileReader.OnLoadEnd = async (e) =>
98124
{
99-
imageUrl = await fileReader.GetResultAsStringAsync();
100-
GetProgressAsync(e, "OnLoadEnd");
125+
imageUrl = await fileReader.GetResultAsStringAsync() ?? "";
126+
await GetProgressAsync(e, "OnLoadEnd");
101127
};
102128
await fileReader.ReadAsDataURLAsync(blob);
103129
}

samples/KristofferStrube.Blazor.FileAPI.WasmExample/Pages/Index.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
@inject IJSRuntime JSRuntime
55
@inject HttpClient HttpClient
6-
@inject URL URL
6+
@inject URLService URL
77

88
<PageTitle>FileAPI - Index</PageTitle>
99

samples/KristofferStrube.Blazor.FileAPI.WasmExample/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99
builder.RootComponents.Add<HeadOutlet>("head::after");
1010

1111
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
12-
builder.Services.AddScoped<URL>();
12+
builder.Services.AddScoped<URLService>();
1313

1414
await builder.Build().RunAsync();
561 KB
Loading
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
using Microsoft.JSInterop;
2+
using System.Text.Json.Serialization;
3+
4+
namespace KristofferStrube.Blazor.FileAPI;
5+
6+
/// <summary>
7+
/// <see href="https://www.w3.org/TR/FileAPI/#dfn-filereader">FileReader browser specs</see>
8+
/// </summary>
9+
public class FileReaderInProcess : FileReader
10+
{
11+
public new IJSInProcessObjectReference JSReference;
12+
protected readonly IJSInProcessObjectReference inProcessHelper;
13+
/// <summary>
14+
/// Constructs a wrapper instance for a given JS Instance of a <see cref="FileReader"/>.
15+
/// </summary>
16+
/// <param name="jSRuntime">An <see cref="IJSRuntime"/> instance.</param>
17+
/// <param name="jSReference">A JS reference to an existing <see cref="FileReader"/>.</param>
18+
/// <returns>A wrapper instance for a <see cref="FileReader"/>.</returns>
19+
public static async Task<FileReaderInProcess> CreateAsync(IJSRuntime jSRuntime, IJSInProcessObjectReference jSReference)
20+
{
21+
IJSInProcessObjectReference inProcesshelper = await jSRuntime.GetInProcessHelperAsync();
22+
return new FileReaderInProcess(jSRuntime, inProcesshelper, jSReference);
23+
}
24+
25+
/// <summary>
26+
/// Constructs a wrapper instance using the standard constructor.
27+
/// </summary>
28+
/// <param name="jSRuntime">An <see cref="IJSRuntime"/> instance.</param>
29+
/// <returns>A wrapper instance for a <see cref="FileReader"/>.</returns>
30+
public static new async Task<FileReaderInProcess> CreateAsync(IJSRuntime jSRuntime)
31+
{
32+
IJSInProcessObjectReference inProcesshelper = await jSRuntime.GetInProcessHelperAsync();
33+
IJSInProcessObjectReference jSInstance = await inProcesshelper.InvokeAsync<IJSInProcessObjectReference>("constructFileReader");
34+
var fileReaderInProcess = new FileReaderInProcess(jSRuntime, inProcesshelper, jSInstance);
35+
await inProcesshelper.InvokeVoidAsync("registerEventHandlers", DotNetObjectReference.Create(fileReaderInProcess), jSInstance);
36+
return fileReaderInProcess;
37+
}
38+
39+
/// <summary>
40+
/// Constructs a wrapper instance for a given JS Instance of a <see cref="File"/>.
41+
/// </summary>
42+
/// <param name="jSRuntime">An <see cref="IJSRuntime"/> instance.</param>
43+
/// <param name="inProcessHelper">An in process helper instance.</param>
44+
/// <param name="jSReference">A JS reference to an existing <see cref="File"/>.</param>
45+
internal FileReaderInProcess(IJSRuntime jSRuntime, IJSInProcessObjectReference inProcessHelper, IJSInProcessObjectReference jSReference) : base(jSRuntime, jSReference)
46+
{
47+
this.inProcessHelper = inProcessHelper;
48+
JSReference = jSReference;
49+
}
50+
51+
/// <summary>
52+
/// Starts a new read for some <see cref="Blob"/> as an <see langword="byte"/>[] which can be read from <see cref="GetResultAsByteArrayAsync"/> once the load has ended which can be checked by setting the action <see cref="OnLoadEnd"/>.
53+
/// </summary>
54+
/// <param name="blob">The <see cref="Blob"/> that should be read asynchronously.</param>
55+
/// <returns></returns>
56+
public void ReadAsArrayBuffer(Blob blob)
57+
{
58+
JSReference.InvokeVoid("readAsArrayBuffer", blob.JSReference);
59+
}
60+
61+
/// <summary>
62+
/// Starts a new read for some <see cref="Blob"/> as a binarily encoded <see langword="string"/> which can be read from <see cref="GetResultAsStringAsync"/> once the load has ended which can be checked by setting the action <see cref="OnLoadEnd"/>.
63+
/// </summary>
64+
/// <param name="blob">The <see cref="Blob"/> that should be read asynchronously.</param>
65+
/// <returns></returns>
66+
public void ReadAsBinaryString(Blob blob)
67+
{
68+
JSReference.InvokeVoid("readAsBinaryString", blob.JSReference);
69+
}
70+
71+
/// <summary>
72+
/// Starts a new read for some <see cref="Blob"/> as a <see langword="string"/> which can be read from <see cref="GetResultAsStringAsync"/> once the load has ended which can be checked by setting the action <see cref="OnLoadEnd"/>.
73+
/// </summary>
74+
/// <param name="blob">The <see cref="Blob"/> that should be read asynchronously.</param>
75+
/// <param name="encoding">An optional encoding for the text. The default is UTF-8.</param>
76+
/// <returns></returns>
77+
public void ReadAsText(Blob blob, string? encoding = null)
78+
{
79+
JSReference.InvokeVoid("readAsText", blob.JSReference, encoding);
80+
}
81+
82+
/// <summary>
83+
/// Starts a new read for some <see cref="Blob"/> as a base64 encoded Data URL which can be read from <see cref="GetResultAsStringAsync"/> once the load has ended which can be checked by setting the action <see cref="OnLoadEnd"/>.
84+
/// </summary>
85+
/// <param name="blob">The <see cref="Blob"/> that should be read asynchronously.</param>
86+
/// <returns></returns>
87+
public void ReadAsDataURL(Blob blob)
88+
{
89+
JSReference.InvokeVoid("readAsDataURL", blob.JSReference);
90+
}
91+
92+
/// <summary>
93+
/// Terminates the load if the <see cref="GetReadyStateAsync"/> is <see cref="LOADING"/> else it sets the result to <see langword="null"/>.
94+
/// </summary>
95+
/// <param name="blob">The <see cref="Blob"/> read that should be terminated.</param>
96+
/// <returns></returns>
97+
public void Abort(Blob blob)
98+
{
99+
JSReference.InvokeVoid("abort", blob.JSReference);
100+
}
101+
102+
/// <summary>
103+
/// Gets the state of the <see cref="FileReader"/>.
104+
/// </summary>
105+
/// <returns>As a standard either <see cref="EMPTY"/>, <see cref="LOADING"/> or <see cref="DONE"/></returns>
106+
public ushort ReadyState => inProcessHelper.Invoke<ushort>("getAttribute", JSReference, "readyState");
107+
108+
/// <summary>
109+
/// Checks whether the result is a either a <see langword="string"/> or a byte array.
110+
/// </summary>
111+
/// <returns>Either the type of <see langword="string"/> or type of <see cref="byte"/>[].</returns>
112+
public Type? ResultType => inProcessHelper.Invoke<bool>("isArrayBuffer", JSReference) ? typeof(byte[]) : typeof(string);
113+
114+
/// <summary>
115+
/// Gets the result of the read a <see langword="string"/>.
116+
/// </summary>
117+
/// <returns>A <see langword="string"/> representing the read. If there was no result from the read or if the read has not ended yet then it will be <see langword="null"/>.</returns>
118+
public string? ResultAsString => inProcessHelper.Invoke<string?>("getAttribute", JSReference, "result");
119+
120+
/// <summary>
121+
/// Gets the result of the read a <see langword="byte"/>[].
122+
/// </summary>
123+
/// <returns>A <see langword="byte"/>[] representing the read. If there was no result from the read or if the read has not ended yet then it will be <see langword="null"/>.</returns>
124+
public byte[]? ResultAsByteArray => inProcessHelper.Invoke<byte[]?>("arrayBuffer", inProcessHelper.Invoke<IJSObjectReference>("getAttribute", JSReference, "result"));
125+
126+
/// <summary>
127+
/// Gets the error object reference which will be <see langword="null"/> if no error occured.
128+
/// </summary>
129+
/// <returns>A nullable IJSObjectReference because it was out of scope to wrap the Exception API.</returns>
130+
public IJSObjectReference? Error => inProcessHelper.Invoke<IJSObjectReference?>("getAttribute", JSReference, "error");
131+
132+
/// <summary>
133+
/// Invoked when a load starts.
134+
/// </summary>
135+
public new Action<ProgressEventInProcess>? OnLoadStart { get; set; }
136+
137+
/// <summary>
138+
/// Invoked when the progress of a load changes which includes when it ends.
139+
/// </summary>
140+
[JsonIgnore]
141+
public new Action<ProgressEventInProcess>? OnProgress { get; set; }
142+
143+
/// <summary>
144+
/// Invoked when a load ends successfully.
145+
/// </summary>
146+
[JsonIgnore]
147+
public new Action<ProgressEventInProcess>? OnLoad { get; set; }
148+
149+
/// <summary>
150+
/// Invoked when a load is aborted.
151+
/// </summary>
152+
[JsonIgnore]
153+
public new Action<ProgressEventInProcess>? OnAbort { get; set; }
154+
155+
/// <summary>
156+
/// Invoked when a load fails due to an error.
157+
/// </summary>
158+
[JsonIgnore]
159+
public new Action<ProgressEventInProcess>? OnError { get; set; }
160+
161+
/// <summary>
162+
/// Invoked when a load finishes successfully or not.
163+
/// </summary>
164+
[JsonIgnore]
165+
public new Action<ProgressEventInProcess>? OnLoadEnd { get; set; }
166+
167+
[JSInvokable]
168+
public void InvokeOnLoadStart(IJSInProcessObjectReference jsProgressEvent)
169+
{
170+
if (OnLoadStart is null) return;
171+
OnLoadStart.Invoke(new ProgressEventInProcess(jSRuntime, inProcessHelper, jsProgressEvent));
172+
}
173+
174+
[JSInvokable]
175+
public void InvokeOnProgress(IJSInProcessObjectReference jsProgressEvent)
176+
{
177+
if (OnProgress is null) return;
178+
OnProgress.Invoke(new ProgressEventInProcess(jSRuntime, inProcessHelper, jsProgressEvent));
179+
}
180+
181+
[JSInvokable]
182+
public void InvokeOnLoad(IJSInProcessObjectReference jsProgressEvent)
183+
{
184+
if (OnLoad is null) return;
185+
OnLoad.Invoke(new ProgressEventInProcess(jSRuntime, inProcessHelper, jsProgressEvent));
186+
}
187+
188+
[JSInvokable]
189+
public void InvokeOnAbort(IJSInProcessObjectReference jsProgressEvent)
190+
{
191+
if (OnAbort is null) return;
192+
OnAbort.Invoke(new ProgressEventInProcess(jSRuntime, inProcessHelper, jsProgressEvent));
193+
}
194+
195+
[JSInvokable]
196+
public void InvokeOnError(IJSInProcessObjectReference jsProgressEvent)
197+
{
198+
if (OnError is null) return;
199+
OnError.Invoke(new ProgressEventInProcess(jSRuntime, inProcessHelper, jsProgressEvent));
200+
}
201+
202+
[JSInvokable]
203+
public void InvokeOnLoadEnd(IJSInProcessObjectReference jsProgressEvent)
204+
{
205+
if (OnLoadEnd is null) return;
206+
OnLoadEnd.Invoke(new ProgressEventInProcess(jSRuntime, inProcessHelper, jsProgressEvent));
207+
}
208+
}

0 commit comments

Comments
 (0)