3

Info and code:

I am designing a UI where the user can design an object to meet their needs. Afterwards, I want them to be able to click a button to download a file containing the JSON representation of this object. A jquery click listener will use ajax to hit the endpoint on the controller when the button is clicked. Currently, the endpoint looks like this:

   // GET: api/Missions/DownloadMission?id
    [HttpGet]
    [Route("api/Missions/DownloadMission{id}")]
    public IHttpActionResult DownloadMission(int id)
    {
        Mission toDownload = db.Missions.Find(id);
        string json = JsonConvert.SerializeObject(toDownload);
    }

As you can see, the mission object's Id is provided to controller, and the mission is grabbed from it. My problem is that I do not know how to convert the object into JSON in a way that I can then write said JSON into a file, and prompt the user to download it.


Things I have tried:

  using (MemoryStream stream = new MemoryStream())
    {
        using (StreamWriter writer = new StreamWriter(stream))
        {
            while(missionJson.nex)
        }
        return File(stream, "text/plain");
    }

//I tried playing around with this type of set up, but could still not get the intended results 
   byte[] bytes = System.IO.File.ReadAllBytes(data);
    var output = new FileContentResult(bytes, "application/octet-stream");
    output.FileDownloadName = "download.txt";

    return output;
    Mission toDownload = db.Missions.Find(id);
    string fileName = @"~\Mission.txt";
    try
    {
        if (File.Exists(fileName))
        {
            File.Delete(fileName);
        }  
        using (FileStream fs = File.Create(fileName))
        {
            JsonSerializer serializer = new JsonSerializer();
            serializer.Converters.Add(new JavaScriptDateTimeConverter());
            serializer.NullValueHandling = NullValueHandling.Ignore;

            using (StreamWriter sw = new StreamWriter(fileName))
            using (JsonWriter writer = new JsonTextWriter(sw))
            {
                serializer.Serialize(writer, toDownload);
            }
            return File(fs, "Mission.txt");
        }   
    }
    catch (Exception Ex)
    {
        Console.WriteLine(Ex.ToString());
    }
// In this case, "File()" isnt recognized, but this is probably the closest i've been
  1. I have looked through questions such as this one

Problems:

  1. Like I said earlier, I don't know how to go from object to Json to a file
  2. basically all tutorials I can find online are very outdated, or require a filepath, presuming you are providing a pre-existing file, which I am not.
Serus
  • 144
  • 2
  • 11
  • Have you tried to simply `return Ok(toDownload);` this will return the json object without serialization – Jawad Jun 03 '21 at 21:38
  • @Jawad I need to have the user download a file containing said JSON rather than just returning the json – Serus Jun 03 '21 at 21:45

2 Answers2

1
  1. Like I said earlier, I don't know how to go from object to Json to a file

    1. You can use the System.Text.Json namespace to serialize and deserialize JavaScript Object Notation (JSON).
    2. string jsonString = JsonSerializer.Serialize(weatherForecast);
  2. basically all tutorials I can find online are very outdated, or require a filepath, presuming you are providing a pre-existing file, which I am not.

    1. You can return FileContentResult.

    2. You can check the example below.

    3. Code

       [HttpGet("DownloadMission/{id}")]
       public FileContentResult DownloadMission(int id)
       {
           Mission toDownload = new Mission { Id = 1, name = "test" };
           string jsonString = JsonSerializer.Serialize(toDownload);
           var fileName = "test.txt";
           var mimeType = "text/plain";
           var fileBytes = Encoding.ASCII.GetBytes(jsonString);
           return new FileContentResult(fileBytes, mimeType)
           {
               FileDownloadName = fileName
           };
       }
      
    4. Result

      enter image description here

Yihui Sun
  • 755
  • 3
  • 5
0

This could work for you:

[HttpGet]
[Route("api/Missions/DownloadMission{id}")]
public IHttpActionResult DownloadMission(int id)
{
    var toDownload = db.Missions.Find(id);
       
    // if you set this, the browser asks the user to save 'export.json'
    HttpContext.Response.Headers.Add("Content-Disposition", "attachment; filename=export.json");

    // return content as json with your default json serializer settings
    return new JsonResult(toDownload);
}

Like pointed out before, replace the IHttpActionResult with IActionResult, that's the right return type for ASP.NET Core.

I didn't try how it behaves with larger objects, maybe there is some optimization needed for that.


Alternatively you can also set the header in a more "fancy" way, that will properly escape your file name and gives you some additional properites to set.

HttpContext.Response.Headers.Add("Content-Disposition", new System.Net.Mime.ContentDisposition
{
    FileName = "export.json",
    Inline   = false
}.ToString());
andreas
  • 301
  • 3
  • 6