JavaScriptSerializer: Any way to send unescaped data? - c#

I wrote a .ToJson() extension method like so:
public static string ToJson(this object obj)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(obj);
}
This allows me to do something like myObject.ToJson() to get a JSON string to send back to my application via my .asmx web service. This all works great.
A problem has arisen where I'm building a page that requires massive amounts of asynchronous data be transferred to the page and I'm starting to reach data payloads of upwards of 100k. In looking at the JSON, I've noticed that it encodes whatever I send back, which adds a lot of extra characters. As this application is an admin tool for a very small audience, I'm not really worried a whole lot about this kind of security, but I can't seem to find it in here how to control encoding.
Here's what I'm receiving (example):
{"d":"[{\"OrderId\":1308,\"Approved\":true,
\"Status\":\"\\u003cimg class=\\\"statusicon\\\" src=\\\"/images/ ...
when I should be getting something like:
{"d": [{"OrderId":1308,"Approved":true,"Status":"<img class=\"statusicon\"
src=\"/images/ ...
Is there any way to control whether or not the JSON data gets escaped?
One thing to note is that I'm forced to use this in my .ajaxSetup() to parse this data coming back:
dataFilter: function (data) {
if (data) {
var msg;
if (typeof (JSON) !== 'undefined' && typeof (JSON.parse) === 'function') {
msg = JSON.parse(data);
} else {
msg = eval('(' + data + ')');
}
if (msg.hasOwnProperty('d')) {
return msg.d;
} else {
return msg;
}
}
}

I had this problem. The json library is not returning escaped text. I believe javascript itself is interpreting it as escaped.
<script type="text/javascript">
$(document).ready(function () {
var columnNumber = 1;
var databaseTypes = <%= Html.Raw(ViewBag.DatabaseTypes) %>;
Take a look at the Viewbag area. This is how to inject text within a asp.net mvc view.

Related

What is the best way to pass data from ASP.NET to AngularJS?

I am using ng-grid in an ASP.NET web application to display data from a WCF Service. In this Plunker example the data is stored in a JSON file and then converted by the Angular module.
var app = angular.module('myApp', ['ngGrid']);
app.controller('MyCtrl', function($scope, $http) {
$scope.setPagingData = function(data, page, pageSize){
var pagedData = data.slice((page - 1) * pageSize, page * pageSize);
$scope.myData = pagedData;
$scope.totalServerItems = data.length;
if (!$scope.$$phase) {
$scope.$apply();
}
};
$scope.getPagedDataAsync = function (pageSize, page, searchText) {
setTimeout(function () {
var data;
if (searchText) {
var ft = searchText.toLowerCase();
$http.get('largeLoad.json').success(function (largeLoad) {
data = largeLoad.filter(function(item) {
return JSON.stringify(item).toLowerCase().indexOf(ft) != -1;
});
$scope.setPagingData(data,page,pageSize);
});
} else {
$http.get('largeLoad.json').success(function (largeLoad) {
$scope.setPagingData(largeLoad,page,pageSize);
});
}
}, 100);
};
$scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);
$scope.gridOptions = {
data: 'myData',
enablePaging: true,
showFooter: true,
enableCellSelection: true,
enableCellEdit: true,
enableRowSelection: false,
totalServerItems:'totalServerItems',
pagingOptions: $scope.pagingOptions,
filterOptions: $scope.filterOptions
};
});
Plunker
This piece of code was interesting because it read dicrectly from a JSON file and dynamically bound it to the ng-grid. I was hoping that I would be able to use the ASP.NET (C#) codebehind to pass a JSON file to the AngularJS code and let it do all of the work to parse it.
It seems like you cannot do this, so what is the best way to pass data to AngularJS from ASP.NET?
Thanks in advance.
The question you're really asking is, how do I pass some server-side information to Javasript? Angular is irrelevant here.
Solution 1: just write it to a client-side variable. Something like:
If you're using MVC:
var myJson = '#ViewBag.MyJson';
var json = JSON.parse(myJson);
If you're using WebForms:
var myJson = '<% Response.Write(MyJson); %>';
var json = JSON.parse(myJson);
Solution 2: define a server-side method that returns your json string, and call it from the client side using Ajax. Then parse it as previously. There's a decent example here.
Solution 3: can't you write to your Json file from the server side, before loading it into Angular?
You could create an Angular directive that handles parsing, and then pass it a JSON file name in your ASP.NET page, like this:
// ASP.NET page
<%
JSONFile.Text = "path/to/json/file.json";
%>
<!DOCTYPE html>
<html>
<head runat="server">
// including our parse-json directive as "metadata" in the head
<parse-json data-json-file="<%JSONFile%>"></parse-json>
</head>
<body>
...
...
</body>
</html>
And then your angular directive could look something like this:
app.directive('parseJson', ['$http', function ($http) {
return {
restrict: 'E',
scope: {
jsonFile: '#'
}
link: function (scope) {
$http.get('my/url/' + scope.jsonFile)
.success(function (data) {
// your parsing logic would go here.
});
}
};
}]);
The data prefix on the data-json-file attribute is the HTML5 standard for custom data attributes.
So, to summarize the code above. In our ASP.NET page we are including a custom tag (our angular directive) named <parse-json> in the <head> of our html page (it doesn't have to be there, but it is sorta metadata so I figured it fit). We are setting the attribute data-json-file to equal the path of the JSON file on our server. When angular loads on the client, it will request this JSON file, and then from there you can do whatever you want with it (in your case, parse it).
Hope this helps!

JSON Data changes while transferring from C# to ExtJS

When transferring JSON data from a Webmethod in asp.net C# through an Ajax call in ExtJS 4.2.2, several characters are added to the beginning and end of the string.
JSON Data before leaving C#:
[{"ID":"0","NAME":"ALAN"},{"ID":"1","NAME":"BLAKE"}]
JSON Data as seen by firebug which is received by ExtJS
{"d":"[{"ID":"0","NAME":"ALAN"},{"ID":"1","NAME":"BLAKE"}]"}
This will also happen if the JSON Data has a set root property.
From what it appears it seems as if something somewhere along the line treated the incoming data as a variable in a JSON string or something like that.
Code on the C# end:
[WebService(Namespace = "localhost")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class Director : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json, UseHttpGet = true, XmlSerializeString = false)]
public string getData()
{
string json = "[{\"ID\":\"0\",\"NAME\":\"ALAN\"},{\"ID\":\"1\",\"NAME\":\"BLAKE\"}]";
System.Diagnostics.Debug.WriteLine(json);
return json;
}
}
Code for the ExtJS Ajax Call (already has a workaround implemented):
Ext.Ajax.request({
async: false,
url: Test061014.ApplicationPath + '/Director.asmx/getData',
headers: { 'Content-Type': 'application/json' },
scope: this,
success: function (conn, response, options, eOpt) {
var s = conn.responseText;
s = s.substring(6, (s.length - 2));
s = s.replace(/\\/g, "");
categoryData = JSON.parse(s);
},
});
That is inserted by ASP.NET for security reasons. Check out this article for more details.
If you aren’t familiar with the “.d” I’m referring to, it is simply a
security feature that Microsoft added in ASP.NET 3.5’s version of
ASP.NET AJAX. By encapsulating the JSON response within a parent
object, the framework helps protect against a particularly nasty XSS
vulnerability.
They have a nice solution of using the dataFilter property so you can stop worrying about .d. Again, credit to the article, here is their solution. You may need to read the article's Don't make me think section as there are a couple of details I left out.
dataFilter: function(data) {
// This boils the response string down
// into a proper JavaScript Object().
var msg = eval('(' + data + ')');
// If the response has a ".d" top-level property,
// return what's below that instead.
if (msg.hasOwnProperty('d'))
return msg.d;
else
return msg;
},

Set a javascript variable from mvc controller

Is it possible to set a javascript variable from a c# controller? We have a situation where we override our master page with a dumb downed version that doesn't require login for users. However, our javascript timeout timer still runs. I would like to in the controller method that overrides the master, to override the timeout to something huge.
public dumbDownController()
{
ViewData["MasterPageOverride"] = "~/Views/Shared/_NoLogin.cshtml";
//Somehow reset that timer below from 20 to like 9999. To simulate no timeout.
return View("Cities", model);
}
Then our javascript file has.
tb.sessionTimer = (function () {
var SESSION_TIMEOUT = 20;
var currentTimeoutCounter = SESSION_TIMEOUT * 60;
...
lots more irrelevant to question
...
}
Large app, so looking to barely change the javascript. Would like to handle it from the controller.
Short Answer:
<script>
var xyz = #ViewData["MasterPageOverride"];
</script>
Longer Answer:
You can't directly assign JavaScript variables in the Controller, but in the View you can output JavaScript which can do the same.
You need to pass the variable to the View somehow. For this example I'll use the ViewData object dictionary. You can set an element in the Controller:
public ActionResult SomeAction()
{
ViewData["aNumber"] = 24;
}
Then in the View it is possible to use it as:
<script>
var xyz = #ViewData["aNumber"];
</script>
Which will be sent to the client browser as:
<script>
var xyz = 24;
</script>
Strings need a bit more attention, since you need to enclose them between '' or "":
<script>
var xyz = "#ViewData["aString"]";
</script>
And as #Graham mentioned in the comments, if the string happens to be valid JSON (or any object literal, but it is very easy to create JSON), and you want to use it as a JavaScript object, you can:
<script>
var xyz = #ViewData["aJsonString"];
</script>
Just make sure the output is valid JavaScript.
On a footnote, be careful with special HTML characters, like < as they are automatically HTML-encoded to prevent XSS attacks, and since you are outputting JavaScript not HTML, this can mess things up. To prevent this, you can use Html.Raw() like:
<script>
var xyz = #Html.Raw(ViewData["aJsonString"]);
</script>
If tb is within the scope of your controller, consider just overriding the sessionTimer function:
public dumbDownController(){
...
tb.sessionTimer = function(){return false;}
}
You have two options (as I understand):
Create the variable from viewbag, data, tempdata, like so:
var SESSION_TIMEOUT = #ViewData["MasterPageOverride"];
var SESSION_TIMEOUT = #ViewBag["MasterPageOverride"];
var SESSION_TIMEOUT = #TempData["MasterPageOverride"];
Or, do it via jQuery AJAX:
$.ajax({
url: '/YourController/YourAction',
type: 'post',
data: { id: id },
dataType: 'json',
success: function (result) {
// setVar
}
});

httpwebrequest posting json incorrectly

Edit: Ok, so it looks like posting as application/json needs to be handled server side separate than a form. Is there any better way to post a form in C# as a complicated object? String:String just doesn't cut it. For example, I want to be able to use Dictionary to produce:
{
"data_map":{"some_value":1,"somevalue":"2"},
"also_array_stuffs":["oh look","people might", "want to", "use arrays"],
"integers_too":4
}
---OP---
I've looked on SO and other places. I'm just trying to POST a JSON string to a URL, but the server side keeps interpreting the content as a string instead of a query dict. We have other clients that aren't in c# that hit the server side fine (in HTML, JS, Objective-C, Java), but for some reason the POST data comes back wonky from the C# client.
C# source:
private static Dictionary<string,object> PostRequest(string url, Dictionary<string, object> vals)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(BaseURL+url);
httpWebRequest.ContentType = "application/json; charset=utf-8";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = JsonFx.Json.JsonWriter.Serialize(vals);
//json = json.Substring(1,json.Length-1);
streamWriter.Write(json);
streamWriter.Close();
}
try
{
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
string response = streamReader.ReadToEnd();
Dictionary<string,object> retval = JsonFx.Json.JsonReader.Deserialize<Dictionary<string,object>>(response);
return retval;
}
}
catch(WebException e)
{
}
return null;
}
This gets called like:
public static void Main (string[] args)
{
Dictionary<string,object> test = new Dictionary<string, object>();
test.Add("testing",3);
test.Add("testing2","4");
Dictionary<string,object> test2 = PostRequest("unitytest/",test);
Console.WriteLine (test2["testing"]);
}
For whatever reason, this is the request object that gets passed though:
<WSGIRequest
GET:<QueryDict: {}>,
POST:<QueryDict: {u'{"testing":3,"testing2":"4"}': [u'']}>,
COOKIES:{},
META:{'CELERY_LOADER': 'djcelery.loaders.DjangoLoader',
'CONTENT_LENGTH': '28',
'CONTENT_TYPE': 'application/json; charset=utf-8',
'DJANGO_SETTINGS_MODULE': 'settings.local',
'GATEWAY_INTERFACE': 'CGI/1.1',
'HISTTIMEFORMAT': '%F %T ',
'HTTP_CONNECTION': 'close',
'LANG': 'en_US.UTF-8',
'QUERY_STRING': '',
'REMOTE_ADDR': '127.0.0.1',
'REMOTE_HOST': '',
'REQUEST_METHOD': 'POST',
'RUN_MAIN': 'true',
'SCRIPT_NAME': u'',
'SERVER_PORT': '9090',
'SERVER_PROTOCOL': 'HTTP/1.0',
'SERVER_SOFTWARE': 'WSGIServer/0.1 Python/2.7.2+',
'SHELL': '/bin/sh',
'SHLVL': '1',
'SSH_TTY': '/dev/pts/0',
'TERM': 'xterm',
'TZ': 'UTC',
'wsgi.errors': <open file '<stderr>', mode 'w' at 0x7f3c30158270>,
'wsgi.file_wrapper': <class 'django.core.servers.basehttp.FileWrapper'>,
'wsgi.input': <socket._fileobject object at 0x405b4d0>,
'wsgi.multiprocess': False,
'wsgi.multithread': True,
'wsgi.run_once': False,
'wsgi.url_scheme': 'http',
'wsgi.version': (1, 0)}>
[18/Oct/2012 19:30:07] "POST /api/1.0/unitytest/ HTTP/1.0" 200 31
Some of the more sensitive data in the request has been removed, but is irrelevant
Ugh, I hope I don't make a habit of answering my own questions.
So, Posting Json this way is different than a normal form submission. That means if your server side is expecting just a normal form submission it will not work. The C# code does as it's intended to do, but only submits a JSON string as the POST body. While this may be convenient for people who validate, clean, and handle raw input anyway, keep in mind that if you're using a normal web framework, you will have to write an alternate condition to accept the raw string.
If anybody has an idea how to do a form submission in C# containing objects more complex than a hashmap/dictionary of strings, then I will upvote your answer and give you lots of hugs. For now, this hacky nonsense will have to do.
Well, once, a long time ago I implemented a banking app front end, which, made massive use of JSON for communication between client and server.
It was a clean way to find complex object to and from the server, no need to make complex cleanup or raw string processing.
The key was using WebServices designed for ajax on the server side, your web server class should look like this:
[WebService(Namespace = "http://something.cool.com/")]
[ScriptService] // This is part of the magic
public class UserManagerService : WebService
{
[WebMethod]
[ScriptMethod] // This is too a part of the magic
public MyComplexObject MyMethod(MyComplexInput myParameter)
{
// Here you make your process, read, write, update the database, sms your boss, send a nuke, or whatever...
// Return something to your awaiting client
return new MyComplexObject();
}
}
Now, on your client-side, set things up to make ASP.NET talk to you in JSON, I'm using JQuery for making the ajax requests.
$.ajax({
type: 'POST',
url: "UserManagerService.asmx/MyMethod",
data: {
myParameter:{
prop1: 90,
prop2: "Hallo",
prop3: [1,2,3,4,5],
prop4: {
// Use the complexity you need.
}
}
},
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function(response) {
alert(response.d);
}
});
Anything that ASP want to return as the result for your ScriptMethod, is going to be contained in the response.d variable. So, let's say you are returning from the server a complex object, "response.d" is the reference to your object, you access all the object members using the dot notation as usual.

Calling a web service from Javascript (passing parameters and returning dataset)

I have created a web service in C# and now need to call it from a mobile app. I'm trying to create a Windows 7 mobile app, but using HTML5 and Javascript not the native code. The web service takes 2 parameters, Email and Password, and returns a Dataset. I don't really have any javascript experience (or web services experience for that matter, trying to learn with this project), and when trying to research how to call a web service using javascript I just found too much information and didn't know where to begin because so many other technologies were also mentioned.
So I decided to try things out and this is what I came up with so far:
<script type="text/javascript">
document.addEventListener("deviceready", onDeviceReady, false);
// once the device ready event fires, you can safely do your thing! -jm
function onDeviceReady() {
}
function LoginButton_onclick() {
UpdateChildrenApp.PhoneWebServices.GetMyChildren(document.getElementById('EmailBox').value,document.getElementById('PasswordBox').value, OnComplete, OnError)
}
function OnComplete(result) {
for (var i = 0; i < result.tables[0].rows.length; i++)
document.getElementById('Test').innerHTML += ''+(result.tables[0].rows[i].col_name);
}
function OnError(result) {
document.getElementById('Test').innerHTML ='Error :'+result.get_message();
}
</script>
This code does nothing when I press the submit button. Could someone please point out what the problems are and how I can fix them or suggest what I should research to address the problems and put me on the right track? Any help is greatly appreciated.
First, your webservices should return a JSON object if you want to use it in javascript.
You can of course return any XML/string, but using JSON will be A LOT easy to use the data in javascript.
Then, I would advise you to use jquery to call the webservice, as jquery will do a lot of work for you.
Read this article, it should help you set different components correctly:
I would use jQuery to do this kind of thing.
The ajax functionality its provides is really easy to use.
I would use the Revealing Module Pattern (RMP) and 2 javascript files. If you're unfamiliar with the RMP, there is a great post covering it here:
http://weblogs.asp.net/dwahlin/archive/2011/08/02/techniques-strategies-and-patterns-for-structuring-javascript-code-revealing-module-pattern.aspx
I find that if I dont employ some kind of structure to my js code using the RMP, I just end up with a mess of functions in one file.
Id have Startup.js and Dataservice.js and they would look something like this:
Startup.js
var Startup = function () {
var isValid,
dataObject = {},
populateDataObject = function () {
dataObject.dealer = $("[id$='_txtUser']").val();
dataObject.password = $("[id$='_txtPassword']").val();
},
init = function () {
var dealerId = 0;
$("[id$='_SubmitButton']").bind('click', function (evt) {
evt.preventDefault();
populateDataObject();
if (isValid) {
Dataservice.processLoginRequest(dataObject, processLoginRequestResult);
}
});
};
return {
init: init,
processLoginRequestResult: processLoginRequestResult
};
} ();
Dataservice.js (assumes old school .asmx, change as needed)
var Dataservice = function () {
$.ajaxSetup({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json"
});
var serviceBase = '../services/LoginService.asmx/',
processScreenRequest = function (valObject, callback) {
$.ajax({
url: serviceBase + "ProcessLoginRequest",
data: JSON.stringify(valObject),
success: function (json) {
callback(json);
}
});
};
return {
processScreenRequest: processScreenRequest
};
} ();
and then I would include refereces to these 2 js files as well as jquery in my html page.
I hope this helps.
I've used Dojo for this once, its pretty simple you can make xhrget or xhrpost requests. It has a function called load that is the callback where you can modify the contents of the HTML components in the page.
Use these links : http://dojotoolkit.org/reference-guide/1.7/dojo/xhrGet.html

Categories

Resources