Home > Software engineering >  Why does System.Text.Json output invalid JSON from my MVC model?
Why does System.Text.Json output invalid JSON from my MVC model?

Time:08-11

I haven't programmed in 15 years. I am trying to encode a model with System.Text.Json and send the encoded output to a javascript function, where I want to parse it with JSON.parse.

I would like to use System.Text.Json instead of Newtonsoft.Json because it is faster, more memory efficient, and I have always gravitated toward stricter structures. So I was disappointed when System.Text.Json put out what jsonlint.com says is invalid json.

The relevant line of code in Index.cshtml is:

else { <button title="Existing visit today" name="visitBtn" id="existingVisitBtn" method="post" onclick="openExistingVisitModal(@JsonSerializer.Serialize(Model.Patients[j].VisitsToday))">Visit</button> }

It is about halfway down the whole Index.cshtml:

@using DataLibrary.Models;
@using System.Text.Json;
@model PatientsPlusVisitTypes

@{
    ViewData["Title"] = "Patient List";
    int i = 0;
    int patientIDint = 0;
}




<div >
    <h1 >SSRounds - Patient List</h1>
</div>
<h6 >Inpatient Rounds Tracking for Surgical Services</h6>
<br />



<table >
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Patients[0].Seen)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Patients[0].UA)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Patients[0].Surgicalist)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Patients[0].Location)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Patients[0].Hospital)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Patients[0].LastName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Patients[0].FirstName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Patients[0].MD)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Patients[0].Priority)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Patients[0].Diagnosis)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Patients[0].Details)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>



        @for (int j = 0; j < Model.Patients.Count; j  )
        {
            patientIDint = Model.Patients[j].PatientID;
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => Model.Patients[j].Seen)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => Model.Patients[j].UA)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => Model.Patients[j].Surgicalist)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => Model.Patients[j].Hospital)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => Model.Patients[j].Location)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => Model.Patients[j].LastName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => Model.Patients[j].FirstName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => Model.Patients[j].MD)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => Model.Patients[j].Priority)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => Model.Patients[j].Diagnosis)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => Model.Patients[j].Details)
                </td>
                <td>
                    @{
                        if (Model.Patients[j].VisitsToday.Count == 0)

                        {
                            <button  name="visitBtn" id="visitBtn" method="post" onclick="addID('@Model.Visits.Count', '@patientIDint')">Visit</button>
                        }
                        else
                        {
                            <button  title="Existing visit today" name="visitBtn" id="existingVisitBtn" method="post" onclick="openExistingVisitModal(@JsonSerializer.Serialize(Model.Patients[j].VisitsToday))">Visit</button>
                        }

                    }


                    <form asp-controller="Home" asp-action="HidePatient">
                        <button name="patientID" method="post" value=@(Model.Patients[j].PatientID) >Remove</button>
                    </form>
                </td>
            </tr>

        }
    </tbody>
</table>

<div  id="visitModal">
    <div class = "modalContent">
        <div class = "modalHeader">
            <span class = "closeBtn">&times;</span>
            <h2>Add a Visit</h2>
        </div>
        <div class = "modalBody">
            <table >
                    <thead>
                        <tr>
                            <th>
                                @Html.DisplayNameFor(model => model.Visits[0].CPT)
                            </th>
                            <th>
                                @Html.DisplayNameFor(model => model.Visits[0].Description)
                            </th>
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>
                        @{
                            foreach (VisitTypeModel cptItem in Model.Visits)
                            {
                                <tr>
                                    @using (Html.BeginForm("SaveVisit", "Home", FormMethod.Post, new { name = "CPTForm", id = $"CPTEntry{i}" }))
                                    {
                                        <td>
                                            <button type="submit" method="post" name="CPT" [email protected] >@cptItem.CPT</button>

                                        </td>
                                        <td>
                                            <label>@cptItem.Description</label>
                                        </td>
                                        i  ;
                                    }
                                </tr>
                            }
                        }
                    </tbody>
                </table>
        </div>
        <div class = "modalFooter">

        </div>
    </div>
</div>

<div  id="existingVisitModal">
    <div >
        <div >
            <div >
                <span >&times;</span>
                <h2>Existing Visit Today</h2>
            </div>
            <div >
                <table >
                    <thead>
                        <tr>
                            <th>
                                Time
                            </th>
                            <th>
                                Entered By
                            </th>
                            <th>
                                Visit Level
                            </th>
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>
                        @{

                        }
                    </tbody>
                </table>
            </div>
            <div >
                <button type="button"  data-bs-dismiss="modal">Cancel</button>
            </div>
        </div>
    </div>
