Search code examples
c#inno-setuppascalscriptwinhttprequest

How to save to a file the response content of WinHttp.WinHttpRequest.5.1?


I'm writing a script with Inno Setup that call my Web API written in C# that returns

File(bytes, "text/plain", "MyFileName.txt");

I read that ResponseText returns a limited number of chars if is called in synchronous way.

I'm using this code and I receive limited number of chars.

function ActivateLicense(): Boolean;
var
  WinHttpReq: Variant;
  jsonbody: String;
  FStatus: Integer;
  Stream: TFileStream;
  Buffer: string;
  Size: LongInt;
begin
  try
    WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');          
    WinHttpReq.Open('POST', 'http://myweburl', False);
    WinHttpReq.SetRequestHeader('Content-Type', 'application/json');

    jsonbody := '{"ActivationCode":"' + KeyPage.Values[0] + '"}';
    WinHttpReq.Send(jsonbody)
    
    FStatus := WinHttpReq.Status; // 200=OK!
    Result := FStatus=200;

    if Result then
    begin
      Stream := TFileStream.Create(WizardDirValue() + '\license\mylicense.txt', fmCreate);
      try
        Size := WinHttpReq.GetResponseHeader('Content-Length');
        Stream.WriteBuffer(WinHttpReq.ResponseText, Size);
      finally
        Stream.Free;
      end;
    end
      else
    begin
      Log('HTTP Error: ' + IntToStr(WinHttpReq.Status) + ' ' +
          WinHttpReq.StatusText);
          MsgBox(WinHttpReq.ResponseText, mbError, MB_OK);
          Result := False;
    end;
  except
    MsgBox('Something went wrong trying to connect to our servers.', mbError, MB_OK);
    Result := False;
  end;
end;

Can I read ResponseText in async way? Or how can I use the others properties (ResponseBody, ResponseStream) of WinHttp.WinHttpRequest.5.1 to get all content?

[ActionName("activate")]
[HttpPost]
public async Task<IActionResult> Activate([FromBody] ActivateLicenseCommand command)
{
    try
    {
        DirectoryInfo d = new DirectoryInfo(_environment.ContentRootPath + @"/licenses/");

        FileInfo[] files = d.GetFiles("*.lic"); //Getting the files
        if (files.Length != 1)
        {
            return Problem("There is an error with license's file. Please contact support.");
        }

        //Download the file
        using (FileStream fsSource = new FileStream(files[0].FullName,
            FileMode.Open, FileAccess.Read))
        {
            // Read the source file into a byte array.
            byte[] bytes = new byte[fsSource.Length];
            int numBytesToRead = (int)fsSource.Length;
            int numBytesRead = 0;
            while (numBytesToRead > 0)
            {
                // Read may return anything from 0 to numBytesToRead.
                int n = fsSource.Read(bytes, numBytesRead, numBytesToRead);

                // Break when the end of the file is reached.
                if (n == 0)
                    break;

                numBytesRead += n;
                numBytesToRead -= n;
            }
            numBytesToRead = bytes.Length;

            return File(bytes, "text/plain", files[0].Name);
        }
    }
    catch (FileNotFoundException ioEx)
    {
        return Problem(ioEx.Message);
    }
}

The content of the file that I want to send is:

<License>
  <Id>0445e5a4-932a-491b-a59d-e017d8eddc1d</Id>
  <Type>Standard</Type>
  <Expiration>Mon, 21 Nov 2022 13:50:13 GMT</Expiration>
  <Quantity>1</Quantity>
  <LicenseAttributes>
    <Attribute name="generated">2022-10-21 12:50:13Z</Attribute>
    <Attribute name="license">2022-11-21 13:50:13Z</Attribute>
    <Attribute name="updates">2022-11-21 13:50:13Z</Attribute>
    <Attribute name="enableBetaVersions">0</Attribute>
  </LicenseAttributes>
  <Customer>
    <Name>Pippo Pluto</Name>
    <Email>[email protected]</Email>
  </Customer>
  <Signature>MIGHAkEoiobRz2rFP7Jh8jnIdbGA4mCLbyW9TEpf8VfHkPbXP3lFFi7NlS3K5SKsIPvIk90LdvnCyWTLKduMMwCevuflVQJCAIInvKBiPG4pD0vGZcO/am6vPkl5UDSamxRy49EmeMr0Yb7o6Xqm4oqGS+FuY8hET2oYEZw793o53XLiV1DXaD3W</Signature>
</License>

In Inno Script if I read ResponseText I don't receive the last character (>). If I call the Web API from C# method I can read all the content of the file.

For example with :

byte[] fileContent = await response.Content.ReadAsByteArrayAsync();

Solution

  • Imo, your problem is not about reading the response from the server. I think it's the saving the response to the file that is wrong.

    Instead of the WriteBuffer, try my SaveStringToUTF8FileWithoutBOM function from
    Create a UTF8 file without BOM with Inno Setup (Unicode version)

    SaveStringToUTF8FileWithoutBOM(
      WizardDirValue() + '\license\mylicense.txt', WinHttpReq.ResponseText);
    

    Side note: I believe most of your Activate method implementation can be reduced to

    return File(files[0].FullName, "text/plain", files[0].Name);
    

    No need for all that complicated and inefficient code to load whole file to memory only to return it from the method.