Question How to write C# method for getting data in JavaScript without returning Status200Ok or so.

Pablo

Well-known member
Joined
Aug 12, 2021
Messages
62
Programming Experience
10+
Hello! I'm a desktop app and videogame developer and I'm learning web development. I followed a tutorial about CRUD in ASP.NET Core MVC, which lists, adds, edits, and removes employees' data. My app starts with an html table with the employees' list, each field in a <td> (a row cell); all fields are individual data (like name, salary, etc.). But I want to add a variable list of phone numbers for each employee; for that, I added a new table Telefono to the DB, which is linked to table Empleado through the idEmpleado FK field, and I'm trying to place those numbers into options of a select object placed in the <td> of the table Empleado list. All this code I'm talking about is JavaScript.
Below I show the C# method that is fetched to load the Empleado (employee) list, which is located in the Controller class. It works fine.

C#:
        [HttpGet]
        public async Task<IActionResult> listaEmpleados()
        {
            List<Empleado> _lista = await _empleadoRepository.Lista();

            return StatusCode(StatusCodes.Status200OK, _lista);
        }

Below I show the C# method that is fetched to load the list of Telefono (phone number) objects from a specific Empleado (employee). You can see that there I changed the return type, I replaced the Status200OK return type by the List<Telefono> itself, because I think that that was in conflict with the data retrieving in JavaScript code. Currently it is not working (this method and/or the JavaScript function which fetches it). Actually I don't exactly know it the changes I made are correct or not, and how it would be the correct way, because by now, all these methods just loaded one list and returned Status200OK, but now I need to load the variable Telefono list first (without returning Status200OK, that is the problem I think) and then pass them to the Empleado list (add <option>s to the <select> in the <td>). It doesn't work (the JS returns an empty array).

C#:
        [HttpGet]
        public async Task<List<Telefono>> listaTelefonos(int idEmpleado)
        {
            List<Telefono> _lista = await _telefonoRepository.Lista(idEmpleado);

            return _lista;
        }

Below I show the JavaScript function which loads and shows the Empleado list (without Telefono objects by now). It works fine.

JavaScript:
function MostrarEmpleados() {

    fetch("/Home/listaEmpleados")
        .then(response => {
            return response.ok ? response.json() : Promise.reject(response)
        })
        .then(responseJson => {
            $("#tablaEmpleados tbody").html("");
            if (responseJson.length > 0) {

                responseJson.forEach((empleado) => {
                    $("#tablaEmpleados tbody").append(
                        $("<tr>").append(
                            $("<td>").text(empleado.nombreCompleto),
                            $("<td>").text(empleado.refDepartamento.nombre),
                            $("<td>").text(empleado.sueldo),
                            $("<td>").text(empleado.fechaContrato),
                            $("<td>").append(
                                $("<button>").addClass("btn btn-primary btn-sm boton-editar-empleado").text("Editar").data("dataEmpleado", empleado),
                                $("<button>").addClass("btn btn-danger btn-sm ms-2 boton-eliminar-empleado").text("Eliminar").data("dataEmpleado", empleado),
                            )
                        )
                    )
                })
            }
        })
}

Below I show the JavaScript function that should load the variable list of Telefono objects for a specific Empleado, through the idEmpleado FK field. With its corresponding C# method I showed above, it is returning an empty array (I saw while debugging). So, maybe (or very probably) the syntax of this function is not correct, so as its C# method's one. It doesn't work (it returns an empty array).

JavaScript:
function ObtenerTelefonos(id) {

    return fetch(`/Telefono/listaTelefonos?idEmpleado=${id}`)
        .then(response => {
            return response.ok ? response.json() : Promise.reject(response)
        })
        .then(responseJson => {
            const telefonos = [];
            if (responseJson.length > 0) {
                responseJson.forEach((telefono) => {
                    telefonos.push({
                        idTelefono: telefono.idTelefono,
                        descripcion: telefono.descripcion,
                        numero: telefono.numero,
                        idEmpleado: telefono.idEmpleado
                    });
                })
            }
            return telefonos;
        })
}

