Open javiercn opened 4 years ago
Thanks for contacting us.
We're moving this issue to the Next sprint planning
milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
Thanks for contacting us.
We're moving this issue to the Next sprint planning
milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
This sounds like a really nice feature.
We could consider this a special case of "support passing byte[]
in JS interop calls without base64 serialization". If we supported that, then it would be trivial to convert a byte[]
to a blob URL, which could then be used on an <img src>
.
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.
This is a useful feature. But, the "support passing byte[]" in JS interop calls is a better generalization and more flexible approach.
This would be benefitial to reduce the attack surface of web applications: no additional rest interface needed for image creation. We currently use base64 encoded images and it would be nice to reduce the memory overhead for this.
Another instance of this https://github.com/dotnet/aspnetcore/issues/31585
In the interim a new docs page covering best practices for working with images in Blazor (in .NET 6) is available here: https://docs.microsoft.com/aspnet/core/blazor/images?view=aspnetcore-6.0
Thanks all for the discussion.
We could consider this a special case of "support passing
byte[]
in JS interop calls without base64 serialization". If we supported that, then it would be trivial to convert abyte[]
to a blob URL, which could then be used on an<img src>
.
This is exactly the scenario https://docs.microsoft.com/aspnet/core/blazor/images?view=aspnetcore-6.0 covers. Closing out this issue accordingly.
Reopening as after some discussion within the team we believe there will still be value from having a separate components for this.
this have huge value for enterprise applications for this. we use base64 heavily in our application now. i see this as a huge improvement to performance.
This would definitely make things much easier. Go for the component.
We are going to be using this issue to track https://github.com/dotnet/aspnetcore/issues/30290. In 6.0 we added support for dealing with streams of data in 6.0
As part of this issue, we want to add some component primitives that simplify some common scenarios.
MediaComponent
base component that:
All this builds on top of the APIs we already provided in 6.0 to deal with large binary data.
Might potentially support caching the content on the client by providing a key, to avoid repeated roundtrips if the content was already sent once.
Related to https://github.com/dotnet/aspnetcore/issues/27983#issuecomment-1147859617.
This definitely sounds like a good feature to me!
I've been looking for some way to have an objectURL representing a ReadableStream or Response that is still in flight, but can't see any evidence it's possible (other than using a service worker, which I don't think we want to introduce here). So it looks like we'd have to make the client read the entire stream into memory as a blob, and then construct an objectURL from that. This is better than the "base64" alternative but is still a bit limited as:
<img src=...>
However this does simplify the feature a bit, since all we can do is use the existing JS binary streaming interop to send a whole byte[]
/Stream
to JS and then get it to construct a blob
and then objectURL
from that. We'd probably then use a MutationObserver to revoke the objectURL as soon as the img
is removed or if its src
changes.
Might potentially support caching the content on the client by providing a key, to avoid repeated roundtrips if the content was already sent once.
We could theoretically construct a fake Response
object and then store it via the Cache Storage API. This would involve more orchestration, as the JS side would have to pull the data if it's not already cached, instead of more simply having the .NET side push it regardless. It could certainly be done. We'd want to have some design around the cache rules (e.g., expiry) and to what extent we're interested in the .NET side being able to push updates that override the client-side cache.
Optionally, a FileDownload component counterpart to FileUpload that allows the user to save the file.
That sounds good. I suspect it wouldn't be a component at all, but rather just a helper method like:
await FileDownload.SaveAs(streamOrByteArray, "filename.ext");
... since you'd trigger it procedurally when something happens, such as the user clicking a button.
We also need to think about what the img
elements should display before the image data has been fully transferred. Presumably we don't want it to display as a broken image. So do we just not add the img
element to the document until we have the data? Or do we render a <div>
that has the expected width/height to avoid weird reflow effects as the images load?
Update: I suggest we do render an <img>
element right away, but set its src to some kind of "blank image" value (maybe as a data URL). That way, if you have a CSS rule that matches img
, it will apply both before and after the image data is fetched.
- It's definitely not suitable for any kind of video
I wouldn't focus too much on Video vs Image and more on the size as a trait, you can also have images that take in a GB and we can always make a comment that this is designed for images/videos up to x MB, which is something that we can measure and make that clear in the remarks. There are plenty of short clips that this is useful for (an example would be mp4 gifs).
We could theoretically construct a fake
Response
object and then store it via the Cache Storage API. This would involve more orchestration, as the JS side would have to pull the data if it's not already cached, instead of more simply having the .NET side push it regardless. It could certainly be done. We'd want to have some design around the cache rules (e.g., expiry) and to what extent we're interested in the .NET side being able to push updates that override the client-side cache.
I was thinking of a simpler approach where you can pass a URL and do the caching/invalidation yourself by modifying the fake URL. I don't think we need to be doing cleanup as I expect the browser to automatically cleanup when the space limit is reached (if necessary). We would need to do some investigation, but I wouldn't worry about cleanup too much.
The main goal here is to avoid recurring transfers on subsequent visits/re-renders which can also make it much faster to render.
I've been looking for some way to have an objectURL representing a ReadableStream or Response that is still in flight, but can't see any evidence it's possible (other than using a service worker, which I don't think we want to introduce here). So it looks like we'd have to make the client read the entire stream into memory as a blob, and then construct an objectURL from that. This is better than the "base64" alternative but is still a bit limited as:
Unfortunately, this is not possible today :(.
I wouldn't focus too much on Video vs Image and more on the size as a trait
I'd expect that:
With the design as given, (1) would work but (2) would not. It would really only be a specialised kind of video that would work, and in general we'd be guiding people towards failure except in these special cases. The great majority of video scenarios on the web rely on streaming to make the behavior reasonable. Without evidence that customers are asking for a video feature and their scenarios are exclusively very tiny video files, this seems like a fairly clear-cut thing to exclude.
I was thinking of a simpler approach where you can pass a URL and do the caching/invalidation yourself by modifying the fake URL.
OK, cool! I was just trying to think of where the cache data actually gets stored. If it goes in the Cache Storage API, then we have to make some decision about the caching headers we put on the fake Response
objects that get cached. If the decision is "don't put any caching headers and let the browser do whatever it wants" that's totally fine and reasonable, especially if we have some sense of what the practical behavior will be as the cache gets filled up. If you were thinking we use some other storage than Cache Storage, I'd be interested in what.
this seems like a fairly clear-cut thing to exclude.
I'm fine with that, I don't feel super strongly about it. Will you be ok if we do things in a way that would allow people to create their own component leveraging our infrastructure? (something like a base class or similar).
FYI, for videos you can actually create a MediaStream object and assign it to the srcObject property, which doesn't involve putting the entire thing in memory I believe. It is only images that don't have this ability.
FYI, for videos you can actually create a MediaStream object and assign it to the srcObject property,
Interesting, I didn't know that. Sounds like that would involve supplying MediaStream content programmatically or do this, which I didn't see any API for (but only looked for a few minutes, so might have missed something obvious).
I'm fine with that, I don't feel super strongly about it. Will you be ok if we do things in a way that would allow people to create their own component leveraging our infrastructure? (something like a base class or similar).
I have no objection to letting people subclass the component we provide and overriding the BuildRenderTree
method so that it produces a <video>
element instead of an <img>
element. They should be able to do this easily with a regular .razor
file and @inherits
. My concern is only about deliberately suggesting to people that they should use this for videos when we know in most cases it will be substandard vs normal streaming :)
I have no objection to letting people subclass the component we provide and overriding the
BuildRenderTree
method so that it produces a<video>
element instead of an<img>
element. They should be able to do this easily with a regular.razor
file and@inherits
. My concern is only about deliberately suggesting to people that they should use this for videos when we know in most cases it will be substandard vs normal streaming :)
I agree, I just want to make sure that the guts of our component can be reused so that things like caching, etc. don't have to be reimplemented. That is why I was suggesting we had a "base" Media component and a concrete Image component that extends it for use with images.
The other thing that might be interesting to consider (somewhat orthogonal) is if there is a way in which we could make the JS this component needs, separate from the main Blazor bundle. Maybe something similar to what we tell customers to do with JS modules. It'll be interesting to see if we can establish a modular pattern for these features so that they are only paid for when used.
The other thing that might be interesting to consider (somewhat orthogonal) is if there is a way in which we could make the JS this component needs, separate from the main Blazor bundle
Very interesting. Earlier, I was contemplating suggesting making a separate package for this (for the same reason) but didn't because I didn't want to overcomplicate things. If we could get the JS into a separate bundle and rely on the .NET trimmer for taking out unused .NET code, then we'd get the size reduction without needing a separate package which would be better still.
I guess the work here would be figuring out how to extend our build system in a clear enough and reusable enough way. Maybe it's fairly straightforwards, in that we already build multiple blazor.*.js
files (using different webpack entrypoints) so maybe we could have another webpack entrypoint for blazor.mediacomponent.js
or whatever it gets called. We'd also have to make sure it gets into the right packages so it can be served from _framework
or similar.
@SteveSandersonMS I would imagine that we would define these as a JS module and produce a separate output, and then we would need to make sure the SDK accounts for this file in the same way as the blazor.webassembly.js file.
Now that I think about it is a bit more complicated, since we would need to figure things out for Blazor Server (I guess we would also embed the file in that case) and blazor webview. I am inclined to say, keep it simple 😄. We can figure out how to do this in the future, as I think it is interesting to have a chance to "ship these things inbox" but following a similar pattern as a third-party library.
Thanks for contacting us.
We're moving this issue to the .NET 7 Planning
milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
While we have made progress on this feature, at this point we think the risk is too high to include this in the .NET 7 release. Moving to .NET 8.
Another instance this component is useful https://github.com/dotnet/aspnetcore/issues/47449
Another problematic case https://github.com/dotnet/aspnetcore/issues/48123
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.
Summary
Introduce an Image component to display images coming from
dynamic
sources like API calls or databases.Motivation
Currently the most common way to display an image coming from the
Database
is to base64 encoded it and create an object URL for it. This is problematic since images have a big size and that results in the allocation of large strings, which has a big impact on performance. We want to display images on the browser without allocating large amounts of memory on the .NET side.Goals
Non-goals
Scenarios
@code { private ImageSource _imageSource;
}