-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Blazor Media Component Suite #63540
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Blazor Media Component Suite #63540
Conversation
…eaming of variable size
This reverts commit 3e674f7.
…for loading and error styling using css data-state
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a comprehensive media component suite for efficiently handling non-HTTP sources (byte[]s or streams) with streaming through JS interop and browser-side caching. The suite provides Image
, Video
, and FileDownload
components built on a shared foundation with unified source handling, automatic caching, and stream-based transfer for optimal performance.
Key changes include:
- New media component architecture with
MediaSource
class and abstractMediaComponentBase
- Browser Cache Storage API integration for efficient content reuse
- TypeScript implementation for streaming and download functionality with fallback support
- Comprehensive test coverage including unit tests and E2E tests
Reviewed Changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.
Show a summary per file
File | Description |
---|---|
src/Components/Web/src/Media/ |
Core media component implementation including base classes and concrete components |
src/Components/Web.JS/src/Rendering/BinaryMedia.ts |
TypeScript implementation for streaming, caching, and download functionality |
src/Components/test/testassets/BasicTestApp/MediaTest/ |
E2E test components for validating media component behavior |
src/Components/test/E2ETest/Tests/ |
E2E test suites for Image, Video, and FileDownload components |
src/Components/Web/test/Media/ |
Unit tests for media component functionality |
src/Components/Web/src/PublicAPI.Unshipped.txt |
Public API surface additions |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a great start, but I think we need to tweak things a bit to balance code-reuse and public API surface.
src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj
Outdated
Show resolved
Hide resolved
protected override void BuildRenderTree(RenderTreeBuilder builder) | ||
{ | ||
builder.OpenElement(0, TagName); | ||
|
||
builder.AddAttribute(1, MarkerAttributeName, ""); | ||
|
||
if (IsLoading) | ||
{ | ||
builder.AddAttribute(2, "data-state", "loading"); | ||
} | ||
else if (_hasError) | ||
{ | ||
builder.AddAttribute(2, "data-state", "error"); | ||
} | ||
|
||
builder.AddAttribute(3, "href", "javascript:void(0)"); | ||
|
||
builder.AddAttribute(4, "onclick", EventCallback.Factory.Create(this, OnClickAsync)); | ||
|
||
if (AdditionalAttributes?.ContainsKey("href") == true) | ||
{ | ||
AdditionalAttributes.Remove("href"); | ||
} | ||
builder.AddMultipleAttributes(6, AdditionalAttributes); | ||
|
||
builder.AddElementReferenceCapture(7, elementReference => Element = elementReference); | ||
|
||
builder.AddContent(8, Text ?? "Download"); | ||
|
||
builder.CloseElement(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of this, I think it should be something like <a href="file" download>Text</a>
.
Also, if we want to avoid having the text, we can receive RenderFragment<T>
as a parameter (where T might be some context we want to make available for rendering). Or just RenderFragment
and let the consumer define the UI completely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current approach was made to support the native picker direct-to-file download. Right now when a download is triggered, if the native file picker dialog is available, we stream the data direct-to-file. If not, we default to the <a href="file" download>Text</a>
download
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I must have missed that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, if we want to avoid having the text, we can receive
RenderFragment<T>
as a parameter (where T might be some context we want to make available for rendering). Or justRenderFragment
and let the consumer define the UI completely.
I've implemented the RenderFragment<T>
approach with MediaContext
as the context type, giving consumers access to loading states, error conditions and the object url.
The downside is that users have to provide the element reference to make the element propagation to JS possible, by doing something like this:
<Image Context="ctx" Source=...>
...
<img @ref="ctx.Element" src="@ctx.ObjectUrl" .../>
...
</Image>
@rolandVi to throw a curve ball on this. @pavelsavara rightly pointed out that for |
Thank you for the feedback, this is indeed very useful. I've implemented an approach using the MediaSource api for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
Media Component Suite
Summary
This PR introduces a suite of media components for efficiently handling non-HTTP sources (byte[]s or streams) with streaming through JS interop and browser-side caching. The suite includes
Image
,Video
, andFileDownload
which built on a shared foundation.Features
MediaSource
from byte[] or Stream with MimeType and CacheKey propertiesImage
andVideo
components for efficient reuseDotNetStreamReference
for efficient streaming from .NET to JS--blazor-media-progress
<img data-blazor-image>
<video data-blazor-video>
<a data-blazor-file-download>
API surface
Base
MediaComponentBase
class for shared functionalityImage Component
<img>
(e.g., alt, class, style)<img data-blazor-image data-state="loading|error" ... />
Video Component
<video>
(e.g., controls, autoplay, loop)<video data-blazor-video data-state="loading|error" ... ></video>
FileDownload Component
<a>
(e.g., class, style)<a data-blazor-file-download data-state="loading|error" ... >Download</a>
Implementation (
src\Components
)Web\src\Media\MediaComponentBase.cs
Web\src\Media\MediaSource.cs
Web\src\Media\Image.cs
Web\src\Media\Video.cs
Web\src\Media\FileDownload.cs
Web.JS\src\Rendering\BinaryMedia.ts
Web\test\Media
test\testassets\BasicTestApp\MediaTest
test\E2ETest\Tests\ImageTest.cs
test\E2ETest\Tests\VideoTest.cs
test\E2ETest\Tests\FileDownloadTest.cs
Performance considerations
Examples
Image Component
Video Component
FileDownload Component
Related to -> #63562