So, summarizing, what I'm looking for is to get data (a phone number variable list) from the C# method in the Controller (the DB, SPs, and ADO.Net code in the Repository class are perfect) from the JavaScript function (the MostrarEmpleados() function precisely) in order to add that Telefono variable list to an <option> list in the <select> (dropdown list) which would be appended to the <td> (row cell) in the Empleado list. My two great doubts are the syntax and contents of the listaTelefonos() C# method in the Controller and the ObtenerTelefonos(id) JavaScript function which fetches (or it should) that C# method. I suppose the C# method shouldn't return Status200OK or so, and the JS method is incorrect too (stuff about response and that), but have no idea on how to write it correctly.
I know there are some very good programmers here, I hope someone helps me with this.
I will apreciate your help very much. Thank you in advance.
Pablo
 
First question would be: does your listaTelefonos() even get called? And if it is, did you verify that the list being returned is not empty?

Next question is: does Fiddler, Charles, or your browser DevTools show the request response to be an empty JSON array?
 
Hello Skydiver,
I was passing wrong parameters to the ObtenerTelefonos() function; it returns the data correctly. But the problem I'm having is another and I suspect it is related to the matter of async returns and that stuff.
Below I show the MostrarEmpleados() function where I added the code which should append the <select> with the Telefono objects of each Empleado object in the list table in the page.
C#:
function MostrarEmpleados() {

    var c = 0, className = "";

    fetch("/Home/listaEmpleados")
        .then(response => {
            return response.ok ? response.json() : Promise.reject(response)
        })
        .then(responseJson => {
            $("#tablaEmpleados tbody").html("");
            if (responseJson.length > 0) {

                responseJson.forEach((empleado) => {
                    className = "class" + c;
                    $("#tablaEmpleados tbody").append(
                        $("<tr>").append(
                            $("<td>").text(empleado.nombreCompleto),
                            $("<td>").append(
                                $("<select>").addClass(className)),
                            $("<td>").text(empleado.refDepartamento.nombre),
                            $("<td>").text(empleado.sueldo),
                            $("<td>").text(empleado.fechaContrato),
                            $("<td>").append(
                                $("<button>").addClass("btn btn-primary btn-sm boton-editar-empleado").text("Editar").data("dataEmpleado", empleado),
                                $("<button>").addClass("btn btn-danger btn-sm ms-2 boton-eliminar-empleado").text("Eliminar").data("dataEmpleado", empleado)
                            )
                        )
                    )

                    ObtenerTelefonos(empleado.idEmpleado)
                        .then((telefonos) => {

                            if (telefonos.length > 0)
                                telefonos.forEach((telefono) => {
                                    $("." + className).append($("<option>").text(telefono.descripcion + ": " + telefono.numero));
                                })
                            else
                                $("." + className).append($("<option>").text("No hay teléfonos registrados."));
                        })
                    c++;
                })
            }
        })
}

I put a breakpoint in the line of c++; and another one into the ObtenerTelefonos() function, and while debugging I saw astonished that program execution passes first 4 (the number of employees) times by the c++; line and THEN 4 times by the ObtenerTelefonos(empleado.idEmpleado); line, this issue I assume is the cause of every phone number is appended to the last Empleado. As I said, I suspect async and that stuff would be the origin of this problem, but I can't figure out how to solve it.
Again, thank you so much for your time and your help.
Regards,
Pablo
 
Take off the async/await and make your calls synchronous instead of async to prove or disprove your theory.

(I don't think it's asynchronous vs synchronous unless you are keeping global or class state variables that you are sharing between those asynchronous calls, but then that is not really the fault of async, but rather poor multi threaded design on your part.)
 
Hello Skydiver,
Sorry for the delay in answering your last reply.
Actually, there is no multi-threading design on my part, but the async and await that we were talking about. I mean, there is no Thread or ThreadPool or ResetEvent objects in my code, I just followed the tutorial and it came with those async and await keywords.
But I managed to solve my quest, I added the variable phone number list to the listaEmpleados() C# method and was able to read it and display it with the MostrarEmpleados() JavaScript function in the page screen.

