I'm having lots of trouble trying to get an image I'm retrieving from my Web API to display as a background-image in my Angular application.
The Web API's action that returns the image looks like this:
/// <summary>
/// Returns the medium image for the specified project as image/png media type.
/// </summary>
/// <param name="projectId"></param>
/// <returns></returns>
[HttpGet("{projectId:int}/image/medium")]
[SwaggerResponse(200, typeof(byte[]))]
[Produces("image/png")]
public FileContentResult GetImageMedium(int projectId)
{
var res = _repository.GetProjectResource(projectId, "Medium");
FileContentResult result = new FileContentResult(res.ByteContent, res.MediaType);
return result;
}
This is currently what my Angular service method looks like (but I have tried lots of alternatives):
getProjectImage(id: number) {
return this._http
.get(`${this._url}/${id}/Image/Medium`, { headers: this._auth.headers, responseType: ResponseContentType.Blob })
.map(response => response.arrayBuffer());
}
And this is what I'm trying to apply to the [style.background-image]
of the DOM element:
return `url(${'data:image/png;base64,' + new Buffer(response)})`
As I said before, I've been trying combinations of things from things I've found around the internet, but I have an inherent misunderstanding of most of the pieces involved. What is my Web API returning me? How can I handle that client side? How do I massage the content into something appropriate for a background-image
css property? I would really like to understand this much better in addition to getting this to work. All help is greatly appreciated!
Update
I also just tried to change the Web API action to return a base64 string like this:
/// <summary>
/// Returns the medium image for the specified project as image/png media type.
/// </summary>
/// <param name="projectId"></param>
/// <returns></returns>
[HttpGet("{projectId:int}/image/medium")]
[SwaggerResponse(200, typeof(byte[]))]
[Produces("image/png")]
public string GetImageMedium(int projectId)
{
var res = _repository.GetProjectResource(projectId, "Medium");
return Convert.ToBase64String(res);
}
and handling it client side like this:
getProjectImage(id: number) {
return this._http
.get(`${this._url}/${id}/Image/Medium`, { headers: this._auth.headers });
}
and simplifying the caller of my service to provide the following to [style.background-image]
of the DOM element:
return `url(${'data:image/png;base64,' + response})`
I've console.log
ed the response and it indeed looks like a base64 string (I think?). But the css never changes.
Update 2
My markup is currently this:
<div class="image"
[style.background-image]="project.image | async"></div>
My component's code is currently this:
projects.map(project => {
project.image = this._projectsService.getProjectImage(project.projectId)
.map(response => `url('data:image/png;base64,${response['_body']}')`)
});
I've gotten to the point where if I console.log
this out, copy it, and paste it into the css rules for the div in dev tools, the image shows up. I've tried running this in NgZone
and the css still won't show up. Any and all help is appreciated.
Update 3
So, if I change <div class="image" [style.background-image]="project.image | async"></div>
to <img [src]="project.image | async" alt="">
, I get the image to appear asynchronously. The unfortunate thing about this approach is that while the request is in flight, the image error icon is visible. This error icon remains for any items that don't return an image (incomplete database)