I'm trying to handle a JSONP request server side for a form submission ie.
var myJSONP = new Request.JSONP({
url: 'http://mysite.../handlers/FormHandler.ashx',
callbackKey: 'jsoncallback',
data: {
partTag: 'mtvo',
iod: 'hlPrice',
viewType: 'json',
results: '100',
query: 'ipod'
},
onRequest: function(url){
// etc
},
onComplete: function(data){
// etc
}
}).send();
public class FormHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string json = ??
JObject j = JObject.Parse(json);
context.Response.ContentType = "text/json";
context.Response.Write("Hello World");
}
I'm not sure how to deserialize in the ashx ie. I use Json.Net but how to get from context
Do I have to use context.Request to retrieve values individually or can I decode directly from context?
thanks
I am not sure which JSONP you are using, but using MooTools Request.JSON, the data is delivered in context.Request.Form:
?context.Request.Form.ToString()
"partTag=mtvo&iod=hlPrice&viewType=json&results=100&query=ipod"
So you can access each of the form elements in code:
?context.Request.Form["partTag"]
"mtvo"
Based on this, I believe that you will have to assemble the object yourself using the form elements.
To answer your question, yes, you need to use Context.Request to read the data from your client side.
BTW. if you can use RESTful web service instead of implement your own http handler, it will be much easier, RESTful web service which JSON serialize and deserialize is handled by the WCF framework.
Related
In an application I am developing RESTful API and we want the client to send data as JSON. Part of this application requires the client to upload a file (usually an image) as well as information about the image.
I'm having a hard time tracking down how this happens in a single request. Is it possible to Base64 the file data into a JSON string? Am I going to need to perform 2 posts to the server? Should I not be using JSON for this?
As a side note, we're using Grails on the backend and these services are accessed by native mobile clients (iPhone, Android, etc), if any of that makes a difference.
I asked a similar question here:
How do I upload a file with metadata using a REST web service?
You basically have three choices:
Base64 encode the file, at the expense of increasing the data size by around 33%, and add processing overhead in both the server and the client for encoding/decoding.
Send the file first in a multipart/form-data POST, and return an ID to the client. The client then sends the metadata with the ID, and the server re-associates the file and the metadata.
Send the metadata first, and return an ID to the client. The client then sends the file with the ID, and the server re-associates the file and the metadata.
You can send the file and data over in one request using the multipart/form-data content type:
In many applications, it is possible for a user to be presented with
a form. The user will fill out the form, including information that
is typed, generated by user input, or included from files that the
user has selected. When the form is filled out, the data from the
form is sent from the user to the receiving application.
The definition of MultiPart/Form-Data is derived from one of those
applications...
From http://www.faqs.org/rfcs/rfc2388.html:
"multipart/form-data" contains a series of parts. Each part is
expected to contain a content-disposition header [RFC 2183] where the
disposition type is "form-data", and where the disposition contains
an (additional) parameter of "name", where the value of that
parameter is the original field name in the form. For example, a part
might contain a header:
Content-Disposition: form-data; name="user"
with the value corresponding to the entry of the "user" field.
You can include file information or field information within each section between boundaries. I've successfully implemented a RESTful service that required the user to submit both data and a form, and multipart/form-data worked perfectly. The service was built using Java/Spring, and the client was using C#, so unfortunately I don't have any Grails examples to give you concerning how to set up the service. You don't need to use JSON in this case since each "form-data" section provides you a place to specify the name of the parameter and its value.
The good thing about using multipart/form-data is that you're using HTTP-defined headers, so you're sticking with the REST philosophy of using existing HTTP tools to create your service.
I know that this thread is quite old, however, I am missing here one option. If you have metadata (in any format) that you want to send along with the data to upload, you can make a single multipart/related request.
The Multipart/Related media type is intended for compound objects consisting of several inter-related body parts.
You can check RFC 2387 specification for more in-depth details.
Basically each part of such a request can have content with different type and all parts are somehow related (e.g. an image and it metadata). The parts are identified by a boundary string, and the final boundary string is followed by two hyphens.
Example:
POST /upload HTTP/1.1
Host: www.hostname.com
Content-Type: multipart/related; boundary=xyz
Content-Length: [actual-content-length]
--xyz
Content-Type: application/json; charset=UTF-8
{
"name": "Sample image",
"desc": "...",
...
}
--xyz
Content-Type: image/jpeg
[image data]
[image data]
[image data]
...
--foo_bar_baz--
Here is my approach API (i use example) - as you can see, you I don't use any file_id (uploaded file identifier to the server) in API:
Create photo object on server:
POST: /projects/{project_id}/photos
body: { name: "some_schema.jpg", comment: "blah"}
response: photo_id
Upload file (note that file is in singular form because it is only one per photo):
POST: /projects/{project_id}/photos/{photo_id}/file
body: file to upload
response: -
And then for instance:
Read photos list
GET: /projects/{project_id}/photos
response: [ photo, photo, photo, ... ] (array of objects)
Read some photo details
GET: /projects/{project_id}/photos/{photo_id}
response: { id: 666, name: 'some_schema.jpg', comment:'blah'} (photo object)
Read photo file
GET: /projects/{project_id}/photos/{photo_id}/file
response: file content
So the conclusion is that, first you create an object (photo) by POST, and then you send second request with the file (again POST). To not have problems with CACHE in this approach we assume that we can only delete old photos and add new - no update binary photo files (because new binary file is in fact... NEW photo). However if you need to be able to update binary files and cache them, then in point 4 return also fileId and change 5 to GET: /projects/{project_id}/photos/{photo_id}/files/{fileId}.
I know this question is old, but in the last days I had searched whole web to solution this same question. I have grails REST webservices and iPhone Client that send pictures, title and description.
I don't know if my approach is the best, but is so easy and simple.
I take a picture using the UIImagePickerController and send to server the NSData using the header tags of request to send the picture's data.
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"myServerAddress"]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:UIImageJPEGRepresentation(picture, 0.5)];
[request setValue:#"image/jpeg" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"myPhotoTitle" forHTTPHeaderField:#"Photo-Title"];
[request setValue:#"myPhotoDescription" forHTTPHeaderField:#"Photo-Description"];
NSURLResponse *response;
NSError *error;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
At the server side, I receive the photo using the code:
InputStream is = request.inputStream
def receivedPhotoFile = (IOUtils.toByteArray(is))
def photo = new Photo()
photo.photoFile = receivedPhotoFile //photoFile is a transient attribute
photo.title = request.getHeader("Photo-Title")
photo.description = request.getHeader("Photo-Description")
photo.imageURL = "temp"
if (photo.save()) {
File saveLocation = grailsAttributes.getApplicationContext().getResource(File.separator + "images").getFile()
saveLocation.mkdirs()
File tempFile = File.createTempFile("photo", ".jpg", saveLocation)
photo.imageURL = saveLocation.getName() + "/" + tempFile.getName()
tempFile.append(photo.photoFile);
} else {
println("Error")
}
I don't know if I have problems in future, but now is working fine in production environment.
FormData Objects: Upload Files Using Ajax
XMLHttpRequest Level 2 adds support for the new FormData interface.
FormData objects provide a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the XMLHttpRequest send() method.
function AjaxFileUpload() {
var file = document.getElementById("files");
//var file = fileInput;
var fd = new FormData();
fd.append("imageFileData", file);
var xhr = new XMLHttpRequest();
xhr.open("POST", '/ws/fileUpload.do');
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
alert('success');
}
else if (uploadResult == 'success')
alert('error');
};
xhr.send(fd);
}
https://developer.mozilla.org/en-US/docs/Web/API/FormData
Since the only missing example is the ANDROID example, I'll add it.
This technique uses a custom AsyncTask that should be declared inside your Activity class.
private class UploadFile extends AsyncTask<Void, Integer, String> {
#Override
protected void onPreExecute() {
// set a status bar or show a dialog to the user here
super.onPreExecute();
}
#Override
protected void onProgressUpdate(Integer... progress) {
// progress[0] is the current status (e.g. 10%)
// here you can update the user interface with the current status
}
#Override
protected String doInBackground(Void... params) {
return uploadFile();
}
private String uploadFile() {
String responseString = null;
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("http://example.com/upload-file");
try {
AndroidMultiPartEntity ampEntity = new AndroidMultiPartEntity(
new ProgressListener() {
#Override
public void transferred(long num) {
// this trigger the progressUpdate event
publishProgress((int) ((num / (float) totalSize) * 100));
}
});
File myFile = new File("/my/image/path/example.jpg");
ampEntity.addPart("fileFieldName", new FileBody(myFile));
totalSize = ampEntity.getContentLength();
httpPost.setEntity(ampEntity);
// Making server call
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode == 200) {
responseString = EntityUtils.toString(httpEntity);
} else {
responseString = "Error, http status: "
+ statusCode;
}
} catch (Exception e) {
responseString = e.getMessage();
}
return responseString;
}
#Override
protected void onPostExecute(String result) {
// if you want update the user interface with upload result
super.onPostExecute(result);
}
}
So, when you want to upload your file just call:
new UploadFile().execute();
I wanted send some strings to backend server. I didnt use json with multipart, I have used request params.
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public void uploadFile(HttpServletRequest request,
HttpServletResponse response, #RequestParam("uuid") String uuid,
#RequestParam("type") DocType type,
#RequestParam("file") MultipartFile uploadfile)
Url would look like
http://localhost:8080/file/upload?uuid=46f073d0&type=PASSPORT
I am passing two params (uuid and type) along with file upload.
Hope this will help who don't have the complex json data to send.
You could try using https://square.github.io/okhttp/ library.
You can set the request body to multipart and then add the file and json objects separately like so:
MultipartBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("uploadFile", uploadFile.getName(), okhttp3.RequestBody.create(uploadFile, MediaType.parse("image/png")))
.addFormDataPart("file metadata", json)
.build();
Request request = new Request.Builder()
.url("https://uploadurl.com/uploadFile")
.post(requestBody)
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
logger.info(response.body().string());
#RequestMapping(value = "/uploadImageJson", method = RequestMethod.POST)
public #ResponseBody Object jsongStrImage(#RequestParam(value="image") MultipartFile image, #RequestParam String jsonStr) {
-- use com.fasterxml.jackson.databind.ObjectMapper convert Json String to Object
}
Please ensure that you have following import. Ofcourse other standard imports
import org.springframework.core.io.FileSystemResource
void uploadzipFiles(String token) {
RestBuilder rest = new RestBuilder(connectTimeout:10000, readTimeout:20000)
def zipFile = new File("testdata.zip")
def Id = "001G00000"
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>()
form.add("id", id)
form.add('file',new FileSystemResource(zipFile))
def urld ='''http://URL''';
def resp = rest.post(urld) {
header('X-Auth-Token', clientSecret)
contentType "multipart/form-data"
body(form)
}
println "resp::"+resp
println "resp::"+resp.text
println "resp::"+resp.headers
println "resp::"+resp.body
println "resp::"+resp.status
}
As soon as my page loads I would like to make a web request so that its response can be accessed via JavaScript. I have written a c# class that makes the requests to the server. This class is invoked by a controller in my MVC application. I can confirm that the client class is functioning properly & returns a string representation of the JSON.
My question is this. How should I call the controller so that I can use the response in my javascript? The #http.Action simply returns a txt file containing the html of the whole page with the response in the place that i make the call. I would like to instead store this as a variable and maintaining the initial Index view..
Code Bellow has been modified to only include essentials.
Controller
public ActionResult getMeterConfig () {
string scheme = "http";
string host = "*****";
int port = ****;
string dataset = "*****";
string db = "****";
string method = "GET";
var request = new client();
request.setProps(scheme, host, port, dataset, db, method);
request.makeRequest();
var response = request.getResponse();
return Json (response,JsonRequestBehavior.AllowGet);
}
Then to call the controller on page load:
$(window).load(function(){
var json = #Html.Action("actionName","contollerName";
});
EDIT For Clarification
Ive changed the javascript to be :
$(window).load(function () {
$.get('#Html.Action("getMeterConfig", "GetMeterConfig")', function (response) {
var meters = response;
});
});
This returns a download entitled Index.json rather than store the response in the variable meters.
To make this even more peculiar the .json document reads as follows... It includes my index view HTML and substitutes the #Html.Action("getMeterConfig", "GetMeterConfig") with the actual response.
You would make an AJAX request to that controller action. Assuming jQuery, since ASP.NET MVC comes with it:
$(window).load(function(){
$.get('#Url.Action("getMeterConfig", "contollerName")', function (response) {
var json = response;
});
});
So when your client-side page loads, that client-side code would make a separate request to this getMeterConfig action. The JSON returned by that request would be available in the callback function. (I named the variable response but you can call it whatever you like.)
I have a situation where I am accessing an ASP.NET Generic Handler to load data using JQuery. But since data loaded from JavaScript is not visible to the search engine crawlers, I decided to load data from C# and then cache it for JQuery. My handler contains a lot of logic that I don't want to apply again on code behind. Here is my Handler code:
public void ProcessRequest(HttpContext context)
{
JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
string jsonString = string.Empty;
context.Request.InputStream.Position = 0;
using (var inputStream = new System.IO.StreamReader(context.Request.InputStream))
{
jsonString = inputStream.ReadToEnd();
}
ContentType contentType = jsonSerializer.Deserialize<ContentType>(jsonString);
context.Response.ContentType = "text/plain";
switch (contentType.typeOfContent)
{
case 1: context.Response.Write(getUserControlMarkup("SideContent", context, contentType.UCArgs));
break;
}
}
I can call the function getUserControlMarkup() from C# but I will have to apply some URL based conditions while calling it. The contentType.typeOfContent is actually based on URL parameters.
If possible to send JSON data to this handler then please tell me how to do that. I am trying to access the handler like this:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Common.host + "Handlers/SideContentLoader.ashx?typeOfContent=1&UCArgs=cdata");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
But its giving NullReferenceException in Handler code at line:
ContentType contentType = jsonSerializer.Deserialize<ContentType>(jsonString);
A nice way of doing it is to use Routing.
In the Global.asax
protected void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
private void RegisterRoutes(RouteCollection routes)
{
routes.MapHttpHandlerRoute("MyRouteName", "Something/GetData/{par1}/{par2}/data.json", "~/MyHandler.ashx");
}
This is telling ASP.Net to call your handler on /Something/GetData/XXX/YYY/data.json.
You can can access Route Parameters in the handler:
context.Request.RequestContext.RouteData.Values["par1"].
The crawler will parse URLs as long as they are referenced somewhere (i.e. robots file or links)
Not sure why you want to do it, but to add a content to an HTTP request use:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Common.host + "Handlers/SideContentLoader.ashx?typeOfContent=1&UCArgs=cdata");
var requestStream = request.GetRequestStream();
using (var sw = new StreamWriter(requestStream))
{
sw.Write(json);
}
Your Problem is
Load Content into Div using Javascript in ASP.NET using C#.
Visible to Search Engines
My Opinion
When You want Update Partial Page there are some handler or service to communicate between server and client You can Using Ajax for Request to server.
if you use jquery you can try this function jQuery.ajax(); example:
$.ajax({
url:"/webserver.aspx",
data:{id:1},
type:'POST',
success: function(data) {
//do it success function
}
}) ;
Next Step is Generate Web Service in Code behind Your ASP.NET that should be result as JSON or XML format, whatever you use make sure you can parse easily in success function of jQuery.ajax();
Here some Reference for Generate Web Service on ASP.NET
Generate JSON Web Service ASP.NET
Parse Json on Code Behind Parse JSON Code Behind
Generate JSON RESULT and Parse using Client Side Javascript Web Services ASP.NET Json
2.Visible to Search Engine actually
I think if You allow Search engine to Index your page it's no problem , Even if You have some Ajax Code , Search engine will be indexing your page.
I've found this article, I believe this will help you.
http://www.overpie.com/aspnet/articles/csharp-post-json-to-generic-handler
I have a ServiceStack service that compresses the response using RequestContext.ToOptimizedResult(), e.g.:
[Route("/numbers/search")]
public class FindNumbers
{
}
public object Get(FindNumbers query)
{
var data = new List<string> { "One", "Two", "Three" };
return RequestContext.ToOptimizedResult(data);
}
This works perfectly when issuing a request like:
GET http://myhost:13487/numbers/search.json
And is compressed as expected with the Accept-Encoding request header:
Accept-Encoding: gzip,deflate,sdch
I can also issue a JSONP request:
GET http://myhost:13487/numbers/search?callback=func
which correctly returns an application/javascript callback (uncompressed).
THE PROBLEM
When I add the Accept-Encoding request header to the JSONP request, the response is the compressed JSON data as per the original JSON request, and not a compressed application/javascript callback.
Are there any obvious reasons that I'm missing for this behaviour, or is it simply a bug in ServiceStack? My expectation would be to receive a compressed JSONP callback in the response, but I'm fairly green with JSONP and there may be a good reason for the fallback.
Note, I'm in progress of working through the ServiceStack source, but I figured I'd get this out there as more brains are better than one...
Thanks in advance
EDIT
So, I've traced the issue down the following source
https://github.com/ServiceStack/ServiceStack/blob/5d09d439cd1a13712411552e2b3ede5a71af2ee5/src/ServiceStack/Host/Handlers/GenericHandler.cs#L79
and
https://github.com/ServiceStack/ServiceStack/blob/5d09d439cd1a13712411552e2b3ede5a71af2ee5/src/ServiceStack/Host/RestHandler.cs#L107
if (doJsonp && !(response is CompressedResult))
return httpRes.WriteToResponse(httpReq, response, (callback + "(").ToUtf8Bytes(),")".ToUtf8Bytes());
return httpRes.WriteToResponse(httpReq, response);
So if the response is a compressed result, then regardless of the requirement for JSONP via ?callback=func the response will simply contain the compressed json (in the case of the example above), which rings true with my findings above. So it looks like the jsonp callback wrapper needs to be applied earlier in the callstack.
For those that are interested, I solved this by writing a compression plugin that intercepts the response and handles the compression outside of the service method, which is where I believe it should be done. It also addresses the JSONP issue described above.
In my opinion, compression is an orthogonal concern to the service method logic, and moving this outside of the service method as a response filter enables service to service calls to exist with inherent strong typing instead of the ugly public object MyServiceMethod(DtoType request) { } signatures for allowing arbitrary compressed/uncompressed responses. I've taken the assumption here that if the client states a valid Accept-Encoding header then the response will be compressed regardless, which I think is a fair call to make.
For now, I've opted against a pull request to ServiceStack as I see it as a major change in the approach to how the framework handles compression and would require considerable upfront discussion with the owners. This code is purely for demonstrative purposes, but I'm using it and it works very well.
Code:
public class CompressionFeature : IPlugin
{
public void Register(IAppHost appHost)
{
appHost.ResponseFilters.Add((request, response, dto) =>
{
if (dto == null || dto is AuthResponse || dto is CompressedResult || dto is Exception) return;
using (var serializationContext = new HttpRequestContext(request, response, dto))
{
if (!serializationContext.RequestAttributes.AcceptsDeflate && !serializationContext.RequestAttributes.AcceptsGzip) return;
var serializedDto = EndpointHost.ContentTypeFilter.SerializeToString(serializationContext, dto);
var callback = request.GetJsonpCallback();
var isJsonpRequest = EndpointHost.Config.AllowJsonpRequests && !string.IsNullOrEmpty(callback);
if (isJsonpRequest)
{
serializedDto = (callback + "(") + serializedDto + ")";
serializationContext.ResponseContentType = ContentType.JavaScript;
}
var compressedBytes = serializedDto.Compress(serializationContext.CompressionType);
var compressedResult = new CompressedResult(compressedBytes, serializationContext.CompressionType, serializationContext.ResponseContentType);
response.WriteToResponse(compressedResult, serializationContext.ResponseContentType);
}
});
}
}
Register the plugin in your AppHost:
appHost.Plugins.Add(new CompressionFeature());
I'm trying to use a web service that doesn't use SOAP and WSDL but i don't know how to do it. I would really appreciate some pointers.
The API for the service is:
http://someaddress.com/webservices/name/id where id is the parameter.
The supported request method is GET.
Could i use something like this:
var myReq = new XMLHttpRequest();
var url = "http://someaddress.com/webservices/name/2"
myReq.open("GET", url, true);
myReq.send();
The simplest way to get an xml is to use the url as an argument to XDocument.Load() method.
var xml = XDocument.Load("http:...");
This method fetches the data from a remote url, parses it using an XmlReader an constructs an XDocument object. Then you can use LINQ to XML to query or transform data.
Unfortunately, this wouldn't work for POST, DELETE, PUT http requests
Edit:
It depends on your service and what operations you can do with it:
Using XDocument.Load() is the simplest solution. If this is a simple resource over the internet, with no authentication, no HTTp headers needed and supports only GET requests than this is the way to go. You can write a method which take your parameters and appends them in the URL
public SomeClass GetSomeEntity(string id)
{
var xml = XDocument.Load("http://mywebservice.com/ws/" + id);
// transform xml into an instance of actual type
}
Using a WebClient you can get more control over your HttpRequest. You can set basic authentication credentials, append other HTTP headers, POST form-data etc. You have "async" methods also.
using (var client = new WebClient())
{
var xml = XDocument.Load(client.OpenRead("http://yoururl.com");
// process xml
}
You can think of "HttpWebRequest" as a low-level implementation of a web request.
Here is a snipped of code to help you do this..
public static string SendRequest(string uri, string method, string contentType, string body)
{
string responseBody = String.Empty;
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(new Uri(uri));
req.Method = method;
if (!String.IsNullOrEmpty(contentType))
{
req.ContentType = contentType;
}
if (!String.IsNullOrEmpty(body))
{
byte[] bodyBytes = Encoding.UTF8.GetBytes(body);
req.GetRequestStream().Write(bodyBytes, 0, bodyBytes.Length);
req.GetRequestStream().Close();
}
HttpWebResponse resp;
try
{
resp = (HttpWebResponse)req.GetResponse();
}
catch (WebException e)
{
resp = (HttpWebResponse)e.Response;
}
Stream respStream = resp.GetResponseStream();
if (respStream != null)
{
responseBody = new StreamReader(respStream).ReadToEnd();
}
return responseBody;
}
The WebClient object is very well done for those kind of tasks.
Check out the WCF REST Developer Center - it shows you how easily and efficiently you can create REST services (no SOAP) using the WCF infrastructure.
Using JQuery is the simplest as far as I know. Try if this works in your case:
var param = new Object();
param.id = 2;
$.ajax({
type: "GET",
url: "http://someaddress.com/webservices/name",
data: $.toJSON(param),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
if (msg.d) {
//do something
}
}
});