Tuesday, December 15, 2015

How I got an image to the backend of my Aurelia site

Yesterday's task was supposed to be easy enough: everything else in my configuration page is being saved to the backend, time to make the banner image save. I'm using the Aurelia fetch client, and I figured it couldn't be that hard.

You'll notice I said "yesterday's", because I went to be last night with my banner images still firmly locked into the front end. However, stepping away, and some sleep, and I have a solution. It is NOT idea, I think. There may be a better solution, and if I find one, I will blog about it here.

In the end, I was not able to coerce the fetch client to send the data in a way that I could consume it. I will keep looking. But all of the examples of sending form data via AJAX to a .NET backend used jquery, so I dropped into jquery.

My C# is pretty straightforward WebApi 2:

    [Route("user/{zid}/frontend/{feId}/banner")]
    [HttpPost]
    public IHttpActionResult SaveBanner(string zid, string feId)
    {
        if (!System.Web.HttpContext.Current.Request.Files.AllKeys.Any()) return Ok();

        var httpPostedFile = System.Web.HttpContext.Current.Request.Files["BannerImage"];
        if (httpPostedFile == null) return Ok();

        using (var ms = new MemoryStream())
        {
            httpPostedFile.InputStream.CopyTo(ms);
            var response = _repository.SetBanner(zid, feId, ms.GetBuffer() });
            if (response.Success) return Ok();
            return BadRequest();
        }
    }

The javascript is a bit trickier. I know it is going to be possible to save the banner image and all of the other settings in one call to the backend, but right now it's done with two. So I end up with javascript that first uses the fetch client to save the other settings, represented by a JSON string, and then a jquery ajax call to save the image:

    updateUISettings(feId, feSettings, bannerImage) {
        let url = `/vt/user/${this.zid}/frontend/${feId}`;
        
        let content = {
            Name: feName,
            Settings: feSettings
        };
        return this.put(url, content)
            .then(response => {
                if (bannerImage) {
                    let bannerUrl = `{$root}/${url}/banner`;
                    var data = new FormData();
                    data.append("BannerImage", bannerImage);
                
                    return new Promise((accept, reject) => {
                        $.ajax({
                            type: "POST",
                            url: bannerUrl,
                            contentType: false,
                            processData: false,
                            data: data
                        })
                        .done((data, textStatus, xhr) => {
                            accept(response);
                        })
                        .fail((xhr, textStatus) => {
                            reject(textStatus);
                        });
                    });
                } else {
                    return response;
                }
            });
    }

Amazingly, it works.

For which I am grateful, as I have a demo today, and I wanted this front-end configuration piece to be complete.

No comments: