在 Asp .Net Core 3.1 中发送带有排序项和查询参数(搜索栏)的视图

Send view with sorted items and query parameters (Search Bar) in Asp .Net Core 3.1

我创建了一个这样的搜索栏

 <form method="post" asp-action="Search">
    <input type="text" name="search" placeholder="Enter here the Name " />
    <select name="type" id="type" class="form-control">
        <option value="Success">Inactive Reservation</option>
        <option value="Approved">Active Reservation</option>
        <option value="Pending">Pending Reservation</option>
    </select>
    <input type="submit" value="Search" />
</form>

控制器中的方法:

public async Task<IActionResult> Search(string search,string type)      
{       
    var allRsv = from m in _db.Reservation
                 select m;

    var Rsv = allRsv
        .Where(x => x.ClientName.ToLower().Contains(search.ToLower()) && 
                    x.Status.ToLower().Contains(type.ToLower()));

    return View(Rsv);
}

我想要的:在搜索页面中发送类似“您搜索了@search 并输入:@type.

return 视图没有执行此操作的选项,return 也没有执行操作..

我可以用简单的方法来做吗?

我唯一的想法是发送查询字符串,然后在搜索视图中请求查询

What I want: to send in search page something like 'You searched for @search and type: @type.

您可以尝试 pass data to search page 通过 ViewData 等,如下所示。

在查看页面中

<form method="post" asp-action="Search">
    <input type="text" name="search" placeholder="Enter here the Name " />
    <select name="type" id="type" class="form-control">
        <option value="Success">Inactive Reservation</option>
        <option value="Approved">Active Reservation</option>
        <option value="Pending">Pending Reservation</option>
    </select>
    <input type="submit" value="Search" />
</form>

<h3>You searched for "@ViewData["search"]" and type: @ViewData["type"].</h3>

动作方法

public async Task<IActionResult> Search(string search, string type)
{
    var allRsv = from m in _db.Reservation
                    select m;

    var Rsv = allRsv
        .Where(x => x.ClientName.ToLower().Contains(search.ToLower()) &&
                    x.Status.ToLower().Contains(type.ToLower()));

    ViewData["search"] = search;
    ViewData["type"] = type;

    return View(Rsv);
}

测试结果

使用ViewData在控制器和视图之间传递数据是可以的,只要它们之间的数据不多。如果你有很多事情要做,它会让其他人更难理解 ViewData 发生了什么,因为它是一个 weak-typed 而你不知道它包含什么,可以得到什么等等。然后你必须回到控制器,看看传递了什么。如果有多个控制器返回同一个视图怎么办...真讨厌!

此外,将数据库中的内容直接从控制器显示到视图并不是一个好习惯。

因此您应该使用 ViewData 的备选方案之一,即 ViewModel,即 strongly-typed!


假实体模型

由于我没有您的数据库,因此对于此演示,我将设置两个假的实体模型来表示您的持久性存储中的数据。

namespace DL.NetCore.EmptySolution.Web.UI.Models.Reservation
{
    public class FakeReservationStatusEntity
    {
        public string StatusId { get; set; }
        public string Status { get; set; }
    }

    public class FakeReservationEntity
    {
        public int ReservationId { get; set; }
        public int ClientId { get; set; }
        public string ClientName { get; set; }
        public DateTime StartTimeUtc { get; set; }
        public FakeReservationStatusEntity ReservationStatus { get; set; }
        public int CreatedByUserId { get; set; }
    }
}

我假设的预订和预订状态之间存在 one-to-many 关系。请注意,我特意制作它,使其具有比视图模型更多的属性!


视图模型

它们只是 POCO(普通旧 CLR 对象),用作在控制器和视图之间传输的数据容器。

namespace DL.NetCore.EmptySolution.Web.UI.Models.Reservation
{
    public class ReservationFiltersViewModel
    {
        [Display(Name = "Client name")]
        public string ClientNameSearchQuery { get; set; }

        [Display(Name = "Reservation type")]
        public string ReservationTypeSearchQuery { get; set; }

        public IDictionary<string, string> AvailableReservationTypes { get; set; }
    }

    public class ReservationViewModel
    {
        public int ReservationId { get; set; }
        public string ReservationType { get; set; }
        public string ClientName { get; set; }
        public DateTime StartTime { get; set; }
    }

    public class ReservationListViewModel
    {
        public ReservationFiltersViewModel Filters { get; set; }

        public IEnumerable<ReservationViewModel> Reservations { get; set; }
    }
}

