[.NET Core] Bestand downloaden via RestSharp / .NET Core API

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 27-09 13:36
Ik ben bezig met een web API geschreven in .NET Core (MVC), die communiceert via JSON. Op de client (.NET Windows, WPF) gebruik ik RestSharp om de verbinding te maken.

Elke functie op de server die de client kan aanroepen laat ik een instance van ApiResponse terug sturen, welke een simpele wrapper is die naast de "payload" (object) ook een error message terug kan geven.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[HttpGet]
public async Task<IActionResult> GetSomething()
{
    var something = await _repo.GetSomethingAsync();

    ApiResponse response;
    
    if (something == null)
        response = new ApiResponse(success: false, error: "Something went wrong");
    else
        response = new ApiResponse(success: true, payload: something);
        
    return Ok(response);    
}

Ik stuur dus altijd een "OK" terug.

Op de client kan ik nu checken:

- Als de http code "OK" is dan weet ik dat ik een ApiResponse terug zal krijgen, dus kan ik die casten (of gebruik maken van de RestSharp 'Execute<T>' generic functies). Daarna kan ik specifiek checken of "success == true" en de payload gebruiken. Als "success == false" weet ik dat ik een error message kan verwachten.

- Als de http code niet "OK" is dan is er iets ernstig fout en kan ik ook geen nuttige error geven behalve dat er iets mis is met de server.


Nu heb ik een functie waarmee ik de client een bestand wil laten downloaden. Het bestand staat op de server (zip bestand) en kan mogelijk tot ~1 GB groot zijn (momenteel nog lang niet, maar dit moet flexibel zijn voor grotere bestanden later). Op het moment gebruik ik hier heel simpel een "payload" van een byte array voor, oftewel de server stuurt gewoon de raw bytes in een keer.
C#:
1
2
3
4
5
6
7
8
9
10
11
// Client:
var request = CreateRequest("api/get_file");
var response = await _client.ExecuteTaskAsync<ApiResponse<byte[]>>(request);
if (response.StatusCode == HttpStatusCode.OK)
{
    var apiResponse = response.Data;
    if (apiResponse.Success)
    {
        return apiResponse.Payload; // file contents as byte[]
    }
}


Ik ben bang dat dit niet goed schaalt en weet dat ik eigenlijk gebruik zou moeten maken van file streams. In de web API op de server kan ik daarvoor bijvoorbeeld een "FileResult" terug sturen, bijvoorbeeld:
C#:
1
2
3
4
5
6
7
8
[HttpGet]
public async Task<IActionResult> GetFile()
{
    using (var stream = await _repo.GetStream())
    {
        return File(stream, "application/octet-stream");
    }
}


Op de client zou ik dan gebruik moeten maken van de RestSharp DownloadData functie en de ResponseWriter op ongeveer zo'n manier:
C#:
1
2
3
4
5
6
7
8
// Client:
using (var stream = File.Open("test.zip"))
{
    var request = CreateRequest("api/get_file");
    request.ResponseWriter = s => s.CopyTo(stream);
    
    var response = _client.DownloadData(request); // byte[]
}



Ik heb nu een aantal vragen:

1. In het geval van de filestream methode krijg ik als response alsnog gewoon een byte array terug. Het probleem is dat ik hier dus geen status code of niks uit krijg. Hoe weet ik of er iets mis is gegaan en welke error ik moet tonen?

2. Ik kan nu dus geen ApiResponse maken en terug sturen, laat staan zelf errors terugsturen. Op de server gebeuren een groot aantal checks en als ergens niet aan voldaan is (bijv gebruiker mag deze file niet hebben) dan wil ik een error terug geven die logisch is, en niet gewoon een "404" of whatever. Nu weet ik dat er speciale error codes zijn voor "not authenticated" etc maar die zijn lang niet toereikend voor mijn geval. Ik wil gewoon een eigen error message vanuit de server kunnen terugsturen.


Wat ik dus eigenlijk wil is alsnog een ApiResponse terug sturen, zodat ik er zelf een error aan kan knopen, maar alsnog de file niet in een ruk maar als een filestream kan behandelen.

Heeft iemand een idee?

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • mulder
  • Registratie: Augustus 2001
  • Nu online

mulder

ik spuug op het trottoir

Je kunt een InternalServerError teruggeven met een custom message

oogjes open, snaveltjes dicht


Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 08-10 12:16

Haan

dotnetter

Is ApiResponse een custom class van jezelf?

Ik heb even geen .NET core bij de hand, maar volgens mij werkt het nog vergelijkbaar met Web API 2, dus ik zou bij geen result een NotFound() returnen, of desnoods een InternalServerError() zoals @mulder aangeeft.

En bij succes gewoon een Ok(something), dus zonder deze nog te wrappen in een ApiResponse, dat ding voegt helemaal niks toe, na nog een keer lezen in jouw geval misschien wel, je zou dan voor de InternalServerError kunnen kiezen met een Exception die uitlegt wat er aan de hand is, of misschien een BadRequest, beetje afhankelijk van wat er precies aan de hand is.

[ Voor 24% gewijzigd door Haan op 16-08-2017 10:53 ]

Kater? Eerst water, de rest komt later