</div>

Console logging jsonVisitsToday (passed from @JsonSerializer.Serialize(Model.Patients[j].VisitsToday)) produces this: '{PatientID: 19509, WhenSeen: '2022-08-10T09:56:50', SeenBy: '[email protected]', VisitLevel: '99024', Legit: true}'

No quotes on the property names! Everything I have read says valid JSON requires quotes on the property names. And to get jsonlint.com to call it valid JSON I have to put double quotes around the property names and the values.

**My questions:

  1. Is that valid JSON output (I don't think so)
  2. If it is, how do I parse it?**

The javascript that is giving me fits:

function openExistingVisitModal(jsonVisitsToday) {
    existingVisitModal = document.getElementById("existingVisitModal");
    console.log(jsonVisitsToday);
    //jsonParsed = JSON.parse(jsonVisitsToday); //commented out because it generates an error
    //add elements and data to the modal form here
    existingVisitModal.style.display = 'block';
}

Models:

using System;
using System.ComponentModel.DataAnnotations;

namespace DataLibrary.Models
{
    public class VisitModelSQL
    {
        [Key]
        public int PatientID { get; set; }
        public DateTime WhenSeen { get; set; }
        public string SeenBy { get; set; }
        public string VisitLevel { get; set; }
        public bool Legit { get; set; }
    }
}
namespace SSRoundsMVC.Models
{
    public class VisitModel
    {
        public int PatientID { get; set; }
        public DateTime WhenSeen { get; set; }
        public string SeenBy { get; set; }
        public string VisitLevel { get; set; }
        public bool Legit { get; set; }
    }
}
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;

namespace SSRoundsMVC.Models
{
    public class PtDisplayModel
    {
        [Key]
        [HiddenInput(DisplayValue = false)]
        public int PatientID { get; set; }
        public bool Seen { get; set; }
        public bool UA { get; set; }
        [Display(Name = "S")]
        public bool Surgicalist { get; set; }
        [Display(Name = "Hosp")]
        public string? Hospital { get; set; }
        [Display(Name = "Loc")]
        public string? Location { get; set; }
        [Display(Name = "Last Name")]
        public string? LastName { get; set; }
        [Display(Name = "First Name")]
        public string? FirstName { get; set; }
        [Display(Name = "Doc")]
        public string? MD { get; set; }
        [Display(Name = "#")]
        public int Priority { get; set; }
        public string? Diagnosis { get; set; }
        [Display(Name = "Details and Instructions")]
        public string? Details { get; set; }
        [HiddenInput(DisplayValue = false)]
        public List<DataLibrary.Models.VisitModelSQL>? VisitsToday { get; set; }

    }
}
namespace DataLibrary.Models
{
    public class VisitTypeModel
    {
        public string CPT { get; set; }
        public string Description { get; set; }
        public int Order { get; set; }
        public int PatientID { get; set; }
    }
}
using System;
using DataLibrary.Models;
using SSRoundsMVC.Models;

namespace SSRoundsMVC.Models
{
    public class PatientsPlusVisitTypes
    {
        public List<PtDisplayModel> Patients { get; set; }
        public List<VisitTypeModel> Visits { get; set; }
    }
}

CodePudding user response:

JLq I should have paid more attention to your comments about the output being an object. I can't JSON.parse it because it is already an object. All I need to do is access it with dot notation - as in jsonVisitsToday.WhenSeen. Thanks for your quick responses - I had no idea stackoverflow was so active!

CodePudding user response:

If you manage to remove the outer single quotes, yes, it is valid JSON that will be parsed by the JSON.parse(x) statement.

I would try to modify the view (index.cshtml) to make it output the value with @Html.Raw(x) as in:

onclick="openExistingVisitModal(@Htm.Raw(JsonSerializer.Serialize(Model.Patients[j].VisitsToday)))"

This should produce a direct JSON object as input of your openExistingVisitModal function, and it should not give any errors when it is executed in the parsed view by the browser.

as in onclick="openExistingVisitModal({PatientID: 19509, WhenSeen: '2022-08-10T09:56:50', SeenBy: '[email protected]', VisitLevel: '99024', Legit: true})"

  • Related