Batched Media Upload to Azure Blob Storage through WebApi - javascript

My web app currently allows users to upload media one-at-a-time using the following:
var fd = new FormData(document.forms[0]);
fd.append("media", blob); // blob is the image/video
$.ajax({
type: "POST",
url: '/api/media',
data: fd
})
The media then gets posted to a WebApi controller:
[HttpPost, Route("api/media")]
public async Task<IHttpActionResult> UploadFile()
{
if (!Request.Content.IsMimeMultipartContent("form-data"))
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string mediaPath = await _mediaService.UploadFile(User.Identity.Name, Request.Content);
return Ok(mediaPath);
}
Which then does something along the lines of:
public async Task<string> UploadFile(string username, HttpContent content)
{
var storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer imagesContainer = blobClient.GetContainerReference("container-" + user.UserId);
var provider = new AzureStorageMultipartFormDataStreamProvider(imagesContainer);
await content.ReadAsMultipartAsync(provider);
var filename = provider.FileData.FirstOrDefault()?.LocalFileName;
// etc
}
This is working great for individual uploads, but how do I go about modifying this to support batched uploads of multiple files through a single streaming operation that returns an array of uploaded filenames? Documentation/examples on this seem sparse.
public class AzureStorageMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
private readonly CloudBlobContainer _blobContainer;
private readonly string[] _supportedMimeTypes = { "images/png", "images/jpeg", "images/jpg", "image/png", "image/jpeg", "image/jpg", "video/webm" };
public AzureStorageMultipartFormDataStreamProvider(CloudBlobContainer blobContainer) : base("azure")
{
_blobContainer = blobContainer;
}
public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
{
if (parent == null) throw new ArgumentNullException(nameof(parent));
if (headers == null) throw new ArgumentNullException(nameof(headers));
if (!_supportedMimeTypes.Contains(headers.ContentType.ToString().ToLower()))
{
throw new NotSupportedException("Only jpeg and png are supported");
}
// Generate a new filename for every new blob
var fileName = Guid.NewGuid().ToString();
CloudBlockBlob blob = _blobContainer.GetBlockBlobReference(fileName);
if (headers.ContentType != null)
{
// Set appropriate content type for your uploaded file
blob.Properties.ContentType = headers.ContentType.MediaType;
}
this.FileData.Add(new MultipartFileData(headers, blob.Name));
return blob.OpenWrite();
}
}

Assuming your AzureStorageMultipartFormDataStreamProvider is similar to the same class mentioned on this blog, that is actually already processing multiple files if there are multiple files in the request.
So all you need to do is change your UploadFile to return a IEnumerable<string> and change your controller to have mediaPath as such.
So your MediaService would have:
var filenames = provider.FileData.Select(x => x.LocalFileName).ToList(); ;
return filenames;
And your controller would have:
var mediaPaths = await _mediaService.UploadFile(User.Identity.Name, Request.Content);
return Ok(mediaPaths);

