0

I have two APIs:

  1. Public API
  2. API in DMZ

I need to implement a method which returns a file in a public API.

API in DMZ:

    public HttpResponseMessage GetContent(int id)
    {
        var content = from m in db.messagestoimages
                      where m.Message == id
                      select m;

        if (content == null || content.Count() == 0)
        {
            return null;
        }
        string fileName = content.First().ImageURL;

        string fullPath = AppDomain.CurrentDomain.BaseDirectory  + fileName;
        if (File.Exists(fullPath))
        {

            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
            var fileStream = new FileStream(fullPath, FileMode.Open);
            response.Content = new StreamContent(fileStream);
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            response.Content.Headers.ContentDisposition.FileName = fileName;
            return response;
        }

        return null;
    }

Public API

    public HttpResponseMessage Get(string id)
    {
        try
        {
            //if (form.file != null && form.file.Length > 0)
            {
                using (var client = new HttpClient())
                {
                    try
                    {
                        string host = configuration.GetSection("MySettings").GetSection("OctopusURL").Value;

                        client.BaseAddress = new Uri(host);

                        var response =  client.GetAsync("api/Content/" + id);
                        

                        return response.Result;

                    }
                    catch (Exception ex)
                    {
                        return new HttpResponseMessage(HttpStatusCode.NotFound);
                    }
                }
            }

        }
        catch (Exception ex)
        {
            return new HttpResponseMessage(HttpStatusCode.NotFound); // 500 is generic server error
        }
    }

If I call directly DMZ method, file is downloaded successfully. If I call public API, I do not get a file. Only content.

{
    "version": {
        "major": 1,
        "minor": 1,
        "build": -1,
        "revision": -1,
        "majorRevision": -1,
        "minorRevision": -1
    },
    "content": {
        "headers": [
            {
                "key": "Content-Length",
                "value": [
                    "17488"
                ]
            },
            {
                "key": "Content-Type",
                "value": [
                    "application/octet-stream"
                ]
            },
            {
                "key": "Expires",
                "value": [
                    "-1"
                ]
            },
            {
                "key": "Content-Disposition",
                "value": [
                    "attachment; filename=\"/Userimage/3A297B090A41B649BF80.jpeg\""
                ]
            }
        ]
    },
    "statusCode": 200,
    "reasonPhrase": "OK",
    "headers": [
        {
            "key": "Cache-Control",
            "value": [
                "no-cache"
            ]
        },
        {
            "key": "Pragma",
            "value": [
                "no-cache"
            ]
        },
        {
            "key": "Server",
            "value": [
                "Microsoft-IIS/10.0"
            ]
        },
        {
            "key": "X-AspNet-Version",
            "value": [
                "4.0.30319"
            ]
        },
        {
            "key": "X-SourceFiles",
            "value": [
                "=?UTF-8?B?QzpcVXNlcnNcbmFyaW1cc291cmNlXHJlcG9zXENoYXRBc3Npc3RlbnRcQ2hhdEFzc2lzdGFudFxDaGF0QXNzaXN0ZW50XGFwaVxDb250ZW50XDkzMjQ=?="
            ]
        },
        {
            "key": "X-Powered-By",
            "value": [
                "ASP.NET"
            ]
        },
        {
            "key": "Date",
            "value": [
                "Wed, 21 Aug 2019 13:43:26 GMT"
            ]
        }
    ],
    "requestMessage": {
        "version": {
            "major": 2,
            "minor": 0,
            "build": -1,
            "revision": -1,
            "majorRevision": -1,
            "minorRevision": -1
        },
        "content": null,
        "method": {
            "method": "GET"
        },
        "requestUri": "http://localhost:60236/api/Content/9324",
        "headers": [],
        "properties": {}
    },
    "isSuccessStatusCode": true
}

How can I solve this problem?

I tried changing public API so it gets Stream, creates response and returns, but it did not work - same results.

string host = configuration.GetSection("MySettings").GetSection("OctopusURL").Value;

client.BaseAddress = new Uri(host);

var responseFromServer = await client.GetAsync("api/Images/" + id);
Stream streamToReadFrom = await responseFromServer.Content.ReadAsStreamAsync();

HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(streamToReadFrom);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "sd.jpg";
return response;      
TylerH
  • 20,799
  • 66
  • 75
  • 101
Nate
  • 827
  • 3
  • 18
  • 29

2 Answers2

1

Tested and it works fine. first controller:

public class TestController : ApiController
{
    [Route("GetContent")]
    public HttpResponseMessage Get()
    {
        string fileName = "a.json";

        string fullPath = AppDomain.CurrentDomain.BaseDirectory + fileName;
        if (File.Exists(fullPath))
        {
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
            var fileStream = new FileStream(fullPath, FileMode.Open);
            response.Content = new StreamContent(fileStream);
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            response.Content.Headers.ContentDisposition.FileName = fileName;
            return response;
        }

        return null;
    }
}

second controller:

public class PublicController : ApiController
{
    [Route("GetContent")]
    public async Task<HttpResponseMessage> Get()
    {
        using (var client = new HttpClient())
        {
            try
            {
                client.BaseAddress = new Uri("http://localhost:9000/");

                var responseFromServer = await client.GetAsync("api/Test/GetContent");
                Stream streamToReadFrom = await responseFromServer.Content.ReadAsStreamAsync();

                HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
                response.Content = new StreamContent(streamToReadFrom);
                response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
                response.Content.Headers.ContentDisposition.FileName = "sd.json";
                return response;

            }
            catch (Exception ex)
            {
                return new HttpResponseMessage(HttpStatusCode.NotFound);
            }
        }
    }
}

This call to public controller method downloads the file:

http://localhost:9001/api/Public/GetContent

ozanmut
  • 2,898
  • 26
  • 22
0

You should get the File stream in the Public API method like this and then return it to the Client the same way the DMZ returns it.

Albondi
  • 1,141
  • 1
  • 8
  • 19
  • I tried. Please, check original post, i updated at the end. Same results. – Nate Aug 21 '19 at 14:37
  • Have you tried changing the return type so that you can return `return File(contentStream, content_type, filename);` ? – Albondi Aug 21 '19 at 14:42
  • i just changed to return File(streamToReadFrom, "jpg", "test"); It returns InvalidOperationException: Cannot return null from an action method with a return type of 'Microsoft.AspNetCore.Mvc.FileStreamResult'. – Nate Aug 21 '19 at 14:59
  • Sorry, I would try debugging it and see why the stream is null. – Albondi Aug 21 '19 at 15:13