1. Thomas Rolseth
  2. PowerBuilder
  3. Friday, 10 February 2023 15:40 PM UTC

I need to send very large documents (usually Word) to a SnapDevelop API so that I can upload them into a database table.  The documents are often greater than 30MB.  I initially tried using the SendRequest method.  It worked great until the file size got to around 15MB.  The help indicates that SendRequest (and most other HTTPClient and RESTClient methods) shouldn't be used for large data and so I switched to PostDataStart/PostData/PostDataEnd.

My PB script is below.  I take a word file, read it into a blob, set the content length and then try sending it in chunks.  What I'm unclear about is how to setup and define my controller method in SnapDevelop.  I want to pass a document ID and the chunked blob to the controller so that I can send both to a service method for processing.  What should the arguments for the controller method UploadTest be?  Does PostData put the chunked blob into the response body?  If so, how do I access it in the controller?

The basic framework of my controller method is also included below.

Has anyone used PostData with SnapDevelop?  Any code samples you could share would be much appreciated.

Thanks, Tom

 

ls_url = gs_webapi_url + 'File/UploadTest/674113'

li_filenum = FileOpen('C:\Temp\large.doc', StreamMode!)		
lLen = FileReadEx(li_filenum,blb_roi)
FileClose(li_filenum)	

ls_content_length = string(Len(blb_roi))

Client.SetRequestHeader("Content-Length", ls_content_length)

// send the request
li_rc = client.PostDataStart(ls_url)
IF li_rc = 1 THEN
	// post the data in parts
	li_loop = 0
	do while li_rc = 1
		li_Loop ++
		lblb_PostPart = BlobMid(blb_roi, (li_Loop - 1) * li_PartLen + 1, li_PartLen)
		li_rc = client.PostData(lblb_PostPart, li_PartLen)
	loop
	li_rc = client.PostDataEnd()

	// get results
	ll_StatusCode = client.GetResponseStatusCode()
	ls_StatusText = Client.GetResponseStatusText()
	IF ll_StatusCode = 200 THEN
		MessageBox('Document Upload','OK, Loops = ' + string(li_loop))
	ELSE
		MessageBox('Document Upload', ls_statustext + '~r~n~r~n, Loops = ' + string(li_loop))
	END IF
END IF

DESTROY client

 

        [HttpPost]
        public int UploadTest(string docID)
        {
            return 0;
        }
Francisco Martinez @Appeon Accepted Answer Pending Moderation
  1. Tuesday, 14 February 2023 15:43 PM UTC
  2. PowerBuilder
  3. # 1

Hi Tom,

For sending files back to the client, the way it's usually done is:

 

I'm not very sure how the PB client code is supposed to look like, but the example above results in a file download like you would see on any other website.

 

Regards,
Francisco

Comment
There are no comments made yet.
Thomas Rolseth Accepted Answer Pending Moderation
  1. Monday, 13 February 2023 22:01 PM UTC
  2. PowerBuilder
  3. # 2

Francisco, your controller code above for the upload worked perfectly -- thanks!  What about the flipside?  I also need to retrieve large binary data from the database and stream it back to the client.  I assume ReadData would be appropriate on the client side.  But what about the controller?  I tried the code below but it always throws an exception ("stream does not support reading"). In this case, I'm calling a service to return a byte[] array by reference, writing it to a stream and then copying it to the response body.  Any suggestions?

Thanks, Tom 

 

        [HttpGet]
        public async Task<ActionResult> EventDownloadStream()
        {
            byte[] bFile = null;
            
            //Request.Headers.TryGetValue("EVENT_ID", out var eventID);
            string eventID = "674112";
                                  
            try
            {
                var event_id = Convert.ToInt64(eventID);
                int ret = _documentService.GetEventDownloadStream(event_id, ref bFile);
                                
                var stream = new MemoryStream();
                               
                //write binary data to stream
                stream.Write(bFile, 0, bFile.Length);
                                               
                //assign stream to response body
                await Response.Body.CopyToAsync(stream);
                return StatusCode(StatusCodes.Status201Created, "Event ROI data retrieved successfully");
                                
            }
            catch (Exception ex)
            {
                return NotFound(ex.Message);
            }
            
        }
Comment
There are no comments made yet.
Daryl Foster Accepted Answer Pending Moderation
  1. Saturday, 11 February 2023 03:51 AM UTC
  2. PowerBuilder
  3. # 3

Hi Thomas,

Here is an example I did last year which lets you upload (post) a file and other data as a multi-part form from Powerbuilder and the SnapDevelop API that receives it.  It's likely you could adapt it to your needs. 

https://community.appeon.com/index.php/qna/q-a/problem-passing-xml-to-web-api-using-httpclient

In my Powerbuilder code I just use .SendRequest to sent the multipart blob but I think you could probably do the same thing with your .PostData code.

Also in my example I've just defined the xml file as a string in Powerbuilder and assigned it to the multipart blob, but you would just read your file as you have in your example above and use that as the blob you add to the multipart blob.

My multipart data includes some meta data, but you could just use it to send a single file.  The way I've done it the C# api automatically deserialises the data into it's parts, including the IFormFile which includes metadata about the file (filename etc.)

Good luck,

Daryl.

Comment
There are no comments made yet.
Francisco Martinez @Appeon Accepted Answer Pending Moderation
  1. Friday, 10 February 2023 21:38 PM UTC
  2. PowerBuilder
  3. # 4

Hi Tom,

SnapDevelop is only the name of the IDE. When you create a Web API on SnapDevelop, you're actually just creating an ASP.NET Core Web API. Just an FYI for your future reference (this might help you refine your searches in the future).

That said, I looked online for ways to upload files to an ASP.NET Core API and most of the examples, while offering a lot of flexibility, are a little bit complex and require a deeper insight into C# (See Microsoft's Docs)

I poked around on my own and this is what I came up with:

(I added a couple of lines to help test and debug what the API is receiving)

Request is a property of the Controller that contains the request as it comes from the client, and the blob variable probably is what you want to write into the database.

Hopefully this leads you in the right direction.

 

Regards,
Francisco

Comment
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.