what @Html.Raw() and Json.Encode() does

What this code does?

@model CourseVM
<script type="text/javascript">
    var model = @Html.Raw(Json.Encode(Model));
    // go ahead and use the model javascript variable to bind with ko
</script>

Json.Encode serialises the Model to a JSON string. Html.Raw ensures that it is rendered verbatim and isn’t HTML-encoded by Razor. If it is Html-encoded (which Razor does by default) special characters will be converted to their HTML entity representations (e.g. & becomes &amp;). Then the JSON string might not be valid JSON.

There are arguments that encoding protects against script injection and Html.Raw removes that protection.

Html encode() is a built-in feature in MVC so we shouldn’t be worried about script injection in MVC.

Quick layout using pre-defined Json Data

Let’s say we are manually creating Json Data and use ASP.NET Core to quickly come up with a layout. This is the data (JSON output) and final outcome that we expect;

# JSON output

[ { "text": "Head Office", "nodes": [ { "text": "Finance Division", "href": "#parent1", "tags": [ "4" ], "nodes": [ { "text": "Accounting functions", "href": "#child1", "tags": [ "2" ], "nodes": [ { "text": "205", "href": "#grandchild1", "tags": [ "0" ] }, { "text": "206", "href": "#grandchild2", "tags": [ "0" ] } ] }, { "text": "Customer Invoicing", "nodes": [ { "text": 205 }, { "text": 206 } ] }, { "text": "Vendor Invoicing", "nodes": [ { "text": 205 }, { "text": 206 } ] }, { "text": "Banking relationship", "nodes": [ { "text": 205 }, { "text": 206 } ] } ] } ] } ]

Create your test data and drop it under Models, call it DummyData.json. Make sure it’s a valid JSON. These are the lines that we need in controller action method;

var folderDetails = Path.Combine(Directory.GetCurrentDirectory(), $"Models\\{"DummyData.json"}");
var JSON = System.IO.File.ReadAllText(folderDetails);
ViewBag.defaultData = JSON;

return View(result);

In the view, we are rendering ViewBag values in a div HTML tag;

<div id="layoutData">@(ViewBag.defaultData)</div>

We are using jQuery to read this data and use it in any control;

var layoutData = $('#layoutData').text();

You can use layoutData variable anywhere you want. Make sure you are not vulnerable to XSS attacks. For XSS attacks, read this

JSON from Controller to View in ASP.NET MVC Core and avoid XSS

When working on your ASP.NET MVC application, you often need to include some of your app’s data as Javascript objects. You may need this for some interactive behaviour, graphs/charts, or simply to “hydrate” the UI with the relevant information, such as username etc.

There’s certainly a big push to move away from rendering JSON data in MVC Views. Instead, it’s recommended to use Ajax calls that fetch JSON data from backend APIs. This helps to separate concerns in your application, making it more maintainable and easier to support, test and debug.

However, sometimes it’s OK to put JSON data directly in MVC Views:

  • performance–it saves you another network call
  • prototyping–test your idea before you spend a lot of time on adding another endpoint to your backend API
  • size of the data–if it’s just a small object, you may not want to create a separate endpoint just for that thing
  • legacy–the app you’re working on is ancient, soon-to-be-retired, so there’s really no point putting lipstick on the pig

With these caveats in mind, let’s see how you can easily put some JSON into your ASP.NET MVC views.

Encoding problem

The problem with outputting any values into Views in ASP.NET MVC is that the framework encodes the output, trying to save you from introducing Cross-Site Scripting (XSS) vulnerabilities to your front-end code.

Briefly, an XSS vulnerability is when an attacker can provide some content that has a malicious Javascript payload, which then gets rendered by your web app and executed in users’ browsers.

Check out “Prevent Cross-Site Scripting (XSS) in ASP.NET Core” for more details on how to avoid this happening to your app.

The encoding that ASP.NET MVC does for you replaces all special characters like "'<> (and a few more) with their corresponding HTML codes, such &#39;&quot;&lt;&gt;.

Say you have an object Customer, and you are trying to put it in a <script> section like this:

  <script>
    var customers = JSON.parse('@JsonSerializer.Serialize(Model.Customer)');
  </script>

then all you are going to end up in the browser is going to look something like this:

  <script>
    var customers = JSON.parse('{&quot;Id&quot;:1,&quot;FirstName&quot;:&quot;Hasim&quot;,&quot;LastName&quot;:&quot;Santello&quot;,&quot;DOB&quot;:&quot;2/09/2004&quot;}');
  </script>

and it’s not even a correct JSON! ASP.NET MVC made it safe for you, but also, unfortunately, also broke it.

@Html.Raw to the rescue

To turn all those &quot; and such into proper Javascript, you need to tell ASP.NET to skip the encoding and output the raw data:

  <script>
    // ...
    var customers = JSON.parse('@Html.Raw(JsonSerializer.Serialize(Model.Customers))');
    // ...
  </script>

…and viola! it results in a nice, clean, parsable JSON:

  <script>
    // ...
    var customers = JSON.parse('{"Id":1,"FirstName":"Hasim","LastName":"Santello","DOB":"2/09/2004"}');
    // ...
  </script>

Passing the data from Controller to View

In this instance, I strongly recommend avoid using TempDataSessionViewData or ViewBag and just pass the data you need in the view as part of the controller’s model. There are multiple reasons why you shouldn’t be using the methods listed above, but the main is to keep things simple and strongly-typed. So in your controller return the view in the following manner:

  public IActionResult YourControllerMethod()
  {
      var model = new YourModelClass
      {
        // Set whichever fields in here
      };
      return View(model);
  }

…and in your view, at the top of the page, declare the model class, so that you can have compile-time checking and code completion:

  @model YourModelClass
  <!-- rest of your View.cshtml -->

