个人正在学习.net web Api的相关知识,因此用这一系列博客做一记录。
1. 首先我们分别创建 .net web api 项目和 .net core web api 项目。
2. 我们首先比较一下两个项目的目录结构。
下图中是用 vs2017 创建的 .net web api(左)和.net core web api(右) 项目。
从目录结构上我们可以看出 .net web api 除了controller 意外还保留了view, model 和一些放静态文件(fonts, script, content)的文件夹,除此之外还有area 文件夹,学过 asp.net mvc的同学应该会了解area的概念,我们不再赘述。
除此之外还有favorite.ico 文件,如果我们用这个项目作为一个单纯的web api 项目我们会发现除了model以外以上提到的其他的我们都可以完全删除。
然后是web.config 来管理我们asp.net 的一些相关配置,在.net core web api 项目中有类似作用的appsettings.json 文件,如果我们需要发布.net core web api 到IIS上也需要加上我们自己的web.config文件。
packages.config 文件是包管理相关的配置文件。
3. 入口文件比较
Global.asax.cs 文件是.net web api 的入口文件(因为我建立的是基于 MVC 的web api项目,因此入口文件跟asp.net mvc 是一样的)。由下面的代码我们可以看出来在WebApiApplication类里面的Application_Statr 方法里面注册了项目所需要的一些配置。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; namespace FreWebApi { public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); //注册area GlobalConfiguration.Configure(WebApiConfig.Register); //注册web api 路由 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);//注册全局过滤器 RouteConfig.RegisterRoutes(RouteTable.Routes);//注册asp.net mvc 路由,当项目单纯用于作为api使用可以不注册asp.net 路由 BundleConfig.RegisterBundles(BundleTable.Bundles);// 注册bundles 也不是web api所必须的 } } }
而.net core web api 项目的入口文件是Program.cs 文件。从下面的代码我们可以看出来我们的入口方法是Program类里面的Main方法(是不是很熟悉的感觉),从code上我们可以看出只是在Main方法里面调用了CreateWebHostBuilder方法。
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace CoreWebApi { public class Program { ////// 入口是 Main 方法看起来跟console项目有些类似。 /// /// public static void Main(string[] args) { CreateWebHostBuilder(args).Build().Run();//在 Main 方法直接调用下面的CreateWebHostBuilder方法。 } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup (); } }
学过Asp.net MVC 的同学大家都知道,在Application_Statr注册的配置项其实都是在App_Start文件夹里面,下面我们展开这个文件夹。
从上图中的文件来看我们很容易看出来对应的配置在那个文件里面,前面提到过RouteConfig和BundleConfig不是wenApi所必须的所以我们还是重点来看一些WebApiConfig和FilterConfig.
1) FilterConfig: 这个类里面默认添加了HandleErrorAttribute这是一个全局过滤器,主要用于处理异常。
using System.Web; using System.Web.Mvc; namespace FreWebApi { public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); } } }
2)WebApiConfig: 注册了webApi的路由,这些路由是在HttpConfiguration实例的Routes集合属性里面,这里我们注意我们这里注册的都是http路由,当注册asp.net mvc 路由时,是放在RouteTable.Routes集合里面。
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; namespace FreWebApi { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服务 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } }
说到这里有的同学可能会奇怪我们的 .net core web API的各种配置又在哪里呢?我们接着看我们入口类里面的CreateWebHostBuilder方法,在这个方法里面用Lambda表达式调用了WebHost的CreateDefaultBuilder方法,官网的解释如下:
Initializes a new instance of the WebHostBuilder class with pre-configured defaults. 使用预先配置的默认值初始化WebHostBuilder类的新实例。
如果需要获取详细信息的同学,可以参见其他专门将asp.net 的博客这里我们只将项目结构。然后我们调用的这个实例的UseStartup方法,官网解释如下:
Specify the startup type to be used by the web host.
指定Web Host要使用的启动类.
同样的我们对此不做深究,但我们可以从解释中看出来这里指定了启动类,然后我们打开传入的泛型类Startup,我们打开Startup.cs文件,查看里面的代码:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpsPolicy; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace CoreWebApi { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseMvc(); } } }
从上面的code上我们可以看到里面有ConfigService方法和Config方法,但是我们并没有看到类似与.net web api的关于注册路由或者过滤器的任何code,不要慌我们来改写一下ConfigService和config方法。
public void ConfigureServices(IServiceCollection services) { services.AddMvc( options => { options.Filters.Add(); // an instance } ).SetCompatibilityVersion(CompatibilityVersion.Version_2_2); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseMvc( routes => routes.MapRoute( name: "default", template: "{ controller}/{ action}/{ id}" ) ); }
从上面改写以后的方法里面我们就可以清晰的看到过滤器和路由的配置了。
最后我们来展开controllers文件夹:
从下图中我们看到 .net web api生产了两个默认的controller,让我们查看两个controller的定义:
由下面的代码我们明显的看到HomenController是为Asp.Net mvc准备的,继承于Controller类,而ValuesController才是我们真正需要的web api的controller继承于ApiController 类。
public class HomeController : Controller public class ValuesController : ApiController
最后我们来比较一下两个Api的controller:
从下图中我们可以看出两个API的主要不用在于controller的父类不同,然后是asp.net core 默认使用了路由属性,这也是它可以再config里面默认没有配置路由的原因。