繁体   English   中英

在 Web API 中传递日期时间参数?

[英]Pass datetime parameter in Web API?

我想问Web API中如何传递datetime参数,如何在可选日期中传递datetime参数。 我想在URL中搜索可以不带时间的可选日期如:

localhost:IP/api/values?date=2020-01-01

预期成绩:

<ArrayOfTest xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Test>
<UserId>341</UserId>
<Name>Emily</Name>
<Mobile>386754298</Mobile>
<Age>24</Age>
<Date>2021-11-06T16:04:00</Date>
</Test>
<Test>
<UserId>2555</UserId>
<Name>Peter</Name>
<Mobile>48295729</Mobile>
<Age>45</Age>
<Date>2020-10-12T20:35:00</Date>
</Test>

它可以在2020-01-01之后找到日期。 一些值是来自 SQL 服务器数据库的 null,所以我使用dbnull来确保代码有效并且我没有使用实体框架连接数据库,我尝试只在 get 方法中传递 datetime 参数,但它不能正常工作. 是否可以像这样传递数据时间参数?

Class 代码:

    public class TestClass
    {

        public string UserId { get; set; }

        public string Name { get; set; }

        public string Mobile { get; set; }

        public int Age { get; set; }

        public DateTime? Date { get; set; }
    }

controller 代码:

        public IHttpActionResult Get(DateTime date)
        {
            List<UserClass> Test = new List<UserClass>();
            string mainconn = ConfigurationManager.ConnectionStrings["myconn"].ConnectionString;
            SqlConnection sqlconn = new SqlConnection(mainconn);
            string sqlquery = "SELECT UserID, Name, Mobile, Age, Date From tbluser where Date="+date+";
            sqlconn.Open();
            SqlCommand sqlcomm = new SqlCommand(sqlquery, sqlconn);
            SqlDataReader reader = sqlcomm.ExecuteReader();
            while (reader.Read())
                {
                    Test.Add(new UserClass()
                    {
                        UserId = reader.GetValue.ToString(0),
                        Name = reader.GetValue.ToString(1),
                        Mobile = reader.GetValue.ToString(2),
                        Access = Convert.ToInt32(reader.GetValue(3)),
                        Date = (reader.GetValue(4) != DBNull.Value) ? Convert.ToDateTime(reader.GetValue(4)) : (DateTime?)null
                    });
                }
            return Ok(Test);
        }

应该添加这样的字符串

SELECT UserID, Name, Mobile, Age, Date From tbluser where Date="+date+"

这可能会导致SQL 注入 相反,请使用日期类型为https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand.parameters?view=dotnet-plat-ext-6.0 的SQL 参数遵循本文档

这是示例:

        string sqlquery = "SELECT UserID, Name, Mobile, Age, Date From tbluser where Date= @YourDate";
        SqlCommand sqlcomm = new SqlCommand(sqlquery, sqlconn);
        sqlcomm.Parameters.Add("@YourDate", SqlDbType.Date);
        sqlcomm.Parameters["@YourDate"].Value = date;

使用字符串连接构建查询时,建议您对日期使用 ISO 日期格式:

在 C# 中,我们可以使用u格式说明符来获取 SQL 的 ISO 日期,但它会在值后面附加一个Z ,以下是在字符串中使用它的简单方法:

date.ToString("u").TrimEnd('Z');

这相当于:

date.ToString("yyyy-MM-dd HH:mm:ss");

但是现在我们有一个问题,传入的日期参数是代表一整天,还是代表一个特定的时间点(为了这个查询的目的)? 您的要求是我们只想指定日期,不指定时间,因为我们可以使用这种格式:

date.ToString("yyyy-MM-dd")

现在我们遇到了一个新问题,在 SQL 中,如果您的数据包含时间值,那么您需要将数据截断为仅日期部分,以获取所提供日期的所有值。

所以现在您的查询如下所示:

string sqlquery = "SELECT UserID, Name, Mobile, Age, Date From tbluser where Cast([Date] as Date) = '"+date.ToString("yyyy-MM-dd")+"'";

where子句中使用 function 使得这是一个非 SARGABLE 查询,这对于数据库来说很难优化,通常通过使用BETWEEN并传入date和第二天的日期值可以获得更好的性能:

string sqlquery = "SELECT UserID, Name, Mobile, Age, Date From tbluser where [Date] BETWEEN '"+date.ToString("yyyy-MM-dd")+"' AND '"+date.AddDays(1). ToString("yyyy-MM-dd")+"'";

但是现在这个查询有点乱,我们应该使用参数来传递值,这样我们就不需要知道 ISO 日期和格式,ADO.Net 运行时会为我们处理。

参数化查询提供其他好处,例如 SQL 通过输入清理和其他处理优化防止注入

让我们更改查询以使用参数:

string sqlquery = "SELECT UserID, Name, Mobile, Age, Date From tbluser where Date BETWEEN @fromDate AND @toDate";

然后你需要将日期作为参数传递给SqlCommand

请注意,我们在DateTime object 上使用.ToDate()方法来修剪用户可能提供的时间部分。

SqlCommand sqlcomm = new SqlCommand(sqlquery, sqlconn);
sqlcomm.Parameters.Add("@fromDate ", SqlDbType.Date);
sqlcomm.Parameters["@fromDate "].Value = date.Date;
sqlcomm.Parameters.Add("@toDate ", SqlDbType.Date);
sqlcomm.Parameters["@toDate "].Value = date.AddDays(1).Date;

这是比较字符串连接 SQL 与参数化查询的好帖子: C#: SQL

更新请参阅此小提琴进行现场演示: https://dotnetfiddle.net/8zLLrR


Because your controller is pre-sanitizing the input and constraining it to a DateTime typed value, SQL Injection is not likely to be an issue in this specific example, however the string-concatenation approach to build your query is generally a red flag in Web API因为这是您的代码最容易受到外部输入影响的地方。

SQL 服务器有一个优化,它在重新执行查询时尝试重新使用执行计划。 当您第一次运行查询时,您会在 SSMS 中注意到,如果您重新执行相同的查询,它几乎总是比第二次慢。 那是因为它有一个存储执行计划的内部表,而您提交的SQL是该索引的主键。

当日期过滤器更改时,如果您使用字符串连接,这会导致不同的SQL ,因此数据库引擎更难查找现有的查询执行计划,并且在许多情况下它会生成一个新的查询执行计划。 当我们使用参数时,实际的SQL查询每次都是相同的,因此优化器可以简单地查找任何以前保存的执行计划。

SQL 服务器的更高版本有额外的优化,可以自动参数化执行计划索引的查询表达式,但这不是 100%,也不是懒惰的开发人员的借口;)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM