在 ASP .Net Core MVC 中对日期时间进行排序
我正在 ASP.NET Core MVC 中开发一个 Web 应用程序,其中用户输入一个股票代码,然后获取有关给定股票代码的股票信息。我已经设法添加排序功能。它在数字上工作得很好,但是当它是日期时间(2022 年 3 月 7 日等)时如何对该表进行排序?有人可以帮我解决这个问题吗?这是我的代码:
查看模型
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace PoC.Web.ViewModels
{
public class StockViewModel
{
public DateTime Timestamp { get; set; }
public decimal Open { get; set; }
public decimal High { get; set; }
public decimal Low { get; set; }
public decimal Close { get; set; }
public decimal Volume { get; set; }
}
public class SearchModel
{
public string Ticker { get; set; } = "";
public int PageNr { get; set; } = 1;
public int PageSize { get; set; } = 10;
public int TotalRecords { get; set; } = 0;
public int TotalPages { get; set; } = 0;
public List<StockViewModel> Results { get; set; } = new List<StockViewModel>();
public string ErrorMessage { get; set; } = "";
}
public class Error
{
public string Information { get; set; }
}
}
StockController
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
using Microsoft.Extensions.Logging;
using PoC.Web.ViewModels;
using ServiceStack;
using PoC.Core.Media.Interfaces;
namespace PoC.Web.Controllers
{
public class StockController : Controller
{
public IActionResult Index(string ticker = "", int pageNr = 1, int pageSize = 10, string sortOrder="")
{
ViewData["TimestampSortParm"] = String.IsNullOrEmpty(sortOrder) ? "timestamp_desc" : "";
ViewData["VolumeSortParm"] = sortOrder == "Volume" ? "volume_desc" : "Volume";
ViewData["LowSortParm"] = sortOrder == "Low" ? "low_desc" : "Low";
ViewData["HighSortParm"] = sortOrder == "High" ? "high_desc" : "High";
ViewData["OpenSortParm"] = sortOrder == "Open" ? "open_desc" : "Open";
ViewData["CloseSortParm"] = sortOrder == "Close" ? "close_desc" : "Close";
var response = new SearchModel { Ticker = ticker };
if (!String.IsNullOrEmpty(ticker))
{
var apiKey = "";
var apiResponse = $"https://www.alphavantage.co/query?function=TIME_SERIES_MONTHLY&symbol={ticker}&apikey={apiKey}&datatype=csv".GetStringFromUrl();
try
{
var allPrices = apiResponse.FromCsv<List<StockViewModel>>().ToList();
int totalRecords = allPrices.Count;
int totalPages = (totalRecords + pageSize - 1) / pageSize;
response.TotalPages = totalPages;
response.TotalRecords = totalRecords;
switch (sortOrder)
{
case "Timestamp":
response.Results = allPrices.OrderBy(ar => ar.Timestamp).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "volume_desc":
response.Results = allPrices.OrderByDescending(ar => ar.Volume).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "Volume":
response.Results = allPrices.OrderBy(ar => ar.Volume).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "low_desc":
response.Results = allPrices.OrderByDescending(ar => ar.Low).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "Low":
response.Results = allPrices.OrderBy(ar => ar.Low).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "high_desc":
response.Results = allPrices.OrderByDescending(ar => ar.High).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "High":
response.Results = allPrices.OrderBy(ar => ar.High).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "open_desc":
response.Results = allPrices.OrderByDescending(ar => ar.Open).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "Open":
response.Results = allPrices.OrderBy(ar => ar.Open).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "close_desc":
response.Results = allPrices.OrderByDescending(ar => ar.Close).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "Close":
response.Results = allPrices.OrderBy(ar => ar.Close).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
default:
response.Results = allPrices.OrderByDescending(ar => ar.Timestamp).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
}
}
catch (Exception exc)
{
response.ErrorMessage = apiResponse.FromJson<Error>().Information;
}
}
response.PageNr = pageNr;
response.PageSize = pageSize;
return View(response);
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
Index
@model PoC.Web.ViewModels.SearchModel
@{ ViewData["Title"] = "Stocks"; }
<form method="get">
<div class="text-center">
<h1 class="display-4">Welcome to the Stocks page.</h1>
<div class="table-responsive">
<table class="table small">
<tr>
<td>
<label>Enter Ticker</label> <input type="text" asp-for="Ticker" class="form-control" />
</td>
<td style="vertical-align: bottom; horiz-align: center"> <button asp-controller="Stock" asp-action="Index" class="btn btn-dark">Fetch Data from AlphaVantage</button></td>
</tr>
</table>
</div>
<div>
<table class="table">
<thead class="thead-light">
<tr>
<th>
<a asp-controller="Stock" asp-action="Index" asp-route-ticker="@Model.Ticker" asp-route-sortOrder="@ViewData["TimestampSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Timestamp</a>
</th>
<th>
<a asp-controller="Stock" asp-action="Index" asp-route-ticker="@Model.Ticker" asp-route-sortOrder="@ViewData["VolumeSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Volume</a>
</th>
<th>
<a asp-controller="Stock" asp-action="Index" asp-route-ticker="@Model.Ticker" asp-route-sortOrder="@ViewData["LowSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Low</a>
</th>
<th>
<a asp-controller="Stock" asp-action="Index" asp-route-ticker="@Model.Ticker" asp-route-sortOrder="@ViewData["HighSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">High</a>
</th>
<th>
<a asp-controller="Stock" asp-action="Index" asp-route-ticker="@Model.Ticker" asp-route-sortOrder="@ViewData["OpenSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Open</a>
</th>
<th>
<a asp-controller="Stock" asp-action="Index" asp-route-ticker="@Model.Ticker" asp-route-sortOrder="@ViewData["CloseSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Close</a>
</th>
</tr>
</thead>
<tbody>
@foreach (var m in @Model.Results)
{
<tr>
<td>
@m.Timestamp.ToString("dd MMM yyyy")
</td>
<td>
@m.Volume.ToString("N0")
</td>
<td>
@m.Low.ToString("N2")
</td>
<td>
@m.High.ToString("N2")
</td>
<td>
@m.Open.ToString("N2")
</td>
<td>
@m.Close.ToString("N2")
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="text-center">
<nav class="navbar-dark align-content-center">
<ul class="pagination">
@for (var i = 1; i <= Model.TotalPages; i++)
{
<li class="page-item @(i == Model.PageNr ? "active" : "")">
<a asp-controller="Stock" asp-action="Index" asp-route-pageNr="@i" asp-route-ticker="@Model.Ticker" asp-route-currentFilter="@ViewData["CurrentFilter"]" class="page-link">@i</a>
</li>
}
</ul>
</nav>
</div>
</div>
</form>
I'm working on a web application in ASP.NET Core MVC, in which the user inputs a ticker and then gets stock information about the given ticker. I've managed to add a sorting feature. It works fine on numbers, but how do I sort this table when it's DateTime (07 Mar 2022 etc)? Can someone please help me fix this? This is my code:
View model
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace PoC.Web.ViewModels
{
public class StockViewModel
{
public DateTime Timestamp { get; set; }
public decimal Open { get; set; }
public decimal High { get; set; }
public decimal Low { get; set; }
public decimal Close { get; set; }
public decimal Volume { get; set; }
}
public class SearchModel
{
public string Ticker { get; set; } = "";
public int PageNr { get; set; } = 1;
public int PageSize { get; set; } = 10;
public int TotalRecords { get; set; } = 0;
public int TotalPages { get; set; } = 0;
public List<StockViewModel> Results { get; set; } = new List<StockViewModel>();
public string ErrorMessage { get; set; } = "";
}
public class Error
{
public string Information { get; set; }
}
}
StockController
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
using Microsoft.Extensions.Logging;
using PoC.Web.ViewModels;
using ServiceStack;
using PoC.Core.Media.Interfaces;
namespace PoC.Web.Controllers
{
public class StockController : Controller
{
public IActionResult Index(string ticker = "", int pageNr = 1, int pageSize = 10, string sortOrder="")
{
ViewData["TimestampSortParm"] = String.IsNullOrEmpty(sortOrder) ? "timestamp_desc" : "";
ViewData["VolumeSortParm"] = sortOrder == "Volume" ? "volume_desc" : "Volume";
ViewData["LowSortParm"] = sortOrder == "Low" ? "low_desc" : "Low";
ViewData["HighSortParm"] = sortOrder == "High" ? "high_desc" : "High";
ViewData["OpenSortParm"] = sortOrder == "Open" ? "open_desc" : "Open";
ViewData["CloseSortParm"] = sortOrder == "Close" ? "close_desc" : "Close";
var response = new SearchModel { Ticker = ticker };
if (!String.IsNullOrEmpty(ticker))
{
var apiKey = "";
var apiResponse = quot;https://www.alphavantage.co/query?function=TIME_SERIES_MONTHLY&symbol={ticker}&apikey={apiKey}&datatype=csv".GetStringFromUrl();
try
{
var allPrices = apiResponse.FromCsv<List<StockViewModel>>().ToList();
int totalRecords = allPrices.Count;
int totalPages = (totalRecords + pageSize - 1) / pageSize;
response.TotalPages = totalPages;
response.TotalRecords = totalRecords;
switch (sortOrder)
{
case "Timestamp":
response.Results = allPrices.OrderBy(ar => ar.Timestamp).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "volume_desc":
response.Results = allPrices.OrderByDescending(ar => ar.Volume).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "Volume":
response.Results = allPrices.OrderBy(ar => ar.Volume).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "low_desc":
response.Results = allPrices.OrderByDescending(ar => ar.Low).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "Low":
response.Results = allPrices.OrderBy(ar => ar.Low).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "high_desc":
response.Results = allPrices.OrderByDescending(ar => ar.High).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "High":
response.Results = allPrices.OrderBy(ar => ar.High).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "open_desc":
response.Results = allPrices.OrderByDescending(ar => ar.Open).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "Open":
response.Results = allPrices.OrderBy(ar => ar.Open).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "close_desc":
response.Results = allPrices.OrderByDescending(ar => ar.Close).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
case "Close":
response.Results = allPrices.OrderBy(ar => ar.Close).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
default:
response.Results = allPrices.OrderByDescending(ar => ar.Timestamp).Skip((pageNr - 1) * pageSize).Take(pageSize).ToList();
break;
}
}
catch (Exception exc)
{
response.ErrorMessage = apiResponse.FromJson<Error>().Information;
}
}
response.PageNr = pageNr;
response.PageSize = pageSize;
return View(response);
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
Index
@model PoC.Web.ViewModels.SearchModel
@{ ViewData["Title"] = "Stocks"; }
<form method="get">
<div class="text-center">
<h1 class="display-4">Welcome to the Stocks page.</h1>
<div class="table-responsive">
<table class="table small">
<tr>
<td>
<label>Enter Ticker</label> <input type="text" asp-for="Ticker" class="form-control" />
</td>
<td style="vertical-align: bottom; horiz-align: center"> <button asp-controller="Stock" asp-action="Index" class="btn btn-dark">Fetch Data from AlphaVantage</button></td>
</tr>
</table>
</div>
<div>
<table class="table">
<thead class="thead-light">
<tr>
<th>
<a asp-controller="Stock" asp-action="Index" asp-route-ticker="@Model.Ticker" asp-route-sortOrder="@ViewData["TimestampSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Timestamp</a>
</th>
<th>
<a asp-controller="Stock" asp-action="Index" asp-route-ticker="@Model.Ticker" asp-route-sortOrder="@ViewData["VolumeSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Volume</a>
</th>
<th>
<a asp-controller="Stock" asp-action="Index" asp-route-ticker="@Model.Ticker" asp-route-sortOrder="@ViewData["LowSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Low</a>
</th>
<th>
<a asp-controller="Stock" asp-action="Index" asp-route-ticker="@Model.Ticker" asp-route-sortOrder="@ViewData["HighSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">High</a>
</th>
<th>
<a asp-controller="Stock" asp-action="Index" asp-route-ticker="@Model.Ticker" asp-route-sortOrder="@ViewData["OpenSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Open</a>
</th>
<th>
<a asp-controller="Stock" asp-action="Index" asp-route-ticker="@Model.Ticker" asp-route-sortOrder="@ViewData["CloseSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Close</a>
</th>
</tr>
</thead>
<tbody>
@foreach (var m in @Model.Results)
{
<tr>
<td>
@m.Timestamp.ToString("dd MMM yyyy")
</td>
<td>
@m.Volume.ToString("N0")
</td>
<td>
@m.Low.ToString("N2")
</td>
<td>
@m.High.ToString("N2")
</td>
<td>
@m.Open.ToString("N2")
</td>
<td>
@m.Close.ToString("N2")
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="text-center">
<nav class="navbar-dark align-content-center">
<ul class="pagination">
@for (var i = 1; i <= Model.TotalPages; i++)
{
<li class="page-item @(i == Model.PageNr ? "active" : "")">
<a asp-controller="Stock" asp-action="Index" asp-route-pageNr="@i" asp-route-ticker="@Model.Ticker" asp-route-currentFilter="@ViewData["CurrentFilter"]" class="page-link">@i</a>
</li>
}
</ul>
</nav>
</div>
</div>
</form>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我知道错误是什么。在第 18 行中,我将第一个案例从“timestamp_desc”更改为“Timestamp”,并且成功了。但无论如何,感谢@Crowcoder 提供的有用信息。
I know what the error was. In the line nr 18 i've changed the first case from "timestamp_desc" to "Timestamp" and it worked. But anyway, thanks @Crowcoder for the useful information.