I am trying to set the thumbnail for a pull video upload done through the vimeo api. I am developing this for a c# windows service and please note that there are no official libraries for this. For the moment I use this library. I am able to successfully upload the video by following the vimeo documentation, however, when I try to upload an image to be the thumbnail of a video I get an issue. According to the vimeo picutre upload documentation, in step 2, i need to upload my thumbnail image via a PUT request. It says, that I need to do the following:
PUT https://i.cloud.vimeo.com/video/518016424
.... binary data of your file in the body ....
I can't figure out how to do this. I can get the binary data of the image by using
byte[] byte_array_of_image = File.ReadAllBytes(file);
but how can I send this data to the api and get a response (with or without using the library)? If it would help, here is my code to upload the video and thumbnail done so far.
var vc = VimeoClient.ReAuthorize(
accessToken: ConfigurationManager.AppSettings["ACCESS_TOKEN"],
cid: ConfigurationManager.AppSettings["API_KEY"],
secret: ConfigurationManager.AppSettings["API_SECRET"]
);
string temporary_video_dir = ConfigurationManager.AppSettings["TEMP_VIDEO_URL"];
Dictionary<string,string> automatic_pull_parameters = new Dictionary<string, string>();
automatic_pull_parameters.Add("type", "pull");
automatic_pull_parameters.Add("link", temporary_video_dir);
var video_upload_request = vc.Request("/me/videos", automatic_pull_parameters, "POST");
string uploaded_URI = video_upload_request["uri"].ToString();
string video_id = uploaded_URI.Split('/')[2];
Library.WriteErrorLog("Succesfully uploaded Video in test folder. Returned Vimeo ID for video: "+ video_id);
var picture_resource_request = vc.Request("/videos/" + video_id + "/pictures", null, "POST");
string picture_resource_link = picture_resource_request["uri"].ToString();
//Library.WriteErrorLog("uri: " + picture_resource_link);
byte[] binary_image_data = File.ReadAllBytes("http://testclient.xitech.com.au/Videos/Images/Closing_2051.jpg");
string thumbnail_upload_link = picture_resource_link.Split('/')[4];
Please help! Stuck for hours now.
WebClient has a method called UploadData that fits like a glove. Below there is an example that what you can do.
WebClient wb = new WebClient();
wb.Headers.Add("Authorization","Bearer" +AccessToken);
var file = wb.DownloadData(new Uri("http://testclient.xitech.com.au/Videos/Images/Closing_2051.jpg"));
var asByteArrayContent = wb.UploadData(new Uri(picture_resource_request ), "PUT", file);
var asStringContent = Encoding.UTF8.GetString(asByteArrayContent);
reference post:- Vimeo API C# - Uploading a video
the answer is not upvoted but it could be tried worked well in my case.
see the code below:-
public ActionResult UploadChapterVideoVimeo(HttpPostedFileBase file, string productID = "")
{
if (file != null){
var authCheck = Task.Run(async () => await vimeoClient.GetAccountInformationAsync()).Result;
if (authCheck.Name != null)
{
BinaryContent binaryContent = new BinaryContent(file.InputStream, file.ContentType);
int chunkSize = 0;
int contenetLength = file.ContentLength;
int temp1 = contenetLength / 1024;
if (temp1 > 1)
{
chunkSize = temp1 / 1024;
chunkSize = chunkSize * 1048576;
}
else
{ chunkSize = chunkSize * 1048576; }
binaryContent.OriginalFileName = file.FileName;
var d = Task.Run(async () => await vimeoClient.UploadEntireFileAsync(binaryContent, chunkSize, null)).Result;
vmodel.chapter_vimeo_url = "VIMEO-" + d.ClipUri;
}
return RedirectToAction("ProductBuilder", "Products", new { productId = EncryptedProductID, message = "Successfully Uploaded video", type = 1 });
}
}
catch (Exception exc)
{
return RedirectToAction("ProductBuilder", "Products", new { productId = EncryptedProductID, message = "Failed to Uploaded video " + exc.Message, type = 0 });
}
}
return null; }
Related
I'm trying to upload the Image on Firebase Storage but I face some problems with it.
ar storage = StorageClient.Create();
string studentImageRef = bucket + 33333 + ".jpg";
var obj = storage.GetObject(studentImageRef, studentImageRef);
var downloadUrl = obj.MediaLink;
await storage.UploadObjectAsync(obj, null, new UploadObjectOptions { PredefinedAcl = PredefinedObjectAcl.PublicRead });
// Add the download URL to the student's information
studentsInfo.ImageUrl = downloadUrl;
This is the error I encountered.
Error: The service storage has thrown an exception. HttpStatusCode is NotFound. The specified bucket does not exist
And yes I tried several times and make sure the bucket name is correct but the error still persists.
I figured how to fix this problem using this codes
/ Convert image to stream
var stream = new MemoryStream();
imageFile.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
stream.Position = 0;
// Initialize Google Cloud Storage
var storage = StorageClient.Create();
string studentImageRef = "my-bucket.appspot.com/" + Lname_FnameGetter + ".jpg";
await storage.UploadObjectAsync("my-bucket.appspot.com/", studentImageRef, "image/jpeg", stream, new UploadObjectOptions { PredefinedAcl = PredefinedObjectAcl.PublicRead });
// Get the download URL for the image
var obj = storage.GetObject("my-bucket.appspot.com", studentImageRef);
var downloadUrl = obj.MediaLink;
// Add the download url to the student's information
studentsInfo.ImageUrl = downloadUrl;
The ff. codes i provide solve the problem.
I'm Learning Blazor + WEB API. In the client project, I get all the data from the server into the view, except for the image.
Failed to load resource: the server responded with a status of 404 ()
It's my file upload service:
public async Task<string> UploadFile(Stream msFile, string pictureName)
{
var path = $"{_env.WebRootPath}\\images\\{pictureName}";
var buffer = new byte[4 * 1096];
int bytesRead;
double totalRead = 0;
using FileStream fs = new FileStream(path, FileMode.Create);
while ((bytesRead = await msFile.ReadAsync(buffer)) != 0)
{
totalRead += bytesRead;
await fs.WriteAsync(buffer);
}
var url = $"{_httpContextAccessor.HttpContext.Request.Scheme}://{_httpContextAccessor.HttpContext.Request.Host.Value}/";
var fullPath = $"{url}images/{pictureName}";
return fullPath;
}
My razor component
#foreach (var prod in item.Products)
{
<img class="d-block w-100" style="border-radius:20px;"
src="#prod.Image">
}
GitHub https://github.com/ValencyJacob/PharmacyStore
The image value you set below is just the name, but I find your stored static file and client are located in different project:
var pictureName = $"{pictureId}{ext}";
await _fileUpload.UploadFile(msFile, pictureName);
Model.Image = pictureName;
You need set the value with the full path(e.g: The Image value should be setted like : https://localhost:44375/images/04c91d389a8946d7b741b5a11eb73cfc.jpg):
var pictureName = $"{pictureId}{ext}";
var fullpath = await _fileUpload.UploadFile(msFile, pictureName);
Model.Image = fullpath;
Then you could display the images(store in PharmacyStore.UI) in another project(Client.WASM).
Note:
The port number(44375) should belong to the project which store the static file(PharmacyStore.UI).
I am trying to create a .Net Standard "Client" class for uploading (sometimes very large) files to a Controller. I want to do this by breaking the file into chunks and uploading them one at a time. The intent is for other applications to use this instead of communicating directly to the Web Api.
I already have the Controller working. I've verified that it works using a Kendo-ui control which supports chunk-saving.
The issue I am having is that the IEnumerable<IFormFile> files parameter for my controller is always empty when posted from my client class
Controller
[Route("api/Upload")]
public ActionResult ChunkSave(IEnumerable<IFormFile> files, string metaData, Guid id)
{
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(metaData));
var serializer = new DataContractJsonSerializer(typeof(ChunkMetaData));
ChunkMetaData somemetaData = serializer.ReadObject(ms) as ChunkMetaData;
// The Name of the Upload component is "files"
if (files != null)
{
// If this is the first chunk, try to delete the file so that we don't accidently
// and up appending new bytes to the old file.
if (somemetaData.ChunkIndex == 0)
{
_io.DeleteFile(id, Path.GetFileName(somemetaData.FileName));
}
foreach (var file in files)
{
// Some browsers send file names with full path. This needs to be stripped.
_io.AppendToFile(id, Path.GetFileName(somemetaData.FileName), file.OpenReadStream());
}
}
FileResult fileBlob = new FileResult();
fileBlob.uploaded = somemetaData.TotalChunks - 1 <= somemetaData.ChunkIndex;
fileBlob.fileUid = somemetaData.UploadUid;
return new JsonResult(fileBlob);
}
Client:
public class FileTransferClient
{
HttpClient Client { get; set; }
public FileTransferClient(Uri apiUrl)
{
this.Client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true })
{
BaseAddress = apiUrl
};
this.Client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<bool> UploadFile(Guid id, Stream file, string name, string contentType)
{
bool ret = true;
int chunckSize = 2097152; //2MB
int totalChunks = (int)(file.Length / chunckSize);
if (file.Length % chunckSize != 0)
{
totalChunks++;
}
for (int i = 0; i < totalChunks; i++)
{
long position = (i * (long)chunckSize);
int toRead = (int)Math.Min(file.Length - position + 1, chunckSize);
byte[] buffer = new byte[toRead];
await file.ReadAsync(buffer, 0, toRead);
MultipartFormDataContent content = new MultipartFormDataContent();
content.Add(new StringContent(id.ToString()), "id");
var meta = JsonConvert.SerializeObject(new ChunkMetaData
{
UploadUid = id.ToString(),
FileName = name,
ChunkIndex = i,
TotalChunks = totalChunks,
TotalFileSize = file.Length,
ContentType = contentType
});
content.Add(new StringContent(meta), "metaData");
using (var ms = new MemoryStream(buffer))
{
content.Add(new StreamContent(ms),"files");
var response = await Client.PostAsync("/api/Upload", content).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
ret = false;
break;
}
}
}
return ret;
}
}
Your param is empty, because you're not sending an array of files, but rather just one file. Therefore, the binding fails, and you get a null. The act of chunking (which you aren't actually even doing) does not equate to an IEnumerable<IFormFile>; it's still just an IFormFile.
While you need to send as multipart/form-data because you're sending both a file upload and some other post data, I think you're misunderstanding what this actually does. It simply means the request body contains multiple different mime-types, it does not mean that it's uploading the file in multiple parts, which seems to be what you're thinking it does.
The actual act of streaming the upload occurs on the server-side. It's about how the server chooses to handle the file being uploaded, and not so much about how the user is uploading it. More specifically, any sort of modelbinding, particular to an IFormFile will cause the file to be spooled to disk first, and then passed into your action. In other words, if you're accepting an IFormFile, you've already lost the battle. It's already been fully transferred from the client to your server.
The ASP.NET Core docs show you how to actually stream the upload, and unsurprisingly there's a fair bit of code involved, none of which you have currently. You basically have to turn modelbinding off entirely on the action and manually parse the request body yourself, being careful to actually chunk the reads from the stream and not do something that will force the entirely thing into memory at once.
The issue was that I was using a StreamContent instead of a ByteArrayContent to represent my file chunks. Here's what I ended up with:
public async Task<Bool> UploadFileAsync(Guid id, string name, Stream file)
{
int chunckSize = 2097152; //2MB
int totalChunks = (int)(file.Length / chunckSize);
if (file.Length % chunckSize != 0)
{
totalChunks++;
}
for (int i = 0; i < totalChunks; i++)
{
long position = (i * (long)chunckSize);
int toRead = (int)Math.Min(file.Length - position, chunckSize);
byte[] buffer = new byte[toRead];
await file.ReadAsync(buffer, 0, buffer.Length);
using (MultipartFormDataContent form = new MultipartFormDataContent())
{
form.Add(new ByteArrayContent(buffer), "files", name);
form.Add(new StringContent(id.ToString()), "id");
var meta = JsonConvert.SerializeObject(new ChunkMetaData
{
UploadUid = id.ToString(),
FileName = name,
ChunkIndex = i,
TotalChunks = totalChunks,
TotalFileSize = file.Length,
ContentType = "application/unknown"
});
form.Add(new StringContent(meta), "metaData");
var response = await Client.PostAsync("/api/Upload", form).ConfigureAwait(false);
return response.IsSuccessStatusCode;
}
}
return true;
}
I am trying to upload a blob created from an image to my server and then convert the blob to an image and save it in a C# webapi. I created a canvas to store my image and the converted it into a base64 file. Below is my javascript code.
var blob = canvas.toDataURL("image/jpeg"); // This will save your image as a
//jpeg file in the base64 format.
var jpegFile64 = blob.replace(/^data:image\/(png|jpeg);base64,/, "");
var jpegBlob = base64ToBlob(jpegFile64, 'image/jpeg');
var data = new FormData();
data.append("mypic", jpegBlob, "thisimage.jpg");
var oReq = new XMLHttpRequest();
oReq.open("POST", "http://localhost:52704/api/uploadfile/myfile.jpg/", true);
oReq.onload = function (oEvent) {
alert(this.responseText);
};
oReq.send(data);
}
function base64ToBlob(base64, mime) {
mime = mime || '';
var sliceSize = 1024;
var byteChars = window.atob(base64);
var byteArrays = [];
for (var offset = 0, len = byteChars.length; offset < len; offset += sliceSize) {
var slice = byteChars.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
return new Blob(byteArrays, { type: mime });
}
Below is my webapi server code in C#. The file is saved as "thisimage.jpg" as appended in my FormData in javascript.
public string Post(string id)
{
string result = null;
var httpRequest = HttpContext.Current.Request;
string count = httpRequest.Files.Count.ToString();
if (httpRequest.Files.Count > 0)
{
var postedFile = httpRequest.Files[0];
var filePath = "c:/inetpub/wwwroot/pics/" + postedFile.Filename;
postedFile.SaveAs(filePath);
// File is saved as "thisimage.jpg"
result = "File saved as " + filePath;
}
else
{
result = "Upload failed";
}
return result;
}
It now works! I had a typo in my postedfile address. So now it works and this is an example of how to upload a blob to a server using Webapi and javascript. I added a string value id to my post and used that to give the file a name.
I have a winforms application that uses Google Drive to manage files. My file upload method is fairly simple:
public static File UploadFile(string sourcefile, string description, string mimeType, int attempt)
{
try
{
string title = Path.GetFileName(sourcefile);
var file = new File {Title = title, Description = description, MimeType = mimeType};
byte[] bytearray = System.IO.File.ReadAllBytes(sourcefile);
var stream = new MemoryStream(bytearray);
FilesResource.InsertMediaUpload request = DriveService.Files.Insert(file, stream, "text/html");
request.Convert = false;
request.Upload();
File result = request.ResponseBody;
return result;
}
catch (Exception e)
{
if(attempt<10)
{
return UploadFile(sourcefile, description, mimeType, attempt + 1);
}
else
{
throw e;
}
}
}
This works, but prior to using Google Drive, I used an FTP solution, which allowed asynchronous upload operations. I would like to include a progress bar when files are uploading, but I can't figure out if there is a way to call InserMediaUpload asynchronously. Do such capabilities exist?
Thank you.
We just announced 1.4.0-beta version earlier today.
1.4.0-beta has a lot of great features including UploadAsync which optionally gets a cancellation token.
Take a look also in our new Media wiki page.
We still don't support an UpdateAsync method, but if you need to update your progress bar you can use the ProgressChanged event. Remember that the default ChunkSize is 10MB, so if you want to get updates after shorter periods, you should change the ChunkSize accordingly.
Be aware, that in the next release of the library, we will also going to support server errors (5xx)
UPDATE (June 2015):
We did add support for UploadAsync more than 2 years ago. Server errors are supported as well using an ExponentialBackoffPolicy.
I know it's late..but Adding a Progress Bar is fairly simple.
Following is a working piece of code for uploading:
public static File uploadFile(DriveService _service, string _uploadFile, string _parent, string _descrp = "Uploaded with .NET!")
{
if (System.IO.File.Exists(_uploadFile))
{
File body = new File();
body.Title = System.IO.Path.GetFileName(_uploadFile);
body.Description = _descrp;
body.MimeType = GetMimeType(_uploadFile);
body.Parents = new List<ParentReference>() { new ParentReference() { Id = _parent } };
byte[] byteArray = System.IO.File.ReadAllBytes(_uploadFile);
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
try
{
FilesResource.InsertMediaUpload request = _service.Files.Insert(body, stream, GetMimeType(_uploadFile));
request.ProgressChanged += UploadProgessEvent;
request.ChunkSize = FilesResource.InsertMediaUpload.MinimumChunkSize; // Minimum ChunkSize allowed by Google is 256*1024 bytes. ie 256KB.
request.Upload();
return request.ResponseBody;
}
catch(Exception e)
{
MessageBox.Show(e.Message,"Error Occured");
}
}
else
{
MessageBox.Show("The file does not exist.","404");
}
}
And
private void UploadProgessEvent(Google.Apis.Upload.IUploadProgress obj)
{
label1.Text = ((obj.ByteSent*100)/TotalSize).ToString() + "%";
// update your ProgressBar here
}