I made a code to get the camera feed in javascript using getusermedia in html5. Now what i want is to send that image to my c# api. I already this a question that is related to this, Sending base64 string to c# server but no luck. So I just want to ask what are the other way to send an image from html5 and javascript to my c# server.
Found an interesting article on this one over at Ode To Code. It shows how to write both the JavaScript and C# code to handle posting the content of an image captured from an HTML5 video element (from the previous blog post) to a C# ASP.NET server. His code is not too difficult to follow. I'd do the Regex a little differently, but it should work for you.
You can 'capture' the current content of a video object by drawing it to an HTML canvas, then convert the content of the canvas to a data: URI that you can post to your C# application.
The fun part is converting that data: URI back into an image, which the Ode To Code article shows you how to do. What you do with it after that is up to you. The O2C code saves it to disk, but you could run it through a MemoryStream and load it into memory using System.Drawing.Image.FromStream or similar.
Second answer, combining the CORS issue, tested locally.
Tested C# code (attribute and ApiController):
[AttributeUsage(AttributeTargets.Method)]
public class AllowReferrerAttribute : ActionFilterAttribute
{
/// <summary>Update headers with CORS 'Access-Control-Allow-Origin' as required</summary>
/// <param name="actionContext">Context of action to work with</param>
public override void OnActionExecuting(HttpActionContext actionContext)
{
var ctx = (System.Web.HttpContextWrapper)actionContext.Request.Properties["MS_HttpContext"];
var referrer = ctx.Request.UrlReferrer;
if (referrer != null)
{
string refhost = referrer.Host;
string thishost = ctx.Request.Url.Host;
if (refhost != thishost)
ctx.Response.AddHeader("Access-Control-Allow-Origin", string.Format("{0}://{1}", referrer.Scheme, referrer.Authority));
}
base.OnActionExecuting(actionContext);
}
}
public class TestController : ApiController
{
[AllowReferrer]
public void Post([FromBody]string value)
{
if (value == null)
throw new HttpResponseException(HttpStatusCode.BadRequest);
if (value.Length > 100000)
throw new HttpResponseException(HttpStatusCode.Forbidden);
}
}
JavaScript code to invoke:
function imgToBase64(img)
{
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL('image/jpeg');
$(canvas).remove();
return dataURL;
}
$.ajax({ url: 'http://localhost:63905/api/Test', type: 'POST', data: "=" + imgToBase64($('img')[0]), crossDomain: true })
To test I copied the above code into the console of a browser with a foreign page (on one of my servers) loaded, where the first image on the page was a nice big one. Data arrives as expected in the value parameter, and returns a 403 error because it's over 100,000 bytes in size.
The tricks are:
You have to have a [FromBody] parameter in your Post handler.
The data passed to the $.ajax call must be a string with an = character at the start. This is just the way things work with ApiController and [FromBody]. The = character will be stripped.
The AllowReferrer attribute will stop your JavaScript code from giving errors when you try to do an AJAX POST to a different site, but that's all. It just stops you reporting back to your JavaScript as to what you did with the data it posted. The POST will generally still be processed by your controller.
If the site you're on fails it's probably because of cross-site scripting headers like x-xss-protection:1; mode=block in the response when the image was served. A lot of sites now set these headers as easy protection against simple DNS poisoning attacks and so on. This will cause an error along the lines of:
SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
If you get that error then you're up against a CORS issue and there's not much you can do about it. If you're working with your own code then it's not a problem, it's when you're trying to grab stuff from other sites that CORS is an issue.
And no, I'm not going to even start telling you how to break CORS. That's not what Stack Overflow is for.
Related
I am developing Asp.Net Core 3.1 API, Everything working as expected when I send a GET request from google chrome, Edge, Postman. But when I send GET request from internet explorer it starts to download a file default.json with the content as the response of GET request.
Defualt Action method:
public IEnumerable<string> Get()
{
return new string[] { "Welcome" };
}
default.json content:
[
"Welcome"
]
I search on the internet but could not find anything useful.
FVI, I have the same observation when I run the API using visual studio or the deployed API on the server using IIS.
IE Version: 11.900.18362.0
So I have to questions.
Does IE not support this, Is this default behavior of IE?
If Yes then how can it be fixed?
This is IE default behavior, and comes down to it simply doesn't know how to treat content with mime types like */json, hence suggest a download.
Assuming this is for users in general, and you simply want to display the json data in a browser, you could convert the content server side to text.
public ContentResult Get()
{
var jsondata = new string[] { "Welcome" };
return Content(JsonSerializer.Serialize(jsondata));
}
If you are going to do something with the actual json data, which one usually does when consuming an api, you will use some kind of client side script (e.g. Ajax as in below sample, or similar) to get the content, and in those cases there won't be any problem, like the one you encountered.
var xhr = new XMLHttpRequest();
xhr.open('GET', '/api/your-method', true);
xhr.onload = function (e) {
if (this.status == 200) {
var jsonstring = this.responseText;
// do something with the json string, e.g. JSON.parse(jsonstring)
}
};
xhr.send();
Here's a couple of posts that suggests to change the registry, though they won't be viable unless it is for a local computer of your own (and if it is, picking a browser that works out-of-the-box must be easier).
Display JSON in IE as HTML Without Download
How can I convince IE to simply display application/json rather than offer to download it?
Edit
As suggested in a comment, yet another option would be to change the mime type explicit:
Json response download in IE(7~10)
So there is a camera taking images every couple seconds and storing those new images with new files names on the server. When a request is made to "mypage", server side the latest images are loaded up and returned in the response. The images subsequently being refreshed with this jQuery code:
(function($) {
$(function() {
var refreshInterval = 5; // Number of seconds between image refreshes
$('#deskshare-grid img').each(function() {
$(this).data('src', $(this).attr('src'));
});
function refreshImages() {
$.get('?r=' + Math.random(), function(response) {
$('#deskshare-grid img').each(function(index) {
$(this).attr('src', $(response).find('#deskshare-grid img').eq(index).attr('src'));
});
setTimeout(refreshImages, refreshInterval * 1000);
});
}
setTimeout(refreshImages, refreshInterval * 1000);
});
})(jQuery);
The jQuery code I shared works and that is great, I didn't write the code and I want to know how it works.
My mind is stuck on the fact that a request was made for the page, the most recent image was retrieved on the server using C# and those images are included in the response. When a more recent image is created, it has a new file name.
How can jQuery refresh the photo for a file name it does not know client side?
Particularly this part of the code is confusing me:
$.get('?r=' + Math.random(), function(response) {
What is the url request for this $.get? I see the network tab of my F12 tools showing the new image responses but I do not understand how an image with a different file name could be requested with jQuery.
UPDATE
The accepted answer is correct but I wanted to elaborate. This jQuery is requesting the entire page again. The HTML response contains new image urls from the server. jQuery is used to parse the response, get the latest image urls and than update the existing HTML content with those new image urls parsed out of the response. This way there is no page flicker by trying to just refresh the entire page.
It does get request to the same page, Math.random() is to make easier to view each request. When you make a request to ? that is the same page.
What is the url request for this $.get?
The first parameter in the $.get is a relative url. This means that the url it's trying to access will be something along the lines of www.yourdomain.com/whatever?r=.
The "?" indicates the start of a query string, the "r" is the start of the request variable and whatever follows the equal sign is the query itself. In this particular case the query is just a randomly generated number that is sent up to the server. Without seeing the server-side code it would appear as if the filename is generated on the client and sent up to the server in this manner, and is probably used to name the file then on the server-side then.
The $.get('?r=' + Math.random(), function(response) { could be this two things:
Its changing the URL as a trick to not to get cached content.
Is server side required as dummy or something that we don't really know.
I recommend to look at the request's and response's headers for each 5'' call.
My MVC3 app uploads documents from the user to our server. I am returning a JsonResult to display any errors, if any:
[HttpPost]
public JsonResult SaveDocument(DocumentModel model, HttpPostedFileBase postedFile)
{
//my wonderful code
return Json(new { success = true, message="ok" });
}
Heres how i submit the request:
var isSubmitting = false;
var addDocumentOptions = {
beforeSubmit: beforeAddDocumentSubmit, // pre-submit callback
success: afterDocumentSubmit // post-submit callback
};
$('#btnCreateDocument').click(function (e) {
e.preventDefault();
$('#divError').html('');
if (!isSubmitting) {
$('#createDocForm').submit();
}
});
This javascript function runs when the upload is complete:
function afterDocumentSubmit(responseText, statusText, xhr, $form) {
if (responseText.success) {
//no errors
} else {
$('#divError').html('Error: ' + responseText.message);
}
}
In FF, Chrome etc., my javascript code runs fine, but in IE, the browser wants to download the Json result as text. I get a download/open file dialog box that shouldnt appear. How do i make IE not download my Json result and behave like the other browsers? Thanks
I ran into a similar problem doing the same in Spring MVC on Java. The problem was that Spring was returning the content-type of the JSON result as application/json, which seems to make IE want to download it. You can try changing the content-type to text/plain; IE won't prompt you to download the file in this case. I suspect that something similar might be happening here.
You could try:
return Json(new { success = true, message = "ok" }, "text/plain");
In response to your new problem: the issue is that responseText is just a string. What you need to do is to convert it into a Javascript Object. You can do it like this:
var response = JSON.parse(responseText);
if(response.success) {
...
}
Most browsers support JSON.parse(). If you're having issues with non-compliant browsers, you can always use the JSON Javascript Library.
Wild guess: you are using the jquery.form plugin which enables you to upload files using AJAX and you haven't read the documentation which states the following:
Browsers that support the XMLHttpRequest Level 2 will be able to
upload files seamlessly and even get progress updates as the upload
proceeds. For older browsers, a fallback technology is used which
involves iframes since it is not possible to upload files using the
level 1 implmenentation of the XMLHttpRequest object. This is a common
fallback technique, but it has inherent limitations. The iframe
element is used as the target of the form's submit operation which
means that the server response is written to the iframe. This is fine
if the response type is HTML or XML, but doesn't work as well if the
response type is script or JSON, both of which often contain
characters that need to be repesented using entity references when
found in HTML markup.
To account for the challenges of script and JSON responses when using
the iframe mode, the Form Plugin allows these responses to be embedded
in a textarea element and it is recommended that you do so for these
response types when used in conjuction with file uploads and older
browsers. Please note, however, that if there is no file input in the
form then the request uses normal XHR to submit the form (not an
iframe). This puts the burden on your server code to know when to use
a textarea and when not to.
Now that you have read it you should take the respective actions if you want your code to work under IE as I have exemplified in this post.
The proper JsonResult return should look like so:
[HttpPost]
public JsonResult SaveDocument(DocumentModel model, HttpPostedFileBase postedFile)
{
...
return Json(new { success = true, message="ok" }, "application/json; charset=utf-8", JsonRequestBehavior.AllowGet);
}
I'm returning some Json via a C# MVC Controller. Other browsers work fine, but Internet Explorer (IE9) tries to Save the returned Json data as a Text file. Any ideas how to keep this from happening?
//MVC Controller Code...
return Json(new { redirectToUrl = Url.Action("Create", "Album",
new { url = url, isLocalFile = isLocalFile})});
//Clientside Javascript Code
$("#uploadImageForm").ajaxForm({
beforeSubmit: function () {
},
success: function (data, textStatus, xhr) {
window.location.href = data.redirectToUrl;
},
error: function (data, textStatus, xhr) {
}
});
I've tried adding "text/plain" and "text/json" to the second argument of the return Json method, it doesn't work.
Many thanks!
Quote from the documentation of the jquery.form plugin:
Browsers that support the XMLHttpRequest Level 2 will be able to
upload files seamlessly and even get progress updates as the upload
proceeds. For older browsers, a fallback technology is used which
involves iframes since it is not possible to upload files using the
level 1 implmenentation of the XMLHttpRequest object. This is a common
fallback technique, but it has inherent limitations. The iframe
element is used as the target of the form's submit operation which
means that the server response is written to the iframe. This is fine
if the response type is HTML or XML, but doesn't work as well if the
response type is script or JSON, both of which often contain
characters that need to be repesented using entity references when
found in HTML markup.
To account for the challenges of script and JSON responses when using
the iframe mode, the Form Plugin allows these responses to be embedded
in a textarea element and it is recommended that you do so for these
response types when used in conjuction with file uploads and older
browsers. Please note, however, that if there is no file input in the
form then the request uses normal XHR to submit the form (not an
iframe). This puts the burden on your server code to know when to use
a textarea and when not to.
This means that if your form contains file input fields and you are submitting this form to a controller action that returns JSON, you must wrap this JSON in a <textarea> tags.
So your response should not look like this:
{ "redirectToUrl":"some url" }
it should look like this:
<textarea>{ "redirectToUrl":"some url" }</textarea>
In order to achieve that you could use a custom action result that will wrap the response with those tags:
public class TextareaJsonResult : JsonResult
{
public TextareaJsonResult(object data)
{
this.Data = data;
}
public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.Response;
bool shouldWrap = !context.HttpContext.Request.IsAjaxRequest();
if (shouldWrap)
{
response.Write("<textarea>");
}
base.ExecuteResult(context);
if (shouldWrap)
{
response.ContentType = "text/html";
response.Write("</textarea>");
}
}
}
and then have your controller action return this custom result:
[HttpPost]
public ActionResult Upload(HttpPostedFileBase file)
{
// ... some processing
var redirectToUrl = Url.Action(
"Create",
"Album",
new { url = url, isLocalFile = isLocalFile }
);
return new TextareaJsonResult(new { redirectToUrl = redirectToUrl });
}
Now obviously in your AJAX success callback you also need to account for this difference by testing the typeof result and in the case of a legacy browser (such as Internet Explorer) manually parse the response. You may take a look at the source code of the page I have linked to.
But this being said, I can see that in your success callback you are redirecting to a controller action contained in the JSON response returned by the server. Here comes my question: What's the point of using AJAX in the first place if you are going to redirect? Why don't you use a standard form post to the controller action and have the controller action directly perform the redirect? AJAX should be used when you want to stay on the same page.
I agree with Jesse's comment, this is probably a duplicate of the link he provided.
As such I'll provide an alternative. I prefer to view json coming over the wire using a http proxy similar to fiddler http://www.fiddler2.com/fiddler2/ . I mention fiddler because it works with all browsers. The advantage is that you get a treeview of the parsed json. It's MUCH easier to read and find what you're looking for.
Also, I believe firebug for firefox, chrome dev tools, and ie dev tool all provide the same functionality. (I know chrome has the treeview, I think I remember firebug having it, and I would be surprised if modern IE doesn't have it considering the other 2 do.)
i want to build a piece of software that will process some html forms, the software will be a kind of bot that will process some forms on my website automatically.
Is there anyone who can give me some basic steps how to do this job...Any tutorials, samples, books or whatever can help me.
Can some of you post an working code with POST method ?
Check out How to: Send Data Using the WebRequest Class. It gives an example of how create a page that posts to another page using the HttpWebRequest class.
To fill out the form...
Find all of the INPUT or TEXTAREA elements that you want to fill out.
Build the data string that you are going to send back to the server. The string is formatted like "name1=value1&name2=value2" (just like in the querystring). Each value will need to be URL encoded.
If the form's "method" attribute is "GET", then take the URL in the "action" attribute, add a "?" and the data string, then make a "GET" web request to the URL.
If the form's "method" is "POST", then the data is submitted in a different area of the web request. Take a look at this page for the C# code.
To expand on David and JP's answers':
Assuming you're working with forms whose contents you're not familiar with, you can probably...
pull the page with the form via an HttpWebRequest.
load it into an XmlDocument
Use XPath to traverse/select the form elements.
Build your query string/post data based on the elements.
Send the data with HttWebRequest
If the form's structure is known in advance, you can really just start at #4.
(untested) example (my XPath is not great so the syntax is almost certainly not quite right):
HttpWebRequest request;
HttpWebResponse response;
XmlDocument xml = new XmlDocument();
string form_url = "http://...."; // you supply this
string form_submit_url;
XmlNodeList element_nodes;
XmlElement form_element;
StringBuilder query_string = new StringBuilder();
// #1
request = (HttpWebRequest)WebRequest.Create(form_url));
response = (HttpWebResponse)request.GetResponse();
// #2
xml.Load(response.GetResponseStream());
// #3a
form_element = xml.selectSingleNode("form[#name='formname']");
form_submit_url = form_element.GetAttribute("action");
// #3b
element_nodes = form_element.SelectNodes("input,select,textarea", nsmgr)
// #4
foreach (XmlNode input_element in element_nodes) {
if (query_string.length > 0) { query_string.Append("&"); }
// MyFormElementValue() is a function/value you need to provide/define.
query_string.Append(input_element.GetAttribute("name") + "=" + MyFormElementValue(input_element.GetAttribute("name"));
}
// #5
// This is a GET request, you can figure out POST as needed, and deduce the submission type via the <form> element's attribute.
request = (HttpWebRequest)WebRequest.Create(form_submit_url + "?" + query_string.ToString()));
References:
Link
http://www.developerfusion.com/forum/thread/26371/
http://msdn.microsoft.com/en-us/library/system.xml.xmlelement.getattribute.aspx
http://msdn.microsoft.com/en-us/library/system.xml.xmlelement.selectnodes.aspx
If you don't want to go the HttpWebRequest route, I would suggest WatiN. Makes it very easy to automate IE or Firefox and not worry about the internals of the HTTP requests.