Search code examples
c#htmlasp.net-mvcasp.net-core

How to send List<T> from one controller to another via html button


Im generating a List in my CalculationsController in post method CalculateMenu(). In this method Im drawing a table to represent a list, and a button. The button should send this list to another controller. How to do it? What do I need to attach so you can help me?

CalculateMenu method:

[HttpPost]
public async Task<IActionResult> CalculateMenu([FromForm] int[] peopleCount, [FromForm] DateOnly date)
{
    StringBuilder resultString = new StringBuilder();
    resultString.AppendLine("<style>table, th, td {\n table-layout: fixed; \n border: 1px solid; \n width: 100%; \n border-collapse: collapse; \n}</style>");
    resultString.AppendLine("<h1>Answer:</h1>");
    var resultIngredients = await _calculationsService.CalculateIngredients(peopleCount, date);
    resultString.Append(CalculateTotalWeightOfEveryIngredient(resultIngredients));
    resultString.Append(await CalculatePrice(peopleCount, date));
    //How to generate a button? What did i tried:
    //resultString.AppendLine($"<form method=\"what method should i use in this case?\" action=\"put here address of second controller(dont know how)">\n    <button type=\"submit\"> submit </button>\n</form>");
    return Content(resultString.ToString(), "text/html; charset=utf-8");
}
  1. I tried to sent post/put request to CalculationsController in another method and then redirect to another controller:
[HttpPost]
[Route("api/calculations/send")]
public ActionResult Send()
{
    TempData["mydata"] = "111";
    return RedirectToAction("SaveReport", "ReportController");
}
  1. I tried to covert List to JSON and send it in query to another controller. Doesn't worked, in query there just were few symbols
string serializedIngedientsList = JsonSerializer.Serialize(resultIngredients);
resultString.AppendLine($"<button role=\"button\" class=\"sendBtn\"><a href=\"www.siteadress/api/reports/{serializedIngedientsList}\" style=\"text-decoration: none; color: #000000\"> Отчёт </a></button>");

Solution

  • So I took a while to consider your question and in my opinion you got it wrong, as you are going against MVC principle and you are mixing controller and view by putting HTML inside controller's code.

    So to do it the right way, you'd need to add view and controller for actions related to menu.

    For example consider below:

    enter image description here

    Views/Menu contains Index.cshtml page with following simple form code:

    @{
        ViewData["Title"] = "View";
        Layout = "~/Views/Shared/_Layout.cshtml";
    }
    
    <h1>View</h1>
    
    
    <form asp-action="CalculateMenu" method="post">
        <label for="peopleCount">People count:</label><br>
        <input type="text" id="peopleCount" name="peopleCount" value="0"><br>
        <label for="date">Date:</label><br>
        <input type="date" id="date" name="date" value=""><br><br>
        <input type="submit" value="Submit">
    </form> 
    

    And the HomeController has the below code:

    using Microsoft.AspNetCore.Mvc;
    using System.Text;
    using System.Threading.Tasks;
    using System;
    using System.Linq;
    
    namespace TestAspNetMvc.Controllers;
    public class MenuController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
    
        [HttpPost]
        public async Task<IActionResult> CalculateMenu(
            [FromForm] string peopleCount, 
            [FromForm] DateTime date)
        {
            // You need to add necessary error handling if input is wrong.
            var peopleCountParsed = peopleCount.Split(',')
                .Select(x => int.Parse(x))
                .ToArray();
    
            // your logic here
    
            // Here we are using the method to redirect and provide additional data.
            return RedirectToAction("Index", "Test", routeValues: new { peopleCount });
        }
    }
    
    // This is just very simple controller for presentation purposes.
    public class TestController : Controller
    {
        public IActionResult Index(string peopleCount)
        {
            return Ok();
        }
    }
    

    So the idea is to create separate HTML file with form, and keep all logic in controllers. There we can use method RedirectToAction which allows providing routeValues which can be used to forward query parameters.

    And also - I switched peopleCount type to string and date to DateTime, but you can adjust as necessary, but I guess for complex structures you could just post JSON body instead of form data.

    EDIT

    In order for user to be able to send another request to other controller with the parameter set in form, the easiest way is to add a element with proper href attribute:

    <a href="/test?peopleCount={value of param}" />