C#:
        public async Task<List<Empleado>> Lista()
        {
            List<Empleado> _lista = new List<Empleado>();
            TelefonoRepository _telefonoRepository = new TelefonoRepository(_configuration);

            using (var conexion = new SqlConnection(_cadenaSQL))
            {
                conexion.Open();
                SqlCommand cmd = new SqlCommand("sp_ListaEmpleados", conexion);
                cmd.CommandType = CommandType.StoredProcedure;

                using (var dr = await cmd.ExecuteReaderAsync())
                {
                    while (await dr.ReadAsync())
                    {
                        _lista.Add(new Empleado
                        {
                            idEmpleado = Convert.ToInt32(dr["idEmpleado"]),
                            nombreCompleto = dr["nombreCompleto"].ToString(),
                            telefonos = _telefonoRepository.Lista(Convert.ToInt32(dr["idEmpleado"])),
                            refDepartamento = new Departamento() {
                                idDepartamento = Convert.ToInt32(dr["idDepartamento"]),
                                nombre = dr["nombre"].ToString()
                            },
                            sueldo = Convert.ToInt32(dr["sueldo"]),
                            fechaContrato = dr["fechaContrato"].ToString(),
                        });
                    }
                }
            }
            return _lista;
        }

JavaScript:
function MostrarEmpleados() {

    fetch("/Home/listaEmpleados")
        .then(response => {
            return response.ok ? response.json() : Promise.reject(response)
        })
        .then(responseJson => {
            $("#tablaEmpleados tbody").html("");
            if (responseJson.length > 0) {

                responseJson.forEach((empleado) => {

                    var select = $("<select>");
                    for (var a = 0; a < empleado.telefonos.length; a++)
                        select.append($("<option>").text(empleado.telefonos[a].descripcion + ": " + empleado.telefonos[a].numero));
                    $("#tablaEmpleados tbody").append(
                        $("<tr>").append(
                            $("<td>").text(empleado.nombreCompleto),
                            $("<td>").append(select),
                            $("<td>").text(empleado.refDepartamento.nombre),
                            $("<td>").text(empleado.sueldo),
                            $("<td>").text(empleado.fechaContrato),
                            $("<td>").append(
                                $("<button>").addClass("btn btn-primary btn-sm boton-editar-empleado").text("Editar").data("dataEmpleado", empleado),
                                $("<button>").addClass("btn btn-danger btn-sm ms-2 boton-eliminar-empleado").text("Eliminar").data("dataEmpleado", empleado)
                            )
                        )
                    )
                })
            }
        })
}

Anyway, let's suppose that I wanted to display in the page data from two or more different (at all) queries from my database. Is it possible to do? I suspect the line in the controller returning Status200OK with the LIst<T> included (_lista in my case) would make it difficult to show more than one List of objects, because obviously you can't have more than one return sentence and I suppose you can't put more that one List in the

return StatusCode(StatusCodes.Status200OK, _lista);

either.
Well, if you could point me how this can be done (if it can) or where to look it up, I would appreciate your help very much.
Regards
Pablo
 
Your page code interacts with your server controller code once per fetch. That fetch can receive any shape of data you wish to code the server to emit, for the page code to interpret. You can, while interpreting the response, make more fetches if you want.

We try to avoid that (eg fetch a list of employee ids, then for every one fetch the employee details which includes a list of address ids, then for each of those fetch the address details) but it doesn't mean it's impossible, just that it's fairly resource intensive to make thousands of tiny requests, the headers of which are probably greater than the data.

At the moment it looks like you're building this app in quite a manual low level way; there are frameworks and libraries built to help you that you may prefer to use, where you describe the page structure and models, what part of a model is displayed in which area of the page etc and when fetches are made that deliver data models they're automatically patched into the page

I typically go another step beyond those in my dev and use Blazor, which mostly skips out the JavaScript part; you do all your page work in C# and a self contained app that is Microsoft's remit does the page updating
 
Last edited:
Your page code interacts with your server controller code once per fetch. That fetch can receive any shape of data you wish to code the server to emit, for the page code to interpret. You can, while interpreting the response, make more fetches if you want.

We try to avoid that (eg fetch a list of employee ids, then for every one fetch the employee details which includes a list of address ids, then for each of those fetch the address details) but it doesn't mean it's impossible, just that it's fairly resource intensive to make thousands of tiny requests, the headers of which are probably greater than the data.

At the moment it looks like you're building this app in quite a manual low level way; there are frameworks and libraries built to help you that you may prefer to use, where you describe the page structure and models, what part of a model is displayed in which area of the page etc and when fetches are made that deliver data models they're automatically patched into the page

I typically go another step beyond those in my dev and use Blazor, which mostly skips out the JavaScript part; you do all your page work in C# and a self contained app that is Microsoft's remit does the page updating

Hi
Thank you very much for your advice. I'm now in the process of learning Blazor. I think I'll come back here soon with some doubts and questions.
Regards
Pablo
 
Back
Top Bottom