Since you don't post the related codes with the AzureStorageMultipartFormDataStreamProvider class.
So I create a custom AzureStorageMultipartFormDataStreamProvider which inherits from the MultipartFileStreamProvider to enable the web api upload batched uploads of multiple files.
In the AzureStorageMultipartFormDataStreamProvider we could override the ExecutePostProcessingAsync method.
In this method, we could get the upload file data, then we could upload these data to the azure storage.
More details, you could refer to below codes. The total Controller.
public class UploadingController : ApiController
{
public Task<List<FileItem>> PostFile()
{
if (!Request.Content.IsMimeMultipartContent("form-data"))
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var multipartStreamProvider = new AzureStorageMultipartFormDataStreamProvider(GetWebApiContainer());
return Request.Content.ReadAsMultipartAsync<AzureStorageMultipartFormDataStreamProvider>(multipartStreamProvider).ContinueWith<List<FileItem>>(t =>
{
if (t.IsFaulted)
{
throw t.Exception;
}
AzureStorageMultipartFormDataStreamProvider provider = t.Result;
return provider.Files;
});
}
public static CloudBlobContainer GetWebApiContainer(string containerName = "webapi-file-container")
{
// Retrieve storage account from connection-string
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
"your connection string");
// Create the blob client
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(containerName);
// Create the container if it doesn't already exist
container.CreateIfNotExists();
// Enable public access to blob
var permissions = container.GetPermissions();
if (permissions.PublicAccess == BlobContainerPublicAccessType.Off)
{
permissions.PublicAccess = BlobContainerPublicAccessType.Blob;
container.SetPermissions(permissions);
}
return container;
}
}
public class FileItem
{
/// <summary>
/// file name
/// </summary>
public string Name { get; set; }
/// <summary>
/// size in bytes
/// </summary>
public string SizeInMB { get; set; }
public string ContentType { get; set; }
public string Path { get; set; }
public string BlobUploadCostInSeconds { get; set; }
}
public class AzureStorageMultipartFormDataStreamProvider : MultipartFileStreamProvider
{
private CloudBlobContainer _container;
public AzureStorageMultipartFormDataStreamProvider(CloudBlobContainer container)
: base(Path.GetTempPath())
{
_container = container;
Files = new List<FileItem>();
}
public List<FileItem> Files { get; set; }
public override Task ExecutePostProcessingAsync()
{
// Upload the files to azure blob storage and remove them from local disk
foreach (var fileData in this.FileData)
{
var sp = new Stopwatch();
sp.Start();
string fileName = Path.GetFileName(fileData.Headers.ContentDisposition.FileName.Trim('"'));
CloudBlockBlob blob = _container.GetBlockBlobReference(fileName);
blob.Properties.ContentType = fileData.Headers.ContentType.MediaType;
//set the number of blocks that may be simultaneously uploaded
var requestOption = new BlobRequestOptions()
{
ParallelOperationThreadCount = 5,
SingleBlobUploadThresholdInBytes = 10 * 1024 * 1024 ////maximum for 64MB,32MB by default
};
//upload a file to blob
blob.UploadFromFile(fileData.LocalFileName, options: requestOption);
blob.FetchAttributes();
File.Delete(fileData.LocalFileName);
sp.Stop();
Files.Add(new FileItem
{
ContentType = blob.Properties.ContentType,
Name = blob.Name,
SizeInMB = string.Format("{0:f2}MB", blob.Properties.Length / (1024.0 * 1024.0)),
Path = blob.Uri.AbsoluteUri,
BlobUploadCostInSeconds = string.Format("{0:f2}s", sp.ElapsedMilliseconds / 1000.0)
});
}
return base.ExecutePostProcessingAsync();
}
}
The result like this:

I would checkout uploading the media directly to the blob storage after getting the SAS token for all your files from the Web API in one request. Upload the files using a promise and http get from your client, which will parallelize the upload.
Which will be your right design and approach. Which will also increase your upload speed and reduce the latency.

Related

converting a piece of javascript code to c# access API

