0

I am working on a multi-level ASP.NET MVC web platform and I have the requirement to send a file from a System.Web.Mvc.Controller to an ASP.NET MVC web-service's System.Web.Http.ApiController, running remotely on a different machine.

Currently, I have this in my Mvc.Controller:

public ActionResult ForwardThisFile(HttpPostedFileBase file)
{
    // TODO: Forward file to remote DocumentApi:
    DocumentApi.DocumentApiClient client = new DocumentApi.DocumentApiClient();
    client.StoreDocument(file /* <-- How-To? */);
    return View();
}

where the DocumentApiClient has been generated via Visual Studio's Add REST API Client... function from a Swagger Url. (The generated client internally uses the Microsoft.Rest.ClientRuntime which is relying on System.Net.Http.HttpClient, HttpRequestMessage, etc.)

The question is, how do I define and implement the DocumentApi to transfer files to it in an efficient and generic way in the ApiController. Currently, I am thinking of three different options:

  • [HttpPut] public async Task<IHttpActionResult> StoreDocument(HttpPostedFileBase file)
  • [HttpPut] public async Task<IHttpActionResult> StoreDocument(byte[] fileContents, string contentType, string fileName)
  • [HttpPut] public async Task<IHttpActionResult> StoreDocument(Stream fileStream, string contentType, string fileName)

I was thinking, that maybe I could just forward the HttpPostedFileBase instance from the Mvc.Controller to the ApiController, so I've tried the first option. However, Add REST API Client... creates a DocumentApi.Models.HttpPostedFileBase model class in that case and is NOT of the original type System.Web.HttpPostedFileBase. Now, I'm not sure what I should do...

new DocumentApi.Models.HttpPostedFileBase() {
    InputStream = file.InputStream,
    ContentType = file.ContentType,
    ContentLength = file.ContentLength,
    FileName = file.FileName,
}

^ that doesn't work, because for the InputStream, it creates a DocumentApi.Models.Stream class and I have no idea how to convert the System.IO.Stream from the file parameter into a DocumentApi.Models.Stream.

Is it even possible to send a stream across ASP.NET MVC webservices? (Which would basically be the answer to option 3)

In my current state of knowledge, the only alternative appears to me being option 2, where I would send a byte-array containing the whole file. I am asking myself, however, if there is any more convenient or more efficient way to send a file from a Mvc.Controller to a remote ApiController. Is there?
Which one of the options would work and which one is the way to go?

Additionally, I have a bonus question to the above regarding HttpPostedFileBase: Is the way via HttpPostedFileBase the most efficient way to handle uploaded files in ASP.NET MVC? I have seen various alternatives:

  • HttpPostedFileBase like shown above in the first code sample
  • Using the raw HTTP-request via Request.Content.ReadAsStreamAsync() or something similar. Maybe the stream is more efficient for my use case?
  • Using JavaScript to encode a file into a Base64 string and send it via a hidden input field to the controller. (via FileReader's method readAsDataURL(file))

So many options... Which one is best/most generic/most efficient?

j00hi
  • 5,420
  • 3
  • 45
  • 82
  • Why not use FileStreamResult ? – PhillipH Jul 05 '16 at 09:19
  • `FileStreamResult` is for returning a file, not for sending it to another remote Controller via the method described above, afaik. If there is a way, please describe in more detail! – j00hi Jul 05 '16 at 09:24
  • Don't do that. The proper way is to use the http://www.enterpriseintegrationpatterns.com/patterns/messaging/StoreInLibrary.html pattern. Send the file a an FTP location and the just send a message to the other controller to process the message you sent. – MeTitus Jul 05 '16 at 09:30

1 Answers1

0

You should use the HttpClient lib in the calling controller to async upload the file to the destination controller. Various examples of using HttpClient to asycn upload is here C# HttpClient 4.5 multipart/form-data upload.

In this case your receiving remote controller just acts as though its having a file uploaded from a browser with no specific handling required.

Community
  • 1
  • 1
PhillipH
  • 6,182
  • 1
  • 15
  • 25
  • In this case, I would implement the remote controller's method like option 1: `[HttpPut] public async Task StoreDocument(HttpPostedFileBase file)`, would I? I don't see, however, where the content type goes... there is only `"application/octet-stream"` which is required for the stream, I guess, but I need the actual file's content type as well. – j00hi Jul 05 '16 at 09:40
  • What do you need the encoding for at the receiving end ? – PhillipH Jul 05 '16 at 17:15
  • I need to send the file back some time in the future and therefore, the content type should be correct. – j00hi Jul 05 '16 at 20:43
  • You could just look at the HttpContext.Current Header "Content-Type" within the controller. – PhillipH Jul 06 '16 at 07:29