IServiceGateway equivalent for ServiceClientBase.PostFileWithRequest

We currently use the IServiceGateway from an MVC controller to call our API where the DTO is decorated with IRequiresRequestStream. Subsequently we access IRequest.Files to get the contents of the stream.

using (var stream = System.IO.File.OpenRead(fileName))
{
	await base.Gateway.SendAsync(new PublicationUpload()
	{
		Id = publication.Id,
		JobId = job.Id,
		RequestStream = stream
	});
}

This was working up to v6.3 but IRequest.Files is empty with later versions. I created a test case to investigate but this uses JsonServiceClient and not the gateway.

using (var stream = File.OpenRead(fileName))
{
	var response = client.Send(new PublicationUpload
	{
		Id = publication.Id,
		JobId = job.Id,
		RequestStream = stream		
	});
}

I was unable to get this test to pass (asserting that IRequest.Files is not empty) even using v6.3 but it does pass by using PostFileWithRequest instead.

using (var stream = File.OpenRead(fileName))
{
	var response = client.PostFileWithRequest<DataResponse>(stream, "test.txt", new PublicationUpload
	{
		Id = publication.Id,
		JobId = job.Id
	});
}

To update the call from our MVC controller, and allow an upgrade from v6.3, is there an equivalent method to PostFileWithRequest available from the gateway?

Is the a good way to create a JsonServiceClient from the controller which is configured to access the API like the gateway?

The Gateway is only used for sending Request/Response DTOs, not MultiPart Form Data requests.

Where are you accessing IRequest.Files from that is empty now but not before v6.3, in the MVC Controller?

Instead of accessing it from IRequest.Files you can try accessing it from MVC HTTP Request Context in base.Request.Files and load it from there.

In our service class that extends ServiceStack.Service we have the following method to handle the DTO

public async Task<DataResponse> Post(PublicationUpload req)

Then within that we pass Service.Request to a class that validates the upload

public bool IsValidRequest(IRequest req)
{
  return (req.Files != null && req.Files.Length > 0);
}

I see we should pass PublicationUpload.RequestStream for validation which is populated in versions from v6.3 and not be using IRequest.Files which isn’t populated anymore.

We were using IRequiresRequestStream on the dto so we could either; upload a new file or, reuse an existing file from the server. For uploads we set PublicationUpload.RequestStream from HttpPostedFileBase.InputStream and for resuse from a call to File.OpenRead().

I guess something must have changed but we were always relying on an incorrect assumption regarding our use of IRequest.Files.

Not sure if this helps your use case, but we have added the ability to submit MultipartFormDataContent requests through the InProcessGateway which is what you’d use when making in-process API Requests which you can access from:

var gatewayForm = Gateway as IServiceGatewayFormAsync;

await gatewayForm.SendFormAsync(new RequestDto(), formData);

This would let you use the same MultipartFormDataContent that HttpClient’s use to upload files which is supported in .NET 6 JsonApiClient.

Thanks Mythz

I read about MultipartFormDataContent but sadly we aren’t able to deploy .Net 6.0 as yet.

I’ve found some info about IServiceGatewayFormAsync on either of;

Is there a reason this hasn’t been added to Service Gateway? It seems this isn’t specific to Blazor but is only for .Net 6.0?

Right it was initially added to enable FormData requests for Blazor Server but not dependent on it.

But it’s only supported in InProcessGateway and only in .NET 6 builds where HttpClient is included in .NET 6 (i.e. without an external dependency) - using the same HttpClient implementation that the new JsonApiClient uses which includes support for newer HttpClient features such as being able perform safe sync API requests.