asp.net-coremodel-view-controllerasp.net-core-mvcquery-stringquerystringparameter

How do I persist all querystring values in asp.net core 3.1 mvc?


I have an asp.net core 3.1 mvc project where I have a search page (view). I am persisting search, filter and sort criteria values via Session data. This works fine, and persists data correctly, but the querystring does not contain all the information I need it to.

Values for the filters and search are selected via a form, and submit button, but sorting is selected by clicking the column headers in the search results. e.g.:

   <form asp-controller="Companies" asp-action="Index" method="get">
        <p>
           <label>Company Name: </label>
           <select asp-for="CompanyName" asp-items="Model.CompanyName">
                  <option value="">All</option>
           </select> 
           <input type="submit" value="Find" />
        </p>
    </form>

<table class="table">
 <thead>
   <tr>
      <th>
         <a asp-action="Index" asp-route-sortOrder="CompanyName">@Html.DisplayNameFor(model => model.CompaniesListViewModelList[0].CompanyName)</a>
      </th>
   </tr>
 </thead>
 <tbody>
     @foreach (var item in Model.CompaniesListViewModelList)
     {
         <tr>
            <td>
                @Html.DisplayFor(modelItem => item.CompanyName)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
         </tr>
     }
 </tbody>
</table>

If the clicks in the header to change the sort order, none of the querystring values for the filters etc appear in the querystring.

The reason I need this is so that a link can be sent to someone else.

So the question is, how do I get all the used querystring values to appear in the querystring?


Solution

  • In the Index action method, you could use ViewBag or ViewData to store the current search value (the CompanyName), then transfer it to the view page:

    Then, for the sort links, you could use asp-route-{value} to add the current search value as the route parameter, and bind values via the ViewData or ViewBag. Code like this:

     <a asp-action="Index" asp-route-CompanyName="@ViewData["CurrentFilter"]" asp-route-sortOrder="@ViewData["CompanyNameSortParm"]">CompanyName</a>
    

    The sample code as below:

    Models:

    public class Employee
    {
        public int EmployeeId { get; set; }
        public string EmployeeName { get; set; } 
        public string CompanyName { get; set; }
         
    }
    public class Company
    {
        public int CompanyId { get; set; }
        public string CompanyName { get; set; }
        public List<Employee> Employees { get; set; }
    }
    public class EmployeeVM
    {
        public string CompanyName { get; set; }
        public List<Company> AllCompanies { get; set; }
        public List<Employee> Employees { get; set; }
    }
    

    Controller:

    public class CompaniesController : Controller
    {
        public IActionResult Index(string sortOrder, string CompanyName)
        { 
            ViewData["CompanyNameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "companyname_desc" : "";
            ViewData["CurrentFilter"] = CompanyName;
    
            var employees = from s in repo.GetEmployees()
                           select s;
            if (!String.IsNullOrEmpty(CompanyName))
            {
                employees = employees.Where(s => s.CompanyName.Contains(CompanyName));
            }
            switch (sortOrder)
            {
                case "companyname_desc":
                    employees = employees.OrderByDescending(s => s.CompanyName);
                    break; 
                default:
                    employees = employees.OrderBy(s => s.EmployeeId);
                    break;
            }
    
            EmployeeVM vm = new EmployeeVM();
            vm.Employees = employees.ToList();
            vm.AllCompanies = repo.GetAllCompanies().ToList();
    
            return View(vm);
        }
    }
    

    Index Views:

    @model netcore3.Data.EmployeeVM
     
    <form asp-controller="Companies" asp-action="Index" method="get">
        <p>
            <label>Company Name: </label>
            <select asp-for="CompanyName" asp-items="@(new SelectList(Model.AllCompanies, "CompanyName","CompanyName"))">
                <option value="">All</option>
            </select>
            <input type="submit" value="Find" />
        </p>
    </form>
    <table class="table">
        <thead>
            <tr>
                <th>
                    EmployeeName
                </th>
                <th>
                    <a asp-action="Index" asp-route-CompanyName="@ViewData["CurrentFilter"]" asp-route-sortOrder="@ViewData["CompanyNameSortParm"]">CompanyName</a>
                </th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model.Employees)
            {
                <tr>
                    <td>
                        @Html.DisplayFor(modelItem => item.EmployeeName)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.CompanyName)
                    </td>
                    <td>
                        <a asp-action="Edit" asp-route-id="@item.EmployeeId">Edit</a> |
                        <a asp-action="Details" asp-route-id="@item.EmployeeId">Details</a> |
                        <a asp-action="Delete" asp-route-id="@item.EmployeeId">Delete</a>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    

    The result like this:

    enter image description here

    Reference:

    Tutorial: Add sorting, filtering, and paging - ASP.NET MVC with EF Core

    Anchor Tag Helper in ASP.NET Core