控制器

namespace DL.NetCore.EmptySolution.Web.UI.Controllers
{
    public class ReservationController : Controller
    {
        public IActionResult Index(string c, string t)
        {
            var vm = new ReservationListViewModel
            {
                Filters = new ReservationFiltersViewModel
                {
                    ClientNameSearchQuery = c,
                    ReservationTypeSearchQuery = t,
                    // You would normally get the list from your database
                    AvailableReservationTypes = GetFakeReservationStatusesFromDb()
                        .ToDictionary(x => x.StatusId, x => x.Status)
                },
                Reservations = Enumerable.Empty<ReservationViewModel>()
            };

            // You would normally get the list of reservations from your database
            var reservationsFromDb = GetFakeReservationsFromDb();

            // Filters
            if (!String.IsNullOrWhiteSpace(c))
            {
                reservationsFromDb = reservationsFromDb
                    .Where(x => x.ClientName.Contains(c, StringComparison.InvariantCultureIgnoreCase));
            }
            if (!String.IsNullOrWhiteSpace(t))
            {
                reservationsFromDb = reservationsFromDb
                     .Where(x => x.ReservationStatus.StatusId.Contains(t, StringComparison.InvariantCultureIgnoreCase));
            }

            // See you only want to explore what you want on the view
            vm.Reservations = reservationsFromDb
                .Select(x => new ReservationViewModel
                {
                    ReservationId = x.ReservationId,
                    ClientName = x.ClientName,
                    ReservationType = x.ReservationStatus.Status,
                    StartTime = x.StartTimeUtc.ToLocalTime()
                });

            return View(vm);
        }

        [HttpPost]
        public IActionResult Search(ReservationFiltersViewModel filters)
        {
            return RedirectToAction(nameof(Index), 
                new { c = filters.ClientNameSearchQuery, t = filters.ReservationTypeSearchQuery });
        }

        ...
    }
}

索引视图

@model DL.NetCore.EmptySolution.Web.UI.Models.Reservation.ReservationListViewModel
@{
    ViewBag.Title = "Reservations";

    var selectList = new SelectList(Model.Filters.AvailableReservationTypes, "Key", "Value");
}

<h2>Reservations</h2>
<p class="text-muted">
    List of reservations you can manage
</p>
<div class="row">
    <div class="col-lg-4">
        <div class="card">
            <div class="card-body">
                <form method="post" asp-area="" asp-controller="reservation" asp-action="search">
                    <div class="form-group">
                        <label asp-for="Filters.ClientNameSearchQuery"></label>
                        <input asp-for="Filters.ClientNameSearchQuery" class="form-control" />
                    </div>
                    <div class="form-group">
                        <label asp-for="Filters.ReservationTypeSearchQuery"></label>
                        <select asp-for="Filters.ReservationTypeSearchQuery" class="form-control"
                                asp-items="selectList">
                            <option value="">- select -</option>
                        </select>
                    </div>
                    <button type="submit" class="btn btn-success">Search</button>
                </form>
            </div>
        </div>
    </div>
    <div class="col-lg-8">
            <!-- This could be better optimized, i.e., only display non-empty search -->
            <div class="alert alert-info">
                <i class="fas fa-info-circle"></i>
                You searched for <strong>@Model.Filters.ClientNameSearchQuery</strong> 
                and <strong>@Model.Filters.ReservationTypeSearchQuery</strong>
            </div>
        <div class="table-responsive">
            <table class="table table-hover">
                <thead>
                    <tr>
                        <th>#</th>
                        <th>Client name</th>
                        <th>Start from</th>
                        <th>Type</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach (var reservation in Model.Reservations)
                    {
                        <tr>
                            <td>@reservation.ReservationId</td>
                            <td>@reservation.ClientName</td>
                            <td>@reservation.StartTime.ToShortDateString()</td>
                            <td>@reservation.ReservationType</td>
                        </tr>
                    }
                </tbody>
            </table>
        </div>
    </div>
</div>

使用 ViewModel,没有像 ViewData 那样四处流动的魔法弦。一切都是强类型的。并且表单只回发包含我们需要的过滤器模型到服务器。


截图


源代码

我的演示项目的源代码位于 https://github.com/davidliang2008/DL.NetCore.EmptySolution. The checkin specifically for this demo is at https://github.com/davidliang2008/DL.NetCore.EmptySolution/commit/32087b989de06e316cf747ad49da6ad4b24b61b8