I need a C# code that will trigger a nprinting task. On our server we are not allowed to evoke html file, hence I can't use javascript attached.
The attached works just need to translate it to .net as I can't use html on our server
Javascripts below works just fine
<html>
<head>
</head>
<body>
<h1>NPrinting API task starter</h1>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script type="text/javascript">
(function(){
console.log("started")
var taskIDs=[
"f3ebd873-b310-4a22-a269-24ce81b8ce74"
]
$.ajax({
url: 'URL:4993/api/v1/login/ntlm',
xhrFields: {
withCredentials: true
}
}).done(function(data) {
console.log(data);
for(var i=0;i<taskIDs.length;i++){
$.ajax({
type: "POST",
url: 'URL:4993/api/v1/tasks/'+taskIDs[i]+'/executions',
xhrFields: {
withCredentials: true
}
}).done(function(data) {
console.log("task "+i);
console.log(data);
if(i==taskIDs.length)
open(location, '_self').close();
});
}
});
})();
<!-- open(location, '_self').close(); -->
</script>
</body>
</html>
C# code which I can't complete all the below works but doesn't start the task.
//Create the HTTP Request (authenticate) and add required headers
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL:4993/api/v1/login/ntlm");
CookieContainer cookies = new CookieContainer();
request.CookieContainer = cookies;
request.Method = "GET";
request.UserAgent = "Windows";
request.Accept = "application/json";
// specify to run as the current Microsoft Windows user
request.UseDefaultCredentials = true;
try
{
// make the web request and return the content
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader responseReader = new StreamReader(response.GetResponseStream());
string sResponseHTML = responseReader.ReadToEnd();
Console.WriteLine(sResponseHTML);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
//Create second HTTP request (get list of apps) and add required headers
HttpWebRequest secondRequest = (HttpWebRequest)WebRequest.Create(#"URL:4993/api/v1/tasks/f3ebd873-b310-4a22-a269-24ce81b8ce74/executions");
//assign cookie to request to maintain session
secondRequest.CookieContainer = cookies;
secondRequest.Method = "POST";
secondRequest.UserAgent = "Windows";
secondRequest.Accept = "application/json";
// specify to run as the current Microsoft Windows user
secondRequest.UseDefaultCredentials = true;
Thanks
I found a solution to the above, request.
Nprinting API task to run from C#
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Post_Request_API
{
class Program
{
static void Main(string[] args)
{
//Create the HTTP Request (authenticate) and add required headers
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(#"URL:4993/api/v1/login/ntlm");
//Assign custom SSL certificate validation method if certificate is untrusted
//request.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
CookieContainer cookies = new CookieContainer();
request.CookieContainer = cookies;
request.Method = "GET";
request.UserAgent = "Windows";
request.Accept = "application/json";
//Specify to run as the current Microsoft Windows user
request.UseDefaultCredentials = true;
try
{
// make the web request and return the content
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader responseReader = new StreamReader(response.GetResponseStream());
string sResponseHTML = responseReader.ReadToEnd();
Console.WriteLine(sResponseHTML);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
//Create second HTTP request to add a new user and required headers
HttpWebRequest secondRequest = (HttpWebRequest)WebRequest.Create(#"URL:4993/api/v1/tasks/f3ebd873-b310-4a22-a269-24ce81b8ce74/executions");
//Assign custom SSL certificate validation method if certificate is untrusted
//secondRequest.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
//Add the XSRF token
secondRequest.Headers.Add("X-XSRF-TOKEN", cookies.GetCookies(request.RequestUri)["NPWEBCONSOLE_XSRF-TOKEN"].Value);
secondRequest.CookieContainer = cookies;
secondRequest.Method = "POST";
secondRequest.UserAgent = "Windows";
secondRequest.Accept = "application/json";
secondRequest.ContentType = "application/json";
//Specify to run as the current Microsoft Windows user
secondRequest.UseDefaultCredentials = true;
//Prepare JSON object to send to the remote server
JsonUser user = new JsonUser();
user.ID = "";
user.type = "";
user.task = "";
user.created = "";
user.lastUpdate = "";
user.completed = "";
user.progress = "";
user.status = "Enqueued";
user.result = "";
user.priority = "";
string jUserString = JsonConvert.SerializeObject(user);
using (var streamWriter = new StreamWriter(secondRequest.GetRequestStream()))
{
streamWriter.Write(jUserString);
streamWriter.Flush();
streamWriter.Close();
}
try
{
HttpWebResponse response2 = (HttpWebResponse)secondRequest.GetResponse();
StreamReader responseReader2 = new StreamReader(response2.GetResponseStream());
string sResponseHTML2 = responseReader2.ReadToEnd();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public class JsonUser
{
public string ID { get; set; }
public string type { get; set; }
public string task { get; set; }
public string created { get; set; }
public string lastUpdate { get; set; }
public string completed { get; set; }
public string progress { get; set; }
public string status { get; set; }
public string result { get; set; }
public string priority { get; set; }
}
}
}

IFormFile Correct Type for Image Uploading?

I have an asp.net core 2 api and I making a method that will accept images(maybe zip files in the future)
I am using a javascript image uplaoder called filepond and I am using IFormFile as the type.
public IActionResult Import(IFormFile filepond)
{
// return BadRequest();
return Ok();
}
It seems to grab data but when I look at what is stored in filepond I see
name = "filepond"
yet the file name I uploaded was like testImage.jpg.
I see the file name seems to be stored in
ContentDisposition = "form-data; name=\"filepond\"; filename=\"testImage.jpg\""
Is this how it should be?
Since nobody has posted the solution, I'll do it... :-)
public IActionResult Import(IFormFile filepond)
{
try
{
var somePath = #"Ё:\Some\Path\";
var filePath = Path.Combine(somePath, filepond.FileName);
var stream = filepond.OpenReadStream();
var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write);
stream.CopyTo(fileStream);
fileStream.Dispose();
}
catch (Exception) {
return BadRequest();
}
return Ok();
}

Akamai CDN Purging of all files in the site

I need to Purge all my Images in my Website which is using AKAMAI CDN.
I have written the code for purging one file.
PFB the code for single file purging.
But my requirement is to purge all files in the website.
Can anyone suggest how to achieve this.
Thanks
//
// © 2016 WorldVentures. All rights reserved.
//
using Akamai.EdgeGrid.Auth;
using Akamai.Utils;
using CMS;
using CMS.DataEngine;
using CMS.DocumentEngine;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
// Registers the custom module into the system
[assembly: RegisterModule(typeof(AkamaiPurge))]
public class AkamaiPurge : Module
{
// Module class constructor, the system registers the module under the name "CustomInit"
public AkamaiPurge()
: base("CustomInit")
{
}
// Contains initialization code that is executed when the application starts
protected override void OnInit()
{
base.OnInit();
// Assigns custom handlers to events
DocumentEvents.Insert.After += Document_Insert_After;
DocumentEvents.Update.After += Document_Update_After;
DocumentEvents.Delete.After += Document_Delete_After;
}
/// <summary>
/// Will be triggered when any document is added
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Document_Insert_After(object sender, DocumentEventArgs e)
{
// PurgeCache();
PurgeCacheAkamai();
}
/// <summary>
/// Will be triggered when any document is Updated
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Document_Update_After(object sender, DocumentEventArgs e)
{
//PurgeCache();
PurgeCacheAkamai();
}
/// <summary>
/// Will be triggered when any document is Deleted
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Document_Delete_After(object sender, DocumentEventArgs e)
{
//PurgeCache();
PurgeCacheAkamai();
}
/// <summary>
/// Following function will invalidate cache from Akamai server
/// </summary>
public void PurgeCache()
{
string secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string clientToken = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string accessToken = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string apiurl = "https://akab-7t5mh54r7lq3a7d7-js5q6mdtx42qimcn.purge.akamaiapis.net/ccu/v3/invalidate/url/production";
List<string> headers = new List<string>();
string httpMethod = "POST";
string data = "{\"hostname\": \"www.qa.worldventures.com\",\"objects\": [\"www.qa.worldventures.com/getmedia/9931b92a-c7f3-4a71-ab27-37e2b13572c0/should-be-here.jpg?width=2541&height=1811&ext=.jpg\"]}";
Stream uploadStream = null;
uploadStream = new MemoryStream(data.ToByteArray());
var uri = new Uri(apiurl);
var request = WebRequest.Create(uri);
request.Method = httpMethod;
var signer = new EdgeGridV1Signer();
var credential = new ClientCredential(clientToken, accessToken, secret);
signer.Sign(request, credential);
using (var result = signer.Execute(request, credential))
{
using (result)
{
using (var reader = new StreamReader(result))
{
string value = reader.ReadToEnd();
}
}
}
}
/// <summary>
/// Following function will invalidate cache from Akamai server
/// </summary>
public void PurgeCacheAkamai()
{
string secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string clientToken = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string accessToken = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string apiurl = "https://akab-7t5mh54r7lq3a7d7-js5q6mdtx42qimcn.purge.akamaiapis.net/ccu/v3/invalidate/url/production";
List<string> headers = new List<string>();
string httpMethod = "POST";
string outputfile = null;
string data = "{\"hostname\": \"www.qa.worldventures.com\",\"objects\": [\"www.qa.worldventures.com/getmedia/9931b92a-c7f3-4a71-ab27-37e2b13572c0/should-be-here.jpg?width=2541&height=1811&ext=.jpg\"]}";
int maxBodySize = 2048;
EdgeGridV1Signer signer = new EdgeGridV1Signer(null, maxBodySize);
ClientCredential credential = new ClientCredential(clientToken, accessToken, secret);
Stream uploadStream = null;
uploadStream = new MemoryStream(data.ToByteArray());
var uri = new Uri(apiurl);
var request = WebRequest.Create(uri);
foreach (string header in headers) request.Headers.Add(header);
request.Method = httpMethod;
Stream output = Console.OpenStandardOutput();
if (outputfile != null)
output = new FileInfo(outputfile).OpenWrite();
signer.Sign(request, credential, uploadStream);
using (var result = signer.Execute(request, credential, uploadStream))
{
using (output)
{
using (result)
{
using (var reader = new StreamReader(result))
{
string value = reader.ReadToEnd();
}
}
}
}
//using (var result = signer.Execute(request, credential))
//{
// using (result)
// {
// using (var reader = new StreamReader(result))
// {
// string value = reader.ReadToEnd();
// }
// }
//}
}
public void PurgeCacheAkamai2()
{
// Create a request using a URL that can receive a post.
WebRequest request = WebRequest.Create("https://akab-7t5mh54r7lq3a7d7-js5q6mdtx42qimcn.purge.akamaiapis.net/ccu/v3/invalidate/url/production");
// Set the Method property of the request to POST.
request.Method = "POST";
// Create POST data and convert it to a byte array.
string postData = "This is a test that posts this string to a Web server.";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Set the ContentType property of the WebRequest.
request.ContentType = "application/x-www-form-urlencoded";
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close();
// Get the response.
WebResponse response = request.GetResponse();
// Display the status.
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
Console.WriteLine(responseFromServer);
// Clean up the streams.
reader.Close();
dataStream.Close();
response.Close();
}
}
It depends on how you want to do it.
For example if you are still using CCU or Fast purge feature of akamai.
If you are using CCU or fast purge then best thing to do is, tag all your images to a dedicated CP Code.
Once done you can purge the CP Code which will intern purge all the images.
Few useful documents that you can refer for CCU:
https://developer.akamai.com/api/purge/ccu-v2/overview.html
For Fast Purge:
https://control.akamai.com/dl/customers/FIMA/Fast-Purge-QuickRef.pdf
https://github.com/akamai-open/api-kickstart/tree/master/examples
Thank,
Vinod

javascript File to java bytes[] with resteasy

I try to upload a file from an angularJS front to a jboss backoffice, but i get this exeption when service is called:
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of byte[] out of START_OBJECT token
at [Source: io.undertow.servlet.spec.ServletInputStreamImpl#1cc8ac9f; line: 1, column: 39] (through reference chain: fr.test.Document["datas"
])
I guess there is something wrong when i convert the javascript File in java bytes[], but i don't really know what.
I collect the file via a regular input type="file":
<input
type="file"
style="display: none;"
onchange="angular.element(this).controller().addDocument(this)"
>
Then i catch result with an onchange method in my controller:
(i read on this link Return the Array of Bytes from FileReader() that i have to use a promise, that's return a bytes array).
...
ctrl.addDocument = function(element){
var file = element.files[0];
var fileData = new Blob([element.files[0]]);
var promise = new Promise(
function(resolve){
var reader = new FileReader();
reader.readAsArrayBuffer(fileData);
reader.onload = function() {
var arrayBuffer = reader.result
var bytes = new Uint8Array(arrayBuffer);
resolve(bytes);
}
}
);
promise.then(function(data) {
var document = {
name: file.name,
type: file.type,
datas: data
};
console.dir(document);
ctrl.doc = document;
}).catch(function(err) {
console.log(err);
growl.error('Unable to upload file');
});
}
...
Finally, backoffice is called, using a rest service. Here the declaration of my backoffice's service:
#POST
#Path("/uploadFile")
#Consumes(MediaType.APPLICATION_JSON)
public void uploadFile(Document document) {
LOGGER.info("upload document !");
}
And the document object that contains same properties:
public class Document {
private byte[] datas;
private String name;
private String type;
public byte[] getDatas() {
return datas;
}
public void setDatas(byte[] datas) {
this.datas = datas;
}
...
If i comment the line "ctrl.doc = document;" in my controller (the bytes part), service work correctly.
What i missed ? Can i really send a file this way ?

File upload with ember-upload, how to fill request with additional data for servicestack?

For introduction, I have problem with communication between servicestack and application written in ember.js via REST, I am using ember-uploader component to upload a file to service stack.
View hbs:
<table class="table table-bordered table-hover">
{{file-upload}}
</table>
component in coffee script
ABC.FileUploadComponent = Ember.FileField.extend(
url: "/api/upload"
filesDidChange: (->
uploadUrl = #get("url")
console.log uploadUrl
files = #get("files")
test = { fileName: "test" }
uploader = Ember.Uploader.create(
url: uploadUrl
)
uploader.upload(files[0],test) unless Ember.isEmpty(files)
console.log files
return
).observes("files")
)
component in javascript
ABC.FileUploadComponent = Ember.FileField.extend({
url: "/api/upload",
filesDidChange: (function() {
var files, test, uploadUrl, uploader;
uploadUrl = this.get("url");
console.log(uploadUrl);
files = this.get("files");
test = {
fileName: "test"
};
uploader = Ember.Uploader.create({
url: uploadUrl,
data: test
});
if (!Ember.isEmpty(files)) {
uploader.upload(files[0], test);
}
console.log(files);
}).observes("files")
});
My service model:
namespace ABC.Service.ServiceModel
{
public class Upload
{
[Route("/upload")]
public class UploadRequest : IRequiresRequestStream
{
public System.IO.Stream RequestStream { set; get; }
public object FileName { set; get; }
}
public class UploadResponse
{
public int Successed { set; get; }
}
}
}
My Service Method
namespace ABC.Service.Service
{
public class UploadService : ServiceBase // Service base inherites from ServiceStack.Service
{
public Upload.UploadResponse Post(Upload.UploadRequest request)
{
var req = base.Request;
var reqThatIwant = request.FileName;
return new Upload.UploadResponse() { Successed = 1 };
}
}
}
and here is screen from watch :
So my question is, how I have to change the code to get data marked as "2" into Request object marked as "1" (marked on the screen)?
Handling Raw Request Stream
When you use IRequiresRequestStream you're saying you want to take over deserializing the Request and access the raw input HTTP Request Body as a Stream. As a result ServiceStack wont attempt to read from the Request body and instead inject the HTTP Request stream - in this case the only Request DTO parameters it will be able to populate are those on the /pathinfo or ?QueryString, e.g:
[Route("/upload/{FileName}")]
public class Upload : IRequiresRequestStream
{
public Stream RequestStream { set; get; }
public string FileName { set; get; }
}
Accessing FormData HTTP POSTs
But if the JavaScript component is sending you HTTP POST FormData (i.e. application/x-www-form-urlencoded or multipart/form-data) than it's very unlikely you want to treat it like a raw Request Stream but instead access the Request.FormData or Request.Files that were posted.
Handling File Upload examples
Based on your screenshot, the HTTP Request Content-Type is multipart/form-data which case you will most likely be able to access any uploaded files using Request.Files.
Some examples of accessing HTTP Uploaded Files are available in the Live Demos:
Imgur - Save uploaded files to a MemoryStream
public object Post(Upload request)
{
foreach (var uploadedFile in Request.Files
.Where(uploadedFile => uploadedFile.ContentLength > 0))
{
using (var ms = new MemoryStream())
{
uploadedFile.WriteTo(ms);
WriteImage(ms);
}
}
return HttpResult.Redirect("/");
}
Rest Files - Save to FileSystem
public void Post(Files request)
{
var targetDir = GetPath(request);
var isExistingFile = targetDir.Exists
&& (targetDir.Attributes & FileAttributes.Directory) != FileAttributes.Directory;
if (isExistingFile)
throw new NotSupportedException(
"POST only supports uploading new files. Use PUT to replace contents of an existing file");
if (!Directory.Exists(targetDir.FullName))
Directory.CreateDirectory(targetDir.FullName);
foreach (var uploadedFile in base.Request.Files)
{
var newFilePath = Path.Combine(targetDir.FullName, uploadedFile.FileName);
uploadedFile.SaveTo(newFilePath);
}
}
HTTP Benchmarks - Handle multiple and .zip uploaded files
public object Post(UploadTestResults request)
{
//...
foreach (var httpFile in base.Request.Files)
{
if (httpFile.FileName.ToLower().EndsWith(".zip"))
{
using (var zip = ZipFile.Read(httpFile.InputStream))
{
var zipResults = new List<TestResult>();
foreach (var zipEntry in zip)
{
using (var ms = new MemoryStream())
{
zipEntry.Extract(ms);
var bytes = ms.ToArray();
var result = new MemoryStream(bytes).ToTestResult();
zipResults.Add(result);
}
}
newResults.AddRange(zipResults);
}
}
else
{
var result = httpFile.InputStream.ToTestResult();
newResults.Add(result);
}
}
}

Categories

Resources