Txixco
Txixco

Reputation: 3

Use C# to Save an Excel File Contained in a Tableau API Response

I'm trying to download an Excel file from a Tableau view, using a snippet based on this article: Downloading Files with the WebRequest and WebResponse Classes.

WebResponse response = null;
Stream webStream = null;
Stream localStream   = null;
  
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(endPoint);
request.Method = "GET";
request.Headers.Add("X-Tableau-Auth", token);

response = request.GetResponse();
webStream = response.GetResponseStream();

localStream = File.Create("testing.xlsx");
byte[] buffer = new Byte[1024];
int bytesRead;

int bytesProcessed = 0;
do
{
    bytesRead = webStream.Read(buffer, 0, buffer.Length);
    localStream.Write(buffer, 0, bytesRead);
    bytesProcessed += bytesRead;
} while (bytesRead > 0);

response.Close();
webStream.Close();
localStream.Close();

But when I try to open the Excel file it says "Nope, maybe it is corrupt?". The response is a complete Excel file "ready to be saved", which means that it's encoded using UTF-8. Indeed, if I use Postman to do the call, and then save the response, it's saved and opens without any problem.

Before finding the page I said above, I thought the problem was because the response is UTF-8 and the class String is UTF-16. So, I made some testing getting the data from the file generated by Postman and then writing to a new file. The result of the testings: indeed, if the data passes through a String, it's not well saved. Then I tried with that code, and got the same result: fail. I'm pretty sure this code is not using any UTF-16 encoding variable, but maybe I'm wrong.

Anyway, do anyone knows what is my problem with that code, or point me to the right way to accomplish my task? That is, to download a Tableau report to Excel, using the Tableau API.

Thanks in advance.

Upvotes: 0

Views: 513

Answers (1)

Adam
Adam

Reputation: 3867

Unless you're stuck on a particularly old version of .NET, that referenced link is from 2004. The following code will work in .NET 5 / C# 9, and in earlier versions with just some minor tweaking of the using statements. It's showing for Tableau Online, but should work fine for recent versions of Server, if I had to guess. This is sample-grade code, so I would recommend following best practices for the HttpClient if you intend to make this call frequently.

//using System.IO;
//using System.Net.Http;

var token = "your-session-token";
var uri = "https://your-pod.online.tableau.com/api/.../sites/.../views/.../crosstab/excel";
var yourFile = "D:/file/test.xlsx";

using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Add("X-Tableau-Auth", token);
using var response = await client.SendAsync(request);
using FileStream outputFileStream = new FileStream(yourFile, FileMode.Create);
await response.Content.CopyToAsync(outputFileStream);

UPDATE: If you're constrained to WebRequest and non-async methods, you can try the following:

var token = "your-session-token";
var uri = "https://your-pod.online.tableau.com/api/.../sites/.../views/.../crosstab/excel";
var yourFile = "D:/file/test.xlsx";

WebRequest request = WebRequest.Create(uri);
request.Method = "GET";
request.Headers.Add("X-Tableau-Auth", token);

var response = request.GetResponse();
if(((HttpWebResponse)response).StatusCode == HttpStatusCode.OK)
{
    using (Stream dataStream = response.GetResponseStream())
    using (FileStream fileStream = new FileStream(yourFile, FileMode.CreateNew))
    {
        dataStream.CopyTo(fileStream);
    }
}
response.Close();

Upvotes: 0

Related Questions