Skip to content

Commit cd61ed7

Browse files
authored
Merge pull request #25141 from dotnet-maestro-bot/merge/release/5.0-to-master
[automated] Merge branch 'release/5.0' => 'master'
2 parents 569dc2f + 3ced87e commit cd61ed7

File tree

108 files changed

+2557
-342
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+2557
-342
lines changed

THIRD-PARTY-NOTICES.txt

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,4 +267,29 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
267267
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
268268
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
269269
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
270-
SOFTWARE.
270+
SOFTWARE.
271+
272+
License notice for BedrockFramework
273+
===================================
274+
275+
MIT License
276+
277+
Copyright (c) 2019 David Fowler
278+
279+
Permission is hereby granted, free of charge, to any person obtaining a copy
280+
of this software and associated documentation files (the "Software"), to deal
281+
in the Software without restriction, including without limitation the rights
282+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
283+
copies of the Software, and to permit persons to whom the Software is
284+
furnished to do so, subject to the following conditions:
285+
286+
The above copyright notice and this permission notice shall be included in all
287+
copies or substantial portions of the Software.
288+
289+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
290+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
291+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
292+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
293+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
294+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
295+
SOFTWARE.

eng/Versions.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@
274274
<SerilogSinksFilePackageVersion>4.0.0</SerilogSinksFilePackageVersion>
275275
<StackExchangeRedisPackageVersion>2.0.593</StackExchangeRedisPackageVersion>
276276
<SystemReactiveLinqPackageVersion>3.1.1</SystemReactiveLinqPackageVersion>
277+
<SwashbuckleAspNetCorePackageVersion>5.5.1</SwashbuckleAspNetCorePackageVersion>
277278
<XunitAbstractionsPackageVersion>2.0.3</XunitAbstractionsPackageVersion>
278279
<XunitAnalyzersPackageVersion>0.10.0</XunitAnalyzersPackageVersion>
279280
<XunitVersion>2.4.1</XunitVersion>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.IO;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
9+
namespace Microsoft.AspNetCore.Components.Web.Extensions
10+
{
11+
internal class BrowserFile : IBrowserFile
12+
{
13+
internal InputFile Owner { get; set; } = default!;
14+
15+
public int Id { get; set; }
16+
17+
public string Name { get; set; } = string.Empty;
18+
19+
public DateTime LastModified { get; set; }
20+
21+
public long Size { get; set; }
22+
23+
public string Type { get; set; } = string.Empty;
24+
25+
public string? RelativePath { get; set; }
26+
27+
public Stream OpenReadStream(CancellationToken cancellationToken = default)
28+
=> Owner.OpenReadStream(this, cancellationToken);
29+
30+
public Task<IBrowserFile> ToImageFileAsync(string format, int maxWidth, int maxHeight)
31+
=> Owner.ConvertToImageFileAsync(this, format, maxWidth, maxHeight);
32+
}
33+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.IO;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
9+
namespace Microsoft.AspNetCore.Components.Web.Extensions
10+
{
11+
internal abstract class BrowserFileStream : Stream
12+
{
13+
private long _position;
14+
15+
protected BrowserFile File { get; }
16+
17+
protected BrowserFileStream(BrowserFile file)
18+
{
19+
File = file;
20+
}
21+
22+
public override bool CanRead => true;
23+
24+
public override bool CanSeek => false;
25+
26+
public override bool CanWrite => false;
27+
28+
public override long Length => File.Size;
29+
30+
public override long Position
31+
{
32+
get => _position;
33+
set => throw new NotSupportedException();
34+
}
35+
36+
public override void Flush()
37+
=> throw new NotSupportedException();
38+
39+
public override int Read(byte[] buffer, int offset, int count)
40+
=> throw new NotSupportedException("Synchronous reads are not supported.");
41+
42+
public override long Seek(long offset, SeekOrigin origin)
43+
=> throw new NotSupportedException();
44+
45+
public override void SetLength(long value)
46+
=> throw new NotSupportedException();
47+
48+
public override void Write(byte[] buffer, int offset, int count)
49+
=> throw new NotSupportedException();
50+
51+
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
52+
=> ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
53+
54+
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
55+
{
56+
int maxBytesToRead = (int)(Length - Position);
57+
58+
if (maxBytesToRead > buffer.Length)
59+
{
60+
maxBytesToRead = buffer.Length;
61+
}
62+
63+
if (maxBytesToRead <= 0)
64+
{
65+
return 0;
66+
}
67+
68+
var bytesRead = await CopyFileDataIntoBuffer(_position, buffer.Slice(0, maxBytesToRead), cancellationToken);
69+
70+
_position += bytesRead;
71+
72+
return bytesRead;
73+
}
74+
75+
protected abstract ValueTask<int> CopyFileDataIntoBuffer(long sourceOffset, Memory<byte> destination, CancellationToken cancellationToken);
76+
}
77+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.IO;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
9+
namespace Microsoft.AspNetCore.Components.Web.Extensions
10+
{
11+
/// <summary>
12+
/// Represents the data of a file selected from an <see cref="InputFile"/> component.
13+
/// </summary>
14+
public interface IBrowserFile
15+
{
16+
/// <summary>
17+
/// Gets the name of the file.
18+
/// </summary>
19+
string Name { get; }
20+
21+
/// <summary>
22+
/// Gets the last modified date.
23+
/// </summary>
24+
DateTime LastModified { get; }
25+
26+
/// <summary>
27+
/// Gets the size of the file in bytes.
28+
/// </summary>
29+
long Size { get; }
30+
31+
/// <summary>
32+
/// Gets the MIME type of the file.
33+
/// </summary>
34+
string Type { get; }
35+
36+
/// <summary>
37+
/// Opens the stream for reading the uploaded file.
38+
/// </summary>
39+
/// <param name="cancellationToken">A cancellation token to signal the cancellation of streaming file data.</param>
40+
Stream OpenReadStream(CancellationToken cancellationToken = default);
41+
42+
/// <summary>
43+
/// Converts the current image file to a new one of the specified file type and maximum file dimensions.
44+
/// </summary>
45+
/// <remarks>
46+
/// The image will be scaled to fit the specified dimensions while preserving the original aspect ratio.
47+
/// </remarks>
48+
/// <param name="format">The new image format.</param>
49+
/// <param name="maxWith">The maximum image width.</param>
50+
/// <param name="maxHeight">The maximum image height</param>
51+
/// <returns>A <see cref="Task"/> representing the completion of the operation.</returns>
52+
Task<IBrowserFile> ToImageFileAsync(string format, int maxWith, int maxHeight);
53+
}
54+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Threading.Tasks;
5+
6+
namespace Microsoft.AspNetCore.Components.Web.Extensions
7+
{
8+
internal interface IInputFileJsCallbacks
9+
{
10+
Task NotifyChange(BrowserFile[] files);
11+
}
12+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
using Microsoft.AspNetCore.Components.Rendering;
10+
using Microsoft.Extensions.Options;
11+
using Microsoft.JSInterop;
12+
13+
namespace Microsoft.AspNetCore.Components.Web.Extensions
14+
{
15+
/// <summary>
16+
/// A component that wraps the HTML file input element and exposes a <see cref="Stream"/> for each file's contents.
17+
/// </summary>
18+
public class InputFile : ComponentBase, IInputFileJsCallbacks, IDisposable
19+
{
20+
private ElementReference _inputFileElement;
21+
22+
private IJSUnmarshalledRuntime? _jsUnmarshalledRuntime;
23+
24+
private InputFileJsCallbacksRelay? _jsCallbacksRelay;
25+
26+
[Inject]
27+
private IJSRuntime JSRuntime { get; set; } = default!;
28+
29+
[Inject]
30+
private IOptions<RemoteBrowserFileStreamOptions> Options { get; set; } = default!;
31+
32+
/// <summary>
33+
/// Gets or sets the event callback that will be invoked when the collection of selected files changes.
34+
/// </summary>
35+
[Parameter]
36+
public EventCallback<InputFileChangeEventArgs> OnChange { get; set; }
37+
38+
/// <summary>
39+
/// Gets or sets a collection of additional attributes that will be applied to the input element.
40+
/// </summary>
41+
[Parameter(CaptureUnmatchedValues = true)]
42+
public IDictionary<string, object>? AdditionalAttributes { get; set; }
43+
44+
protected override void OnInitialized()
45+
{
46+
_jsUnmarshalledRuntime = JSRuntime as IJSUnmarshalledRuntime;
47+
}
48+
49+
protected override async Task OnAfterRenderAsync(bool firstRender)
50+
{
51+
if (firstRender)
52+
{
53+
_jsCallbacksRelay = new InputFileJsCallbacksRelay(this);
54+
await JSRuntime.InvokeVoidAsync(InputFileInterop.Init, _jsCallbacksRelay.DotNetReference, _inputFileElement);
55+
}
56+
}
57+
58+
protected override void BuildRenderTree(RenderTreeBuilder builder)
59+
{
60+
builder.OpenElement(0, "input");
61+
builder.AddMultipleAttributes(1, AdditionalAttributes);
62+
builder.AddAttribute(2, "type", "file");
63+
builder.AddElementReferenceCapture(3, elementReference => _inputFileElement = elementReference);
64+
builder.CloseElement();
65+
}
66+
67+
internal Stream OpenReadStream(BrowserFile file, CancellationToken cancellationToken)
68+
=> _jsUnmarshalledRuntime != null ?
69+
(Stream)new SharedBrowserFileStream(JSRuntime, _jsUnmarshalledRuntime, _inputFileElement, file) :
70+
new RemoteBrowserFileStream(JSRuntime, _inputFileElement, file, Options.Value, cancellationToken);
71+
72+
internal async Task<IBrowserFile> ConvertToImageFileAsync(BrowserFile file, string format, int maxWidth, int maxHeight)
73+
{
74+
var imageFile = await JSRuntime.InvokeAsync<BrowserFile>(InputFileInterop.ToImageFile, _inputFileElement, file.Id, format, maxWidth, maxHeight);
75+
76+
imageFile.Owner = this;
77+
78+
return imageFile;
79+
}
80+
81+
Task IInputFileJsCallbacks.NotifyChange(BrowserFile[] files)
82+
{
83+
foreach (var file in files)
84+
{
85+
file.Owner = this;
86+
}
87+
88+
return OnChange.InvokeAsync(new InputFileChangeEventArgs(files));
89+
}
90+
91+
void IDisposable.Dispose()
92+
{
93+
_jsCallbacksRelay?.Dispose();
94+
}
95+
}
96+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
7+
namespace Microsoft.AspNetCore.Components.Web.Extensions
8+
{
9+
/// <summary>
10+
/// Supplies information about an <see cref="InputFile.OnChange"/> event being raised.
11+
/// </summary>
12+
public class InputFileChangeEventArgs : EventArgs
13+
{
14+
/// <summary>
15+
/// The updated file entries list.
16+
/// </summary>
17+
public IReadOnlyList<IBrowserFile> Files { get; }
18+
19+
/// <summary>
20+
/// Constructs a new <see cref="InputFileChangeEventArgs"/> instance.
21+
/// </summary>
22+
/// <param name="files">The updated file entries list.</param>
23+
public InputFileChangeEventArgs(IReadOnlyList<IBrowserFile> files)
24+
{
25+
Files = files;
26+
}
27+
}
28+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.AspNetCore.Components.Web.Extensions
5+
{
6+
internal static class InputFileInterop
7+
{
8+
private const string JsFunctionsPrefix = "_blazorInputFile.";
9+
10+
public const string Init = JsFunctionsPrefix + "init";
11+
12+
public const string EnsureArrayBufferReadyForSharedMemoryInterop = JsFunctionsPrefix + "ensureArrayBufferReadyForSharedMemoryInterop";
13+
14+
public const string ReadFileData = JsFunctionsPrefix + "readFileData";
15+
16+
public const string ReadFileDataSharedMemory = JsFunctionsPrefix + "readFileDataSharedMemory";
17+
18+
public const string ToImageFile = JsFunctionsPrefix + "toImageFile";
19+
}
20+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Threading.Tasks;
6+
using Microsoft.JSInterop;
7+
8+
namespace Microsoft.AspNetCore.Components.Web.Extensions
9+
{
10+
internal class InputFileJsCallbacksRelay : IDisposable
11+
{
12+
private readonly IInputFileJsCallbacks _callbacks;
13+
14+
public IDisposable DotNetReference { get; }
15+
16+
public InputFileJsCallbacksRelay(IInputFileJsCallbacks callbacks)
17+
{
18+
_callbacks = callbacks;
19+
20+
DotNetReference = DotNetObjectReference.Create(this);
21+
}
22+
23+
[JSInvokable]
24+
public Task NotifyChange(BrowserFile[] files)
25+
=> _callbacks.NotifyChange(files);
26+
27+
public void Dispose()
28+
{
29+
DotNetReference.Dispose();
30+
}
31+
}
32+
}

0 commit comments

Comments
 (0)