C# .NET
Framework 4.0, Web API, Newtonsoft.Json.dll
I want to send
content file and data to a Web API service, in this case a pdf document and some
metadata about it.
In first time,
I have developed a custom MultipartFormDataStreamProvider
// We implement
MultipartFormDataStreamProvider to override the filename of File which
//
will be stored on server, or else the default name will be of the format like
Body-
//
Part_{GUID}. In the following implementation we simply get the FileName from
//
ContentDisposition Header of the Request Body.
public
class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
public
CustomMultipartFormDataStreamProvider(string path) : base(path)
{}
public
override string GetLocalFileName(HttpContentHeaders headers)
{
return
headers.ContentDisposition.FileName.Replace("\"", string.Empty);
}
///
<summary>
///
Gets the attachment.
///
</summary>
///
<returns></returns>
public
AttachmentModel GetAttachment()
{
try
{
//
This is a custom object.
AttachmentModel attachment = null;
var
key = FormData.AllKeys[0];
var
strings = FormData.GetValues(key);
if
(strings != null)
{
attachment
= JsonConvert.DeserializeObject<AttachmentModel>(strings[0]);
}
return attachment;
}
catch
(Exception ex)
{
return null;
}
}
Then I ‘ve
developed this ApiController:
public class
AttachmentController : ApiController
{
[HttpPost]
[Authorize]
public async
Task<HttpResponseMessage> Post()
{
string
imageFile = null;
FileStream
fileStream = null;
try
{
#region
Check validity
//
Check whether the POST operation is MultiPart?
if
(!Request.Content.IsMimeMultipartContent())
{
return
Request.CreateResponse(HttpStatusCode.OK, "File format not valid.");
}
// This is a folder where we save the
attachment temporarily.
string
documentUploadPath =
System.Configuration.ConfigurationManager.AppSettings["DocumentUploadPath"];
string
root = string.Concat(HostingEnvironment.MapPath("~/"),
documentUploadPath);
CustomMultipartFormDataStreamProvider
provider = new CustomMultipartFormDataStreamProvider(root);
//
Read all contents of multipart message into
CustomMultipartFormDataStreamProvider.
await
Request.Content.ReadAsMultipartAsync(provider);
imageFile
= provider.FileData[0].LocalFileName;
if
(string.IsNullOrEmpty(imageFile))
{
return
Request.CreateResponse(HttpStatusCode.OK, "File not found.");
}
try
{
fileStream
= new FileStream(imageFile, FileMode.Open);
}
catch
{
return
Request.CreateResponse(HttpStatusCode.OK, "Attachment not
recognized.");
}
// This is a custom object.
AttachmentModel
Attachment = provider.GetAttachment();
if
(Attachment == null)
{
return
Request.CreateResponse(HttpStatusCode.OK, "Attachment not
recognized.");
}
MemoryStream
memoryStream = new MemoryStream();
fileStream.CopyTo(memoryStream);
Attachment.Content =
memoryStream.ToArray();
#endregion
//
Other internal consideration and operations.
//
...
var
response = Request.CreateResponse(HttpStatusCode.OK, “OK”;
return
response;
}
catch
(Exception ex)
{
HttpError
httpError = new HttpError {Message = "Internal error."};
return
Request.CreateErrorResponse(HttpStatusCode.InternalServerError, httpError);
}
finally
{
if
(imageFile != null && File.Exists(imageFile))
{
if
(fileStream != null)
{
fileStream.Close();
fileStream.Dispose();
}
File.Delete(imageFile);
}
}
}
Ok. For
testing I have used fiddler with a script like this:
Content-Type:
multipart/form-data; boundary=-------------------------acebdf13572468
Host:
localhost
Connection:
keep-alive
Cache-Control:
max-age=0
Accept:
application/json,
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent:
Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/35.0.1916.153 Safari/537.36
Accept-Encoding:
gzip,deflate,sdch
Accept-Language:
it-IT,en;q=0.8
Content-Length: 225317
Request body:
---------------------------acebdf13572468
Content-Disposition:
form-data; name="fieldNameHere"; filename="test.pdf"
Content-Type:
application/pdf
<@INCLUDE
*C:\temp\test.pdf*@>
---------------------------acebdf13572468
Content-Disposition:
form-data; name="attachment"
{
"IdProtocol": "1",
"application": "TEST",
"filename": "test.pdf"
}
---------------------------acebdf13572468--
It is very important
to close the request with these two minus signs!
Finally a C#
function for calling this web service:
private
bool SendAttachment(AttachmentModel attachment)
{
// This is a custom object.
// AttachmentModel attachment
HttpClient
client = new HttpClient();
using
(var content = new MultipartFormDataContent())
{
var
values = new[]
{
new KeyValuePair<string,
string>("attachment", JsonConvert.SerializeObject(attachment))
};
foreach
(var keyValuePair in values)
{
content.Add(new
StringContent(keyValuePair.Value), keyValuePair.Key);
}
var
fileContent = new ByteArrayContent(attachment.Content);
fileContent.Headers.ContentDisposition
= new ContentDispositionHeaderValue("attachment")
{
FileName
= attachment.NomeFile
};
content.Add(fileContent);
var
requestUri =
"http://localhost/AttachmentManagerService/api/attachment";
var
result = client.PostAsync(requestUri, content);
result.Wait();
if
(result.Result.IsSuccessStatusCode)
{
//
check json format
string
responseContent = result.Result.Content.ReadAsStringAsync().Result;
//
if parse not throw exceptions, deserialize string...
return
true;
}
else
{
return
false;
}
}
}
I hope it is
clear, otherwise if you want to also send me an email.
Kind
regards!