目录
介绍
要求
1.创建一个新的Web API项目
2.将Swagger添加到项目
3.将项目连接到SQL Server数据库
4.登录到SQL Server
5.添加“导出到Excel”
总结
自2016年发布以来,ASP.NET Core取得了惊人的进展,而且每个版本似乎都变得更好,更友好且对开发人员更友好。
Web API是对旧的WCF服务的巨大改进(我们甚至不谈论SOAP ...),并且那里有大量的“入门”资源。本文只是重新编写轮子而已,它只是您要做的以下步骤的“备忘单”:
除了第五项之外,这是我使用每个Web API都要执行的4个步骤,因此我认为最好尽可能快速,轻松地记录需要执行的步骤,我们有更多时间专注于完成实际工作!
现在,我已经提供了一个含有从本文的示例代码的MikesBank.zip文件,但我强烈建议你不使用它。
Visual Studio 2017和ASP.NET Core几乎每个月都在变化... 从零开始创建自己的项目并遵循这些说明是一个更好的主意,使用Microsoft在阅读本文时提供的任何新模板,而不是使用我提供的示例,在您读完本段时,该示例可能已经过时了一半。
祝您阅读愉快!
要阅读本文,您将需要:
我建议您先按照以下说明更新 VS2017和.NET Core的副本。在撰写本文时,我尝试导入一个VS2017很高兴接受的nuget软件包,但是随后抛出了很多编译错误,因为该nuget软件包比我的.NET Core版本更高,拒绝使用我的旧版本。
这个问题已经讨论了很多次了,我相信大家都知道该怎么做。
Visual Studio 2017将为您创建一个基本的API项目,该项目将返回一些硬编码的数据。
如果您在Chrome中运行该项目,则会看到几项JSON数据。
但是,如果您仍在使用Internet Explorer,则可能会收到一条奇怪的消息,询问“您是否要从本地主机打开或保存values.json(19个字节)? ”是的,这是2019年,而他们仍在这样做。我不知道为什么
作为开发人员,您可以(并且应该)通过添加从2010年开始的StackOverflow文章中描述的注册表项来解决此问题。这将使Internet Explorer实际上显示JSON数据,而不是困扰我们。
因此,我们现在有了Web API的起点。现在,让我们变得更好!
考虑到Visual Studio对开发人员的友好程度,当我们告诉我们正在创建Web API项目时,没有提供“为我的API创建Swagger页面”作为选项,我总是感到惊讶。但是,添加起来很容易。
要将Swagger添加到您的项目中:
1、右键单击您的项目名称,然后选择“管理NuGet软件包... ”
2、点击“浏览”标签,然后搜索并安装“swashbuckle.aspnetcore”
3、现在,您可以关闭此“nuget软件包管理器”屏幕。
4、打开“startup.cs ”文件,并对Configure()函数进行以下更改:
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json","MikesBank API");
c.RoutePrefix = string.Empty;
});
5、请注意,该RoutePrefix行...将使Swagger页面成为默认页面。因此,当我调试时,URL指向根路径时,将显示Swagger页面,例如:
https://localhost:44350/
6、接下来,我将简单的修改构造函数,并添加一个新的“env”变量:
public Startup(IHostingEnvironment env, IConfiguration configuration)
{
Configuration = configuration;
this.env = env;
}
private IHostingEnvironment env { get; }
有了这个,我们可以对ConfigureServices()函数进行更改:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
var pathIncludeXmlComments = $@"{env.ContentRootPath}\{env.ApplicationName}.xml";
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
{
Version = "v1",
Title = "MikesBank API",
Description = "For CodeProject"
});
if (System.IO.File.Exists(pathIncludeXmlComments))
c.IncludeXmlComments(pathIncludeXmlComments);
});
}
这有点臃肿,但是可以解决Swagger的问题。在我们的Web API控制器中添加注释通常很有用,Swagger会在其网页中显示这些注释。但是,如果.XML文件不存在,它会完全崩溃我们的应用程序,所以我非常小心,如果这仅包括注释的.xml文件不存在。
7、代码更改都已完成,但是现在,我们只需要对项目设置进行一些更改。再次右键单击您的项目名称,然后选择“属性”。然后,选择“构建”选项卡。
8、在“错误和警告”部分,将“ ;1591” 添加到要忽略的警告列表中。如果我们选择在Web API控制器中添加注释,那就太好了!但是,如果我们还没有添加注释,我不喜欢Visual Studio为我们的代码添加下划线。这不是错误/警告,因此我忽略此警告以忽略此类警告。
1701;1702;1591
9、仍在此屏幕上的“输出”部分中,选中“XML文档文件:” 框。
10、现在,跳至“调试”选项卡,然后从“启动浏览器”textbox中删除“api/values” ,使其保持空白。
如果现在运行项目,您将看到Swagger网站,以及VS2017为我们创建的示例端点的列表。
看起来不错!如果要运行简单的“获取所有值”功能,则可以单击第一GET行,单击“试用 ”按钮,然后单击“执行 ”按钮,然后将看到带有两个内容的像以前一样使用硬编码的值的响应正文。
好的,它不像Postman或Fiddler那样复杂,但是它是免费的,友好的并且非常有用。
使Swagger在此页面上包含注释就像在端点上方添加summary或remarks段一样简单:
///
/// This is the Summary, describing the endpoint
///
///
/// These are the Remarks for the endpoint
///
[HttpGet]
public ActionResult> Get()
{
return new string[] { "value1", "value2" };
}
请记住,Swagger本身确实会定期更新,并且在您阅读本文时(或者再次)更新一次,或者,如果您在搜索Swagger代码没有构建/显示时遇到的问题,请查看最新的文档。
好的,现在让我们将Web API链接到SQL Server数据库。为此,请再次进入“nuget软件包管理器”,搜索并安装以下三个软件包:
如果您更喜欢剪切而不是搜索,那么另一种方法是单击工具\Nuget软件包管理器\软件包管理器控制台,然后运行以下3个命令:
install-package Microsoft.EntityFrameworkCore.SqlServer
install-package Microsoft.EntityFrameworkCore.Tools
install-package Microsoft.EntityFrameworkCore.SqlServer.Design
无论哪种方式,这都会添加连接到SQL Server所需的3个程序包。
现在,我更喜欢使用“数据库优先”方法,在该方法中,我已经有一个“实时运行”的数据库,然后将其链接到我的Web API。在这篇文章中,我已经创建了我的本地服务器上的SQL Server数据库称为“Southwind”,它包含四个表,Location,Department,Employee和Logging。
如果您想继续学习,我提供了一个“Southwind.sql ”脚本,它将为您创建该数据库、表和数据。
实际上,我们可以使Visual Studio根据这些表的结构为我们创建类。为此,请打开软件包管理器控制台(单击工具\Nuget软件包管理器\软件包管理器控制台),然后输入以下命令,将您的数据库的连接字符串替换为我的连接字符串:
Scaffold-DbContext "Server=localhost;Database=Southwind;
Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models
这将为我们神奇地创建一个“SouthwindContext”类,以及四个类,每个数据库表一个。请注意,如果需要,可以通过使用-Tables参数,然后列出表名称,来要求某些(但不是全部)数据库表为其创建类。
Scaffold-DbContext "Server=localhost;Database=Southwind;
Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer
-OutputDir Models -Tables "Course","Lesson","User"
另请注意,如果您的代码当前未事先成功构建,则此Scaffold-DbContext命令将不起作用。因此,在运行该命令之前,请检查您的代码是否可以正常构建。
您可以在此处查看其他选项。
接下来,我们需要告知我们的appsettings.json文件有关数据库连接的信息,因此请打开此文件,并将其添加到顶部:
"ConnectionStrings": {
"SouthwindDatabase": "Server=.;Database=Southwind;Trusted_Connection=True;"
},
现在,打开startup.cs,并将其添加到ConfigureServices()函数中:
var ConnectionString = Configuration.GetConnectionString("SouthwindDatabase");
services.AddDbContext(options =>
options.UseSqlServer(ConnectionString)
);
在继续之前,我们需要确保此代码成功构建,但是现在,由于缺少两个using语句,因此它不会。您可以在Startup.cs顶部手动添加它们:
using Microsoft.EntityFrameworkCore;
using MikesBank.Models;
...或者您可以在上面的代码中单击SouthwindContext和UseSqlServer,然后使用“CTRL” +“.”使Visual Studio 为您添加using语句。
如果您尝试再次构建,则它现在应该可以成功构建,我们可以继续。
现在,我们具有将数据库CRUD操作添加到Web API的所有构造块。
删除Controllers文件夹中的ValuesController.cs文件,然后右键单击Controllers文件夹,选择添加\控制器,选择最后一个选项“使用实体框架进行操作的API控制器”,然后单击添加。
现在,您可以选择一个模型,并获取Visual Studio为您创建一组端点。我将选择Employee模型:
然后,单击“添加”按钮,就这样,我们为其中一个表设置了一组CRUD端点。
我们甚至可以进入控制器文件(在我的示例中为“EmployeeController.cs”),并修改注释,以使其对Swagger更友好。只需删除现有注释,然后将光标放在[HttpGet]上方的空白行上,键入///,Visual Studio将为您提供占位符以键入您的注释。
///
/// Load a list of all employee records from the database
///
///
/// An enumerable list of Employee records
///
[HttpGet]
public async Task>> GetEmployee()
{
return await _context.Employee.ToListAsync();
}
如果我们现在运行项目,将显示Swagger页面,我们可以为Employees端点选择的GET,并获取所有employees列表。
在这一点上,我(个人)会做一个小小的改变:通常情况下,当我得到Employee记录的列表,我不希望包括每条记录的整个层次(其中每个employee属于哪个department,并且这个department所在的location),我只想要Employee记录,仅此而已。
您可以通过打开Employee.cs文件并在virtual字段之前添加[JsonIgnore]来防止序列化整个层次结构(您还需要使用CTRL +“.”技巧来获取Visual Studio为此添加一条using语句) :
[JsonIgnore]
public virtual Department Dep { get; set; }
[JsonIgnore]
public virtual Employee EmpManager { get; set; }
[JsonIgnore]
public virtual ICollection InverseEmpManager { get; set; }
您还可以更改Startup.cs中的AddMvc()设置,以防止JSON.Net在获取每个Employee记录的太多父/所有者时有点失控:
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(
options => options.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
进行此更改后,我仅收到Employee记录列表,仅此而已。
这就是我们使Web API连接到SQL Server数据库以及向SQL Server数据库读取/写入数据的方式。我很乐意为此效劳,但是正如您所看到的,Visual Studio为我们做了(几乎)所有工作。我们只需要记住要采取的步骤。
现在,当发生错误/异常时,我真的不喜欢它,并且错误字符串只是进入存储在IIS服务器上某个位置的一些随机.txt文件。将消息发送到SQL Server上的Logging表要有用得多,因此我们可以跟踪此类问题,也许可以在“日志查看器 ”屏幕上列出这些问题,以供管理员跟踪,保存堆栈跟踪等等。
当然,有一个陷阱:如果由于无法连接数据库而引发了异常,那么……好吧……肯定不会将异常消息存储在数据库中,因为它找不到!
当然,我们可以使用第三方(例如nLog)来处理日志,但是就我个人而言,我更喜欢自己做。
首先,如您所见,我的SQL Server数据库中有一个Logging表。
没有什么复杂的。的Log_Severity,(异常)Log_Message和Log_StackTrace字段将全部来自刚刚发生的任何异常,我有一个“Log_Source”字段,我们可以填充该字段来说明应用程序的哪个区域引发了异常。
哦,我的“Update_Time”字段(我的每个表中都有一个)始终包含UTC timezone中的日期时间。我们很可能在不同国家/地区拥有用户,他们希望在当地时间知道何时发生异常。
要在我们的代码中使用此(或任何其他)表结构,这是我们需要做的。
public void Configure(IApplicationBuilder app,
IHostingEnvironment env, ILoggerFactory loggerFactory)
现在,我们可以在Configure()函数中添加以下几行:
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
// The following "AddContext" comes from our DBLoggerExtensions class.
// We will log any errors of Information of higher.
// (Trace=0, Debug=1, Information=2, Warning=3, Error=4, Critical=5, None=6)
loggerFactory.AddContext(LogLevel.Information,
Configuration.GetConnectionString("SouthwindDatabase"));
此时,如果您尝试构建项目,则可能会收到一条错误消息,说ILoggerFactory中不包含“AddContext” 的定义。要解决此问题,我们需要告诉它扩展方法在哪里。在Startup.cs的顶部,添加以下行:
using MikesBank.LogProvider;
现在,让我们开始吧。
现在,在EmployeesController.cs中,可以添加日志记录。为此,我需要添加一个新变量:
private readonly ILogger logger;
以及新的using声明...
using Microsoft.Extensions.Logging;
然后,我可以修改构造函数:
public EmployeesController(SouthwindContext context, ILoggerFactory loggerFactory)
{
_context = context;
logger = loggerFactory.CreateLogger();
}
就是这样!
现在,您可以高兴地滑动是尽可能多的LogInformation,LogWarning或LogErrors。例如:
[HttpGet]
public async Task>> GetEmployee()
{
logger.LogInformation("Loading a list of Employee records");
return await _context.Employee.ToListAsync();
}
不过,这只是一个恼人的问题。运行此代码,并调用GET端点之后,我确实在Logging中收到了“员工记录的加载列表”消息,但我也从幕后获得了大量消息。就个人而言,我发现这些内容使查找我真正感兴趣的Log消息变得异常困难,并且希望将其关闭。
为此,您可以进入appsettings.Development.json文件,并修改Microsoft和System库中将包括的日志消息类型。如果将它们更改为“Warning”,则您的日志将不会填满所有这些额外的Entity Framework消息。
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Warning",
"Microsoft": "Warning"
}
}
}
显然,这是可选的,也许您会希望在开发版本中看到这些详细信息。由你决定。
最后一件事。
我对某些API的最大烦恼之一是可怕的“HTTP响应500:内部服务器错误”。当您自己的API抛出此异常时,通常是因为出了点问题,您的代码也没有费心去解决问题或优雅地处理它。
而且,当然,因为您还没有捕获到异常,所以您当然不会尝试将其发送到日志,以便您的开发人员和支持团队可以调查原因。因此,请将每个端点包装在try...catch中,并确保所有异常消息最终出现在Logging表中。
这很容易做到,但是以后会少掉很多头发。
public async Task>> GetEmployee()
{
try
{
logger.LogInformation("Loading a list of Employee records");
return await _context.Employee.ToListAsync();
}
catch (Exception ex)
{
logger.LogError(ex, "An exception occurred in the GetEmployee() endpoint");
return new BadRequestObjectResult(ex.Message);
}
}
显然,在生产版本中,您可能不希望如上所述返回完整的异常消息,并且可以根据需要进行修改。
是的,我知道...很可能,我们没人会添加Web API端点,该端点返回一个原始Excel文件,其中包含来自一个表的所有数据。但是,我们已经走了这么远,并且因为它是如此的简单,所以让我们看看我们将如何做到。如果没有其他要求,这对您的其他ASP.NET Core项目也很有用。
首先,我们需要最后一次进入“NuGet软件包管理器”,并安装“DocumentFormat.OpenXml”软件包。即使我们的服务器上没有Excel,这也使我们可以创建Excel文件(* .xlsx)。
接下来,在您的项目中创建一个名为Helpers的文件夹,并将附加的CreateExcelFile.cs保存到该文件夹中。
有了此文件后,我们就可以开始了。
将导出端点添加到控制器的操作非常简单,只需加载数据,然后调用StreamExcelDocument函数,将要导出的数据和要使用的文件名传递给它即可:
[HttpGet("ExportToExcel")]
public async Task ExportEmployeesToExcel()
{
try
{
List employees = await _context.Employee.ToListAsync();
FileStreamResult fr = ExportToExcel.CreateExcelFile.StreamExcelDocument
(employees, "Employees.xlsx");
return fr;
}
catch (Exception ex)
{
return new BadRequestObjectResult(ex);
}
}
多么简单!
作为一个在金融行业工作过的人,让我告诉你,拥有一个简单的、可重用的“导出到Excel”功能是非常棒的。这是我的客户要求的第一个功能,每次……他们喜欢自己的Excel!
就是这样!
现在,我们有了一个不错的ASP.NET Core Web API项目,它具有友好的Swagger页面,SQL Server连接和日志记录。如果我们真的想在下一次工作面试中留下深刻的印象,并且能够告诉他们您的API支持“CRUDE” ,那么还可以加上“导出到Excel ”。