I have a WCF Data Services running and JayData as a client. I now want to upload a file en put it in a blob in the database. I created a entity with a binary scalar property and a string property for the file name.
JaySvcUtil creates my JayDataContext.js just fine like this:
$data.Entity.extend('Entities.Plugin', {
'Id': { 'key':true,'type':'Edm.Int32','nullable':false,'computed':true },
'Data': { 'type':'Edm.Binary','nullable':false,'required':true },
'FileName': { 'type':'Edm.String','nullable':false,'required':true }
});
Does anybody know how to upload a file to WCF Data Service using Javascript?
Thank you
The Data field can be field can be set with Base64 string - JayData 1.3 might offer other options, but the base64 is the way to go with the current stable version (1.2.7).
You can use HTML5 File API to get the Base64 string from your local file.
I hope this helps! Let me know about your results.
Related
I'm building a website using Next JS and Sanity for the CMS. Sanity has built-in schemas for images but not for video, so a video needs to be uploaded with the File schema. The docs suggest that to get a file URL to be used on the front-end you should use the query language GROQ to make this conversion at the request like so:
// GROQ query
*[_type == 'movie'] {
title,
"manuscriptURL": manuscript.asset->url
}
But since I am using the File schema to embed short auto-looping videos into rich text content using the Blocks schema, I don't have the luxury of converting URLs at the request and need to do it dynamically as the blocks array data is being parsed for the #portabletext/react component.
Basically, what I get back for the file is simply an asset reference with the following data:
{
"_type": "file",
"asset": {
"_ref": "file-e4e61f3b231cca8e3339e96e050aee428009c777-gif",
"_type": "reference"
}
}
When I then use Sanity's own #sanity/asset-utils package to get a file URL using their buildFileUrl() function, I get a URL that is undefined for that asset where PROJECT_ID and DATASET are the correct values:
https://cdn.sanity.io/files/[PROJECT_ID]/[DATASET]/undefined.undefined
Here is the function I made, using their package's file URL function, to get the asset URL, which returns the URL above with the undefined values:
export function getSanityFileUrl(sanityFile) {
const fileUrl = buildFileUrl(sanityFile.asset, {projectId: sanityConfig.projectId, dataset: sanityConfig.dataset})
console.log(fileUrl)
}
Thanks and anything helps!
I found the solution. The buildFileUrl() function exported by #sanity/asset-utils expects a different asset object. Instead, a user in this situation should use the getFileAsset() function which can accept a reference to the file.
I use an html table where it's content can be changed with mouse drag and drop implemented. Technically, you can move the data from any table cell to another. The table size 50 row * 10 column with each cell given a unique identifier. I want to export it to .xlsx format with C# EPPlus library, and give back the exported file to client.
So I need the pass the whole table data upon a button press and post it to either a web api or an mvc controller, create an excel file (like the original html table data) and send it back to download with browser.
So the idea is to create an array which contains each of table cell's value ( of course there should be empty cells in that array), and post that array to controller.
The problem with that approach lies in the download, if I call the api or mvc controller with regular jquery's ajax.post it did not recognize the response as a file.
C# code after ajax post:
[HttpPost]
public IHttpActionResult PostSavedReportExcel([FromBody]List<SavedReports> savedReports, [FromUri] string dateid)
{
//some excel creation code
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(new MemoryStream(package.GetAsByteArray()))
};
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = dateid + "_report.xlsx"
};
ResponseMessageResult responseMessageResult = ResponseMessage(response);
return responseMessageResult;
}
Usually, for this kind of result I could use window.location = myurltocontroller to download properly , but that is only for GET requests, POST anything is not possible.
I found some answers which could help me in this topic:
JavaScript post request like a form submit
This points out I should go with creating a form, which passes the values, but I do not know how to do so in case of arrays (the table consists 50*10 = 500 values which I have to pass in the form)
I tried some only frontend solutions to the html-excel export problem, which of course does not require to build files on api side, but free jquery add-ins are deprecated, not customizeable, handle only .xls formats, etc.
I found EPPlus nuget package a highly customizeable tool, that is why I want to try this is at first place.
So the question is: how can I post an array of 500 elements, that the controller will recognize, generate the file, and make it automatically download from browser?
If you can provide some code that would be fantastic, but giving me the right direction is also helpful.
Thank you.
You can use fetch() (docs) to send the request from the JS frontend. When the browser (JS) has received the response, it can then offer its binary content as a download. Something like this:
fetch("http://your-api/convert-to-excel", // Send the POST request to the Backend
{
method:"POST",
body: JSON.stringify(
[[1,2],[3,4]] // Here you can put your matrix
)
})
.then(response => response.blob())
.then(blob => {
// Put the response BLOB into a virtual download from JS
if (navigator.appVersion.toString().indexOf('.NET') > 0) {
window.navigator.msSaveBlob(blob, "my-excel-export.xlsx");
} else {
var a = window.document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = "my-excel-export.xlsx";
a.click();
}});
So the JS part of the browser actually first downloads the file behind the scenes, and only when it's done, it's triggering the "download" from the browsers memory into a file on the HD.
This is a quite common scenario with REST APIs that require bearer token authentication.
I'm developing a REST API with Play 2 and I'm wondering how to implement file upload functionality.
I've read the official Play documentation but it just provides a multipart/form-data example, while my backend does not provide any form... it just consists of a REST API to be invoked by a JavaScript client or whatever else.
That said, what's the correct way to implement such an API? Should I implement a PartHandler and then still use the mutipartFormData parser? How should I pass the file content to the API? Is there any exhaustive example on this topic?
Any help would be really appreciated.
You should look into BodyParsers: http://www.playframework.com/documentation/2.2.x/ScalaBodyParsers
What you are trying to do is not especially complicated, especially if you are only handling smaller files that would fit in memory. After all uploading a file is just about sending the file as a body of a POST or something like that. It is not any different from receiving some XML or JSON in a request.
Hope this helps
import org.apache.http.entity.mime._
import java.io.File
import org.apache.http.entity.mime.content._
import java.io.ByteArrayOutputStream
import play.api.libs.ws.WS
val contents ="contents string"
val file = File.createTempFile("sample", ".txt")
val bw = new java.io.BufferedWriter(new java.io.FileWriter(file)
bw.write(new_contents);
bw.close();
builder.addPart("file", new FileBody(file, org.apache.http.entity.ContentType.create("text/plain"), "sample"))
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
val entity = builder.build
val outputstream = new ByteArrayOutputStream
entity.writeTo(outputstream)
val header = (entity.getContentType.getName -> entity.getContentType.getValue)
val response = WS.url("/post/file").withHeaders(header).post(outputstream.toByteArray())
To pass your contents, depending on your client side, you can encode the contents to Base64 at client side to pass the contents as Json (You can use Json body parser). Then on the server side you can decode the contents using a Base64 decoder (e.g. Apache Commons) to get the byte array. It will be as simple as
Base64.decodeBase64(YourEncodedFileContent)
When you have the byte array you can simply write it on disk or save it into database etc. We are using this approach in production and it works fine however we only handle small file uploads.
OK, thank you all for your suggestions... here below is how I solved my issue:
object Files extends Controller {
def upload = SecuredAction[Files.type]("upload").async(parse.multipartFormData(partHandler)) { implicit request =>
future { request.body.files.head.ref match {
case Some((data, fileName, contentType)) => Ok(success(Json.obj("fileName" -> fileName)))
case _ => BadRequest
}}.recover { case e =>
InternalServerError(error(errorProcessingRequest(e.getMessage)))
}
}
...
private def partHandler = {
parse.Multipart.handleFilePart {
case parse.Multipart.FileInfo(partName, fileName, contentType) =>
Iteratee.fold[Array[Byte], ByteArrayOutputStream](
new ByteArrayOutputStream
) { (outputStream, data) =>
outputStream.write(data)
outputStream
}.map { outputStream =>
outputStream.close()
Some(outputStream.toByteArray, fileName, contentType.get)
}
}
}
}
I hope it helps.
while my backend does not provide any form... it just consists of a REST API to be invoked by a JavaScript client
Then your backend is not a REST API. You should follow the HATEOAS principle, so you should respond with links and forms along with data to every GET request. You don't have to send back HTML, you can describe these things with hypermedia json or xml media types, for example with JSON-LD, HAL+JSON, ATOM+XML, etc... So you have to describe your upload form in your preferred hypermedia, and let the REST client to turn that description into a real HTML file upload form (if the client is HTML). After that you can send a multipart/form-data as usual (REST is media type agnostic, so you can send data in any media type you want, not just in a JSON format). Check the AJAX file upload techniques for further detail...
I'm creating an android app which takes in some json data, is there a way to set up a directory such as;
http://......./jsons/*.json
Alternatively, a way to add into a json file called a.json, and extend its number of containing array data, pretty much add more data into the .json file this increase its size.
It could be by PHP or Javascript.
Look into Parsing JSON, you can use the JSON.parse() function, in addition, I'm not sure about getting all your JSON files from a directory call, maybe someone else will explain that.
var data ='{"name":"Ray Wlison",
"position":"Staff Author",
"courses":[
"JavaScript & Ajax",
"Buildinf Facebook Apps"]}';
var info = JSON.parse(data);
//var infostoring = JSON.stringify(info);
One way to add to a json file is to parse it, add to it, then save it again. This might not be optimal if you have large amounts of data but in that case you'll probably want a proper database anyway (like mongo).
Using PHP:
$json_data = json_decode(file_get_contents('a.json'));
array_push($json_data, 'some value');
file_put_contents('a.json', json_encode($json_data));
I am looking to store a JSON file locally on IOS/Android in a Phonegap(Cordova) application.
Basically, I retrieve a JSON file from the server ($.GETJSON) and I want to first store the JSON file and then retrieve and modify it.
I've looked at FileWriter but I don't see a mimetype... the only example gives text files.
Thanks in advance!
Nick
Nick, just use FileWriter.write to save your JSON data to disk. JSON is a text based file anyway so there is no need to set the mime type. When you are ready to load the file again use FileReader.readAsText. In your "onloadend" handler of the FileReader the method will be called with an event and event.target.result will be your JSON data. Then you'll do a
var myJson = JSON.parse(event.target.result);
to turn the text into a JSON object.
(for template or default settings) I just store them in seperate constant files so i don't have to use any special file utility addons or commands, super easy:
(function(){
angular.module('app').constant('settings_json',
{
"name":"settings",
"data":[
{
"set":"globals",
"share_diagnostics":true,
"user_prefs_save_cloud": true
},
{
"set":"user",
"fname":'',
"lname": '',
"telephone": '',
"email": ''
}
]
}
)})();
Then in your app: (after injecting 'settings_json')
var settings = angular.fromJson(settings_json);