2 Replies Latest reply on Sep 18, 2017 5:28 AM by Harshit Choudhary

    Publish Datasource with REST API in .Net

    Patrick Abernathy

      Good afternoon all.  I'm trying to publish a tdsx datasource using the REST API but am having difficulty getting it to go through.  I'm continuiously getting a 400 error and using the error log files, it's returning due to the exception "Error opening archive C:\ProgramData\Tableau\Tableau Server\data\tabsvc\temp\333333 - CBv2.tdsx3255791622509296634.tmp".  333333 - CBv2.tdsx being my packaged datasource.  In all the documentation I'm seeing, the body of the request shows the tdsx file being sent as a binary data stream.  Everything that I've tried has not been able to get the file to the server.  Any suggestions on how to place the stream into the Body of the request?  Using C# and I've tried just about every converter on the byte[] that I know of.  I'm building the body into a string to pass to my wrapper for the Tableau API's.  The variable datasource below is the one giving me an issue.  Thank you for your time.

       

       

      var datasourceBytes = File.ReadAllBytes(Path.Combine(siteFolder, insightsApiModel.SiteId + " - CBv2.tdsx"));
      
      tableauApi.UploadDatasource(projectId, insightsApiModel.SiteId, string.Concat(datasourceBytes.Select(b => Convert.ToString(b, 2).PadLeft(8,'0'))), insightsApiModel.SiteId + " - CBv2.tdsx");
      odel.SiteId, string.Concat(datasourceBytes.Select(b => Convert.ToString(b, 2).PadLeft(8,'0'))), insightsApiModel.SiteId + " - CBv2.tdsx");
      

       

      public void UploadDatasource(string projectId, string siteId, string datasource, string datasourcePath)
      {
          var boundryString = Guid.NewGuid().ToString().Replace("-", string.Empty);
          var endPoint = "sites/{siteId}/datasources?overwrite=true";
          var body =
              "--" + boundryString + "\r\n" +
              "Content-Disposition: name=\"request_payload\"\r\n" +
              "Content-Type: text/xml\r\n\r\n" +
              "<tsRequest>\r\n" +
              "  <datasource name=\"" + siteId + " - CBv2\" >\r\n" +
              "    <connectionCredentials name=\"" + ConfigurationHelper.InsightsUser + "\" password=\"" + ConfigurationHelper.InsightsPassword + "\" /> \r\n" +
              "    <project id=\"" + projectId + "\" />\r\n" +
              "  </datasource>\r\n" +
              "</tsRequest>\r\n" +
              "\r\n--" + boundryString + "\r\n" +
              "Content-Disposition: name=\"tableau_datasource\"; filename=\"" + datasourcePath + "\"\r\n" +
              "Content-Type: application/octet-stream\r\n\r\n" +
              datasource + "\r\n\r\n" +
              "--" + boundryString + "--";
      
          var client = new TableauRestClient(endPoint, HttpVerb.POST, body, "multipart/mixed; boundary=" + boundryString);
          client.MakeRequest(HttpStatusCode.Created);
      }
      
      
        • 1. Re: Publish Datasource with REST API in .Net
          Patrick Abernathy

          Finally figured this one out so figured I'd post in case someone else needed an answer to this.  Header has to be broken up from the file being imported.  Code snippet on how to put everything together below.

           

          var headerBytes = Encoding.UTF8.GetBytes(header).ToList();
          var datasourceBytes = File.ReadAllBytes(filePath).ToList();
          var newlineBytes = Encoding.UTF8.GetBytes("\r\n").ToList();
          var endBytes = Encoding.UTF8.GetBytes("--" + boundary + "--").ToList();
          
          var bytes = headerBytes.Concat(datasourceBytes).Concat(newlineBytes).Concat(endBytes).ToArray();
          request.ContentLength = bytes.Length;
          
          
          • 2. Re: Publish Datasource with REST API in .Net
            Harshit Choudhary

            Hello Patrick,

             

            I am new to Tableau and struggling to submit datasource to tableau. Is it possible for you to provide me complete working sample that you done instead of code snippet?