Reputation: 853
I'm trying to save some data to my database and uploading an image at the same time using a Web Api.
I failed to do this because I cannot send multipart/from and JSON at the same time. I got this error:
request entity's media type 'multipart/form-data' is not supported for this resource.
This is my code:
public IHttpActionResult Post([FromBody]Post userpost)
{
Upload upload = new Upload();
int postid = Convert.ToInt32(postDB.AddPost(userpost));
var filename = postid + "_"+Guid.NewGuid().ToString();
upload.UploadFile(filename, Request);
return Ok(HttpStatusCode.Accepted);
}
public class Upload:IUpload
{
private const string Container = "images";
public async Task<bool> UploadFile(string filename, HttpRequestMessage Request)
{
var accountName = ConfigurationManager.AppSettings["storage:account:name"];
var accountKey = ConfigurationManager.AppSettings["storage:account:key"];
var storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer imagesContainer = blobClient.GetContainerReference(Container);
var provider = new AzureImages(imagesContainer,filename);
try
{
await Request.Content.ReadAsMultipartAsync(provider);
}
catch (Exception ex)
{
return false;
}
if (string.IsNullOrEmpty(filename))
{
return false;
}
return true;
}
}
}
I'm testing it using Postman Thanks in advance.
Upvotes: 0
Views: 1645
Reputation: 6520
create a view model to handle your entire posted information.
public class CombinedPostAndImage
{
/* your post properties */
public intProperty1 { get;set; }
public string Propert2 { get;set; }
...
public string FileName { get; set; }
/* this example is using a Base64String
public string FileBody { get; set; }
}
change your controller action to accept this new type.
public IHttpActionResult Post(CombinedPostAndImage combinedPost)
{
/* create your Post from the combinedPost */
var post = new Post
{
post.Property1 = combinedPost.Property1,
/* more properties */
};
int postid = Convert.ToInt32(postDB.AddPost(userpost));
var filename= string.Format("{0}_{1}", postid, Guid.NewGuid().ToString());
//Convert Base64 Encoded string to Byte Array.
using (var ms = new MemoryStream(Convert.FromBase64String(combinedPost.FileBody)))
{
var uploader = new Upload();
uploader.UploadFile(filename, ms);
}
}
Per you update I would change the UploadFile method to take a stream. Like
public async Task<bool> UploadFile(string filename, Stream uploadStream)
{
var accountName = ConfigurationManager.AppSettings["storage:account:name"];
var accountKey = ConfigurationManager.AppSettings["storage:account:key"];
var storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer imagesContainer = blobClient.GetContainerReference(Container);
CloudBlockBlob blockBlob = imagesContainer.GetBlockBlobReference(filename);
blockBlob.UploadFromStream(uploadStream);
}
I'm not familiar with the Azure SDK, but from the documentation online, you probably want something like this.
I wouldn't tie my Azure uploader to the Request stream. I'd also pass the Upload(er) class to my controller's constructor since it a required dependency that can be satisfied through an IoC container.
Upvotes: 1