A word of warning about XSS

As mentioned previously, check out that XSS article, and also be mindful of how you use the data received from the server, whether that’s embedded in the page with @Html.Raw or via Ajax.

For instance, do not concatenate strings to make HTML entities. This example

  <script>
    // ...
    var customer = JSON.parse('... some malicious JSON here with XSS attack...');
    $(body).append($('<div>' + customer.Name + '</div>');
    // ...
  </script>

will introduce a very obvious XSS security hole in your site, because if a malicious user updates their name to <script>alerts('YOU PWND!');</script> that code will execute on clients’ browsers.

Whichever JavaScript framework you’re using, check its documentation on how to avoid XSS. With jQuery, use methods like .text() to set text of newly created elements.

Possible values of empty json

An empty string is not a valid json;

string json = "";

While an empty string is not valid JSON two quotes is valid JSON. This is an important distinction.

Which is to say a string that contains two quotes is not the same thing as an empty string.

string json = "{}";
string json = "[]";

Valid minimal JSON strings are

The empty object '{}'

The empty array '[]'

The string that is empty '""'

A number e.g. '123.4'

The boolean value true 'true'

The boolean value false 'false'

The null value 'null'

Resource

https://stackoverflow.com/questions/30621802/why-does-json-parse-fail-with-the-empty-string

JavaScript Callback function

In JavaScript, we can pass a function to another function as an argument. By definition, a callback is a function that we pass into another function as an argument for executing later.

We are going to focus on Asynchronous callbacks. An asynchronous callback is executed after the execution of the high-order function that uses the callback.

Asynchronicity means that if JavaScript has to wait for an operation to complete, it will execute the rest of the code while waiting.

Here is an example of Asynchronous callback;

Suppose that you need to develop a script that downloads a picture from a remote server and process it after the download completes:

function download(url) {
    // ...
}

function process(picture) {
    // ...
}

download(url);
process(picture);

However, downloading a picture from a remote server takes time depending on the network speed and the size of the picture.

The following download() function uses the setTimeout() function to simulate the network request:

function download(url) {
    setTimeout(() => {
        // script to download the picture here
        console.log(`Downloading ${url} ...`);
    },1000);
}

And this code emulates the process() function:

function process(picture) {
    console.log(`Processing ${picture}`);
}

When we execute the following code:

let url = 'https://www.foot.net/pic.jpg';

download(url);
process(url);

we will get the following output:

Processing https://foo.net/pic.jpg
Downloading https://foo.net/pic.jpg ...

This is not what we expected because the process() function executes before the download() function. The correct sequence should be:

  • Download the picture and wait for the download completes.
  • Process the picture.

To resolve this issue, we can pass the process() function to the download() function and execute the process() function inside the download() function once the download completes, like this:

function download(url, callback) {
    setTimeout(() => {
        // script to download the picture here
        console.log(`Downloading ${url} ...`);
        
        // process the picture once it is completed
        callback(url);
    }, 1000);
}

function process(picture) {
    console.log(`Processing ${picture}`);
}

let url = 'https://wwww.javascripttutorial.net/pic.jpg';
download(url, process);

Output:

Downloading https://www.foo.net/pic.jpg ...
Processing https://www.foo.net/pic.jpg

Now, it works as expected.

In this example, the process() is a callback passed into an asynchronous function.

When we use a callback to continue code execution after an asynchronous operation, the callback is called an asynchronous callback.

To make the code more concise, we can define the process() function as an anonymous function:

function download(url, callback) {
    setTimeout(() => {
        // script to download the picture here
        console.log(`Downloading ${url} ...`);
        // process the picture once it is completed
        callback(url);

    }, 1000);
}

let url = 'https://www.javascripttutorial.net/pic.jpg';
download(url, function(picture) {
    console.log(`Processing ${picture}`);
}); 

Handling errors

The download() function assumes that everything works fine and does not consider any exceptions. The following code introduces two callbacks: success and failure to handle the success and failure cases respectively:

function download(url, success, failure) {
  setTimeout(() => {
    console.log(`Downloading the picture from ${url} ...`);
    !url ? failure(url) : success(url);
  }, 1000);
}

download(
  '',
  (url) => console.log(`Processing the picture ${url}`),
  (url) => console.log(`The '${url}' is not valid`)
);

Nesting callbacks and the Pyramid of Doom

How do we download three pictures and process them sequentially? A typical approach is to call the download() function inside the callback function, like this:

function download(url, callback) {
  setTimeout(() => {
    console.log(`Downloading ${url} ...`);
    callback(url);
  }, 1000);
}

const url1 = 'https://www.foo.net/pic1.jpg';
const url2 = 'https://www.foo.net/pic2.jpg';
const url3 = 'https://www.foo.net/pic3.jpg';

download(url1, function (url) {
  console.log(`Processing ${url}`);
  download(url2, function (url) {
    console.log(`Processing ${url}`);
    download(url3, function (url) {
      console.log(`Processing ${url}`);
    });
  });
});

Output:

Downloading https://www.foo.net/pic1.jpg ...
Processing https://www.foo.net/pic1.jpg
Downloading https://www.foo.net/pic2.jpg ...
Processing https://www.foo.net/pic2.jpg
Downloading https://www.foo.net/pic3.jpg ...
Processing https://www.foo.net/pic3.jpg

The script works perfectly fine.

However, this callback strategy does not scale well when the complexity grows significantly.

Nesting many asynchronous functions inside callbacks is known as the pyramid of doom or the callback hell:

asyncFunction(function(){
    asyncFunction(function(){
        asyncFunction(function(){
            asyncFunction(function(){
                asyncFunction(function(){
                    ....
                });
            });
        });
    });
});

To avoid the pyramid of doom, we use promises or async / await functions.