tomkuijsten / restup

Webserver for universal windows platform (UWP) apps
MIT License
114 stars 48 forks source link

Regarding issue #65 - REST service with images #117

Closed alwendt4 closed 7 years ago

alwendt4 commented 7 years ago

Quick follow-up question/issue on Restup …. Issue # 65 (https://github.com/tomkuijsten/restup/issues/65).

I agree 100% with steveegg. And I’m trying to implement something with Restup along the lines of his comment:

GET /api/camera/{id}/snapshot - Current Live image GET /api/camera/{id}/snapshot?time={datetime}&duraction={duration}

Can you please point me to an example of doing this?

I’ve been trying to send a stream, and have failed miserably. Here is my code, but the stream doesn't make it to the client …

    public IAsyncOperation<IGetResponse> Get()
    {

        ReadyPhotoStream();

        return Task.FromResult<IGetResponse>(new GetResponse(
            GetResponse.ResponseStatus.OK,
            photoReceived)).AsAsyncOperation();

    }

    private async void ReadyPhotoStream()
    {
        photoFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Photos/photo.jpg"));
        photoStream = await photoFile.OpenReadAsync();
        photoReceived.ID = 999;
        photoReceived.PhotoStream = photoStream;
    }
Jark commented 7 years ago

Hi @alwendt4,

What is your intended use-case? Do you want to be able to embed it in a web page? Or do you want to use the get response in a different application? It looks like you wan to do the 2nd option.

Restup doesn't support sending non-primitive types to the client, you should've received a bad request on the client as a result of this because it's unable to serialise it.

You'll need to read the file into memory and send it down the stream as a byte array (see -> https://github.com/tomkuijsten/restup/blob/master/src/WebServer/File/StaticFileRouteHandler.cs#L81)

Hope this helps.

alwendt4 commented 7 years ago

Hi Jark,

1) "What is your intended use-case?" Answer: Again, I am in complete agreement with steveegg from issue #65. For brevity's sake, I will neither argue with you on the validity of the use-case, nor repeat parts from your conversation with him. We agree to disagree, and that's as far as I'm going to go. Please don't engage me in this topic/argument as I promise not to respond to it. Respectfully, I think steveegg from issue #65 is right and you're wrong. Please don't take that personally, and I wish to thank you for ultimately helping me solve my problem.

2) Read the file into memory and send it down the stream as a byte array. Worked great ... your example wasn't very helpful to me, so in the spirit of trying to be helpful in return here is my code ...

As an introduction, I have a UWP headless application acting as the RESTful Web Service physically running on a Raspberry Pi 3. And my client is my PC acting as a RESTful client using a .NET framework console application.

So here is how I got it to work ... with the server running, the client initiates a request to the server ...

    static async Task RunAsync()
    {
        client.BaseAddress = new Uri("http://192.168.1.14:8800/");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new
             MediaTypeWithQualityHeaderValue("application/json"));

        try
        {
            Product product;

            // Get the product
            product = await GetProductAsync("api");
            ...
    static async Task<Product> GetProductAsync(string path)
    {
        Product product = null;
        HttpResponseMessage response = await client.GetAsync(path);
        if (response.IsSuccessStatusCode)
        {
            product = await response.Content.ReadAsAsync<Product>();
        }
        return product;
    }

... here is my Product class (a byte stream/array) as you said it needs to be ... public class Product { public int ID { get; set; } public byte[] ImageBytes; }

... which leads into the server code (again, the image stored in a byte array/stream) ...

public sealed class PhotoReceived
{
    public int ID { get; set; }
    public byte[] ImageBytes { get; set; }
}

[RestController(InstanceCreationType.PerCall)]
public sealed class ParameterController
{
    StorageFile photoFile;
    IRandomAccessStream photoStream;
    PhotoReceived photoReceived = new PhotoReceived();

    [UriFormat("/")]
    public IAsyncOperation<IGetResponse> Get()
    {
        ReadyPhotoStream();

        return Task.FromResult<IGetResponse>(new GetResponse(
            GetResponse.ResponseStatus.OK,
            photoReceived)).AsAsyncOperation();
    }

    private async void ReadyPhotoStream()
    {
        photoFile = await StorageFile.GetFileFromApplicationUriAsync(
             new Uri("ms-appx:///Photos/photo.jpg"));
        photoStream = await photoFile.OpenReadAsync();
        photoReceived.ID = 999;
        var reader = new Windows.Storage.Streams.DataReader(photoStream.GetInputStreamAt(0));
        await reader.LoadAsync((uint)photoStream.Size);

        photoReceived.ImageBytes = new byte[photoStream.Size];

        reader.ReadBytes(photoReceived.ImageBytes);
    }

... finally, back to the client ... the GetProductAsync method in the RunAsync() method finishes, and I execute:

            ShowProduct(product);

... the ShowProduct method looks like this ...

    static async void ShowProduct(Product product)
    {
        Console.WriteLine($"ID: {product.ID}");

        System.Drawing.Image localImage;
        using (MemoryStream ImageStream = new System.IO.MemoryStream(product.ImageBytes))
        {
            localImage = System.Drawing.Image.FromStream(ImageStream);
            localImage.Save(@"C:\Users\big_al\Pictures\test.jpg",
                 System.Drawing.Imaging.ImageFormat.Jpeg);
        }

    }

... Thanks again Jark for helping me get through this. Your suggestion to use a byte array paid off well. You can close the issue now, as my issue is resolved. You have my gratitude of extraordinary magnitude.

Jark commented 7 years ago

Hi @alwendt4,

Glad you were able to figure it out.

Jark