用Middleware给ASP.NET Core Web API添加自己的授权验证

  Web API,是一个能让前后端分离、解放前后端生产力的好东西。不过大部分公司应该都没能做到完全的前后端分离。API的实现方式有很

多,可以用ASP.NET Core、也可以用ASP.NET Web API、ASP.NET MVC、NancyFx等。说到Web API,不同的人有不同的做法,可能前台、

中台和后台各一个api站点,也有可能一个模块一个api站点,也有可能各个系统共用一个api站点,当然这和业务有必然的联系。

  安全顺其自然的成为Web API关注的重点之一。现在流行的OAuth 2.0是个很不错的东西,不过本文是暂时没有涉及到的,只是按照最最最

原始的思路做的一个授权验证。在之前的MVC中,我们可能是通过过滤器来处理这个身份的验证,在Core中,我自然就是选择Middleware来处

理这个验证。

  下面开始本文的正题:

  先编写一个能正常运行的api,不进行任何的权限过滤。

 1 using Dapper;
 2 using Microsoft.AspNetCore.Mvc;
 3 using System.Data;
 4 using System.Linq;
 5 using System.Threading.Tasks;
 6 using WebApi.CommandText;
 7 using WebApi.Common;
 8 using Common;
 9
10 namespace WebApi.Controllers
11 {
12     [Route("api/[controller]")]
13     public class BookController : Controller
14     {
15
16         private DapperHelper _helper;
17         public BookController(DapperHelper helper)
18         {
19             this._helper = helper;
20         }
21
22         // GET: api/book
23         [HttpGet]
24         public async Task<IActionResult> Get()
25         {
26             var res = await _helper.QueryAsync(BookCommandText.GetBooks);
27             CommonResult<Book> json = new CommonResult<Book>
28             {
29                 Code = "000",
30                 Message = "ok",
31                 Data = res
32             };
33             return Ok(json);
34         }
35
36         // GET api/book/5
37         [HttpGet("{id}")]
38         public IActionResult Get(int id)
39         {
40             DynamicParameters dp = new DynamicParameters();
41             dp.Add("@Id", id, DbType.Int32, ParameterDirection.Input);
42             var res = _helper.Query<Book>(BookCommandText.GetBookById, dp, null, true, null, CommandType.StoredProcedure).FirstOrDefault();
43             CommonResult<Book> json = new CommonResult<Book>
44             {
45                 Code = "000",
46                 Message = "ok",
47                 Data = res
48             };
49             return Ok(json);
50         }
51
52         // POST api/book
53         [HttpPost]
54         public IActionResult Post([FromForm]PostForm form)
55         {
56             DynamicParameters dp = new DynamicParameters();
57             dp.Add("@Id", form.Id, DbType.Int32, ParameterDirection.Input);
58             var res = _helper.Query<Book>(BookCommandText.GetBookById, dp, null, true, null, CommandType.StoredProcedure).FirstOrDefault();
59             CommonResult<Book> json = new CommonResult<Book>
60             {
61                 Code = "000",
62                 Message = "ok",
63                 Data = res
64             };
65             return Ok(json);
66         }
67
68     }
69
70     public class PostForm
71     {
72         public string Id { get; set; }
73     }
74
75 }

  api这边应该没什么好说的,都是一些常规的操作,会MVC的应该都可以懂。主要是根据id获取图书信息的方法(GET和POST)。这是我们后

面进行单元测试的两个主要方法。这样部署得到的一个API站点,是任何一个人都可以访问http://yourapidomain.com/api/book 来得到相关

的数据。现在我们要对这个api进行一定的处理,让只有权限的站点才能访问它。

  下面就是编写自定义的授权验证中间件了。

  Middleware这个东西大家应该都不会陌生了,OWIN出来的时候就有中间件这样的概念了,这里就不展开说明,在ASP.NET Core中是如何

实现这个中间件的可以参考官方文档 Middleware

  我们先定义一个我们要用到的option,ApiAuthorizedOptions

 1 namespace WebApi.Middlewares
 2 {
 3     public class ApiAuthorizedOptions
 4     {
 5         //public string Name { get; set; }
 6
 7         public string EncryptKey { get; set; }
 8
 9         public int ExpiredSecond { get; set; }
10     }
11 }

  option内容比较简单,一个是EncryptKey ,用于对我们的请求参数进行签名,另一个是ExpiredSecond ,用于检验我们的请求是否超时。

与之对应的是在appsettings.json中设置的ApiKey节点

1   "ApiKey": {
2     //"username": "123",
3     //"password": "123",
4     "EncryptKey": "@*api#%^@",
5     "ExpiredSecond": "300"
6   }

  有了option,下面就可以编写middleware的内容了

  我们的api中就实现了get和post的方法,所以这里也就对get和post做了处理,其他http method,有需要的可以自己补充。

  这里的验证主要是下面的几个方面:

  1.参数是否被篡改

  2.请求是否已经过期

  3.请求的应用是否合法

  主检查方法:Check

 1          /// <summary>
 2         /// the main check method
 3         /// </summary>
 4         /// <param name="context"></param>
 5         /// <param name="requestInfo"></param>
 6         /// <returns></returns>
 7         private async Task Check(HttpContext context, RequestInfo requestInfo)
 8         {
 9             string computeSinature = HMACMD5Helper.GetEncryptResult($"{requestInfo.ApplicationId}-{requestInfo.Timestamp}-{requestInfo.Nonce}", _options.EncryptKey);
10             double tmpTimestamp;
11             if (computeSinature.Equals(requestInfo.Sinature) &&
12                 double.TryParse(requestInfo.Timestamp, out tmpTimestamp))
13             {
14                 if (CheckExpiredTime(tmpTimestamp, _options.ExpiredSecond))
15                 {
16                     await ReturnTimeOut(context);
17                 }
18                 else
19                 {
20                     await CheckApplication(context, requestInfo.ApplicationId, requestInfo.ApplicationPassword);
21                 }
22             }
23             else
24             {
25                 await ReturnNoAuthorized(context);
26             }
27         }

  Check方法带了2个参数,一个是当前的httpcontext对象和请求的内容信息,当签名一致,并且时间戳能转化成double时才去校验是否超时

和Applicatioin的相关信息。这里的签名用了比较简单的HMACMD5加密,同样是可以换成SHA等加密来进行这一步的处理,加密的参数和规则是

随便定的,要有一个约定的过程,缺少灵活性(就像跟银行对接那样,银行说你就要这样传参数给我,不这样就不行,只好乖乖从命)。

  Check方法还用到了下面的4个处理

  1.子检查方法--超时判断CheckExpiredTime

 1          /// <summary>
 2         /// check the expired time
 3         /// </summary>
 4         /// <param name="timestamp"></param>
 5         /// <param name="expiredSecond"></param>
 6         /// <returns></returns>
 7         private bool CheckExpiredTime(double timestamp, double expiredSecond)
 8         {
 9             double now_timestamp = (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
10             return (now_timestamp - timestamp) > expiredSecond;
11         }

  这里取了当前时间与1970年1月1日的间隔与请求参数中传过来的时间戳进行比较,是否超过我们在appsettings中设置的那个值,超过就是

超时了,没超过就可以继续下一个步骤。

  2.子检查方法--应用程序判断CheckApplication

  应用程序要验证什么呢?我们会给每个应用程序创建一个ID和一个访问api的密码,所以我们要验证这个应用程序的真实身份,是否是那些

有权限的应用程序。

 1         /// <summary>
 2         /// check the application
 3         /// </summary>
 4         /// <param name="context"></param>
 5         /// <param name="applicationId"></param>
 6         /// <param name="applicationPassword"></param>
 7         /// <returns></returns>
 8         private async Task CheckApplication(HttpContext context, string applicationId, string applicationPassword)
 9         {
10             var application = GetAllApplications().Where(x => x.ApplicationId == applicationId).FirstOrDefault();
11             if (application != null)
12             {
13                 if (application.ApplicationPassword != applicationPassword)
14                 {
15                     await ReturnNoAuthorized(context);
16                 }
17             }
18             else
19             {
20                 await ReturnNoAuthorized(context);
21             }
22         }

  先根据请求参数中的应用程序id去找到相应的应用程序,不能找到就说明不是合法的应用程序,能找到再去验证其密码是否正确,最后才确

定其能否取得api中的数据。

  下面两方法是处理没有授权和超时处理的实现:

  没有授权的返回方法ReturnNoAuthorized

 1         /// <summary>
 2         /// not authorized request
 3         /// </summary>
 4         /// <param name="context"></param>
 5         /// <returns></returns>
 6         private async Task ReturnNoAuthorized(HttpContext context)
 7         {
 8             BaseResponseResult response = new BaseResponseResult
 9             {
10                 Code = "401",
11                 Message = "You are not authorized!"
12             };
13             context.Response.StatusCode = 401;
14             await context.Response.WriteAsync(JsonConvert.SerializeObject(response));
15         }

  这里做的处理是将响应的状态码设置成401(Unauthorized)。

  超时的返回方法ReturnTimeOut

 1         /// <summary>
 2         /// timeout request
 3         /// </summary>
 4         /// <param name="context"></param>
 5         /// <returns></returns>
 6         private async Task ReturnTimeOut(HttpContext context)
 7         {
 8             BaseResponseResult response = new BaseResponseResult
 9             {
10                 Code = "408",
11                 Message = "Time Out!"
12             };
13             context.Response.StatusCode = 408;
14             await context.Response.WriteAsync(JsonConvert.SerializeObject(response));
15         }

  这里做的处理是将响应的状态码设置成408(Time Out)。

  下面就要处理Http的GET请求和POST请求了。

  HTTP GET请求的处理方法GetInvoke

 1         /// <summary>
 2         /// http get invoke
 3         /// </summary>
 4         /// <param name="context"></param>
 5         /// <returns></returns>
 6         private async Task GetInvoke(HttpContext context)
 7         {
 8             var queryStrings = context.Request.Query;
 9             RequestInfo requestInfo = new RequestInfo
10             {
11                 ApplicationId = queryStrings["applicationId"].ToString(),
12                 ApplicationPassword = queryStrings["applicationPassword"].ToString(),
13                 Timestamp = queryStrings["timestamp"].ToString(),
14                 Nonce = queryStrings["nonce"].ToString(),
15                 Sinature = queryStrings["signature"].ToString()
16             };
17             await Check(context, requestInfo);
18         }

  处理比较简单,将请求的参数赋值给RequestInfo,然后将当前的httpcontext和这个requestinfo交由我们的主检查方法Check去校验

这个请求的合法性。

  同理,HTTP POST请求的处理方法PostInvoke,也是同样的处理。

 1         /// <summary>
 2         /// http post invoke
 3         /// </summary>
 4         /// <param name="context"></param>
 5         /// <returns></returns>
 6         private async Task PostInvoke(HttpContext context)
 7         {
 8             var formCollection = context.Request.Form;
 9             RequestInfo requestInfo = new RequestInfo
10             {
11                 ApplicationId = formCollection["applicationId"].ToString(),
12                 ApplicationPassword = formCollection["applicationPassword"].ToString(),
13                 Timestamp = formCollection["timestamp"].ToString(),
14                 Nonce = formCollection["nonce"].ToString(),
15                 Sinature = formCollection["signature"].ToString()
16             };
17             await Check(context, requestInfo);
18         }

  最后是Middleware的构造函数和Invoke方法。

 1        public ApiAuthorizedMiddleware(RequestDelegate next, IOptions<ApiAuthorizedOptions> options)
 2         {
 3             this._next = next;
 4             this._options = options.Value;
 5         }
 6
 7         public async Task Invoke(HttpContext context)
 8         {
 9             switch (context.Request.Method.ToUpper())
10             {
11                 case "POST":
12                     if (context.Request.HasFormContentType)
13                     {
14                         await PostInvoke(context);
15                     }
16                     else
17                     {
18                         await ReturnNoAuthorized(context);
19                     }
20                     break;
21                 case "GET":
22                     await GetInvoke(context);
23                     break;
24                 default:
25                     await GetInvoke(context);
26                     break;
27             }
28             await _next.Invoke(context);
29         }

  到这里,Middleware是已经编写好了,要在Startup中使用,还要添加一个拓展方法ApiAuthorizedExtensions

 1 using Microsoft.AspNetCore.Builder;
 2 using Microsoft.Extensions.Options;
 3 using System;
 4
 5 namespace WebApi.Middlewares
 6 {
 7     public static class ApiAuthorizedExtensions
 8     {
 9         public static IApplicationBuilder UseApiAuthorized(this IApplicationBuilder builder)
10         {
11             if (builder == null)
12             {
13                 throw new ArgumentNullException(nameof(builder));
14             }
15
16             return builder.UseMiddleware<ApiAuthorizedMiddleware>();
17         }
18
19         public static IApplicationBuilder UseApiAuthorized(this IApplicationBuilder builder, ApiAuthorizedOptions options)
20         {
21             if (builder == null)
22             {
23                 throw new ArgumentNullException(nameof(builder));
24             }
25
26             if (options == null)
27             {
28                 throw new ArgumentNullException(nameof(options));
29             }
30
31             return builder.UseMiddleware<ApiAuthorizedMiddleware>(Options.Create(options));
32         }
33     }
34 }

  到这里我们已经可以在Startup的Configure和ConfigureServices方法中配置这个中间件了

  这里还有一个不一定非要实现的拓展方法ApiAuthorizedServicesExtensions,但我个人还是倾向于实现这个ServicesExtensions。

 1 using Microsoft.Extensions.DependencyInjection;
 2 using System;
 3
 4 namespace WebApi.Middlewares
 5 {
 6     public static class ApiAuthorizedServicesExtensions
 7     {
 8
 9         /// <summary>
10         /// Add response compression services.
11         /// </summary>
12         /// <param name="services">The <see cref="IServiceCollection"/> for adding services.</param>
13         /// <returns></returns>
14         public static IServiceCollection AddApiAuthorized(this IServiceCollection services)
15         {
16             if (services == null)
17             {
18                 throw new ArgumentNullException(nameof(services));
19             }
20
21             return services;
22         }
23
24         /// <summary>
25         /// Add response compression services and configure the related options.
26         /// </summary>
27         /// <param name="services">The <see cref="IServiceCollection"/> for adding services.</param>
28         /// <param name="configureOptions">A delegate to configure the <see cref="ResponseCompressionOptions"/>.</param>
29         /// <returns></returns>
30         public static IServiceCollection AddApiAuthorized(this IServiceCollection services, Action<ApiAuthorizedOptions> configureOptions)
31         {
32             if (services == null)
33             {
34                 throw new ArgumentNullException(nameof(services));
35             }
36             if (configureOptions == null)
37             {
38                 throw new ArgumentNullException(nameof(configureOptions));
39             }
40
41             services.Configure(configureOptions);
42             return services;
43         }
44     }
45 }

ApiAuthorizedServicesExtensions

  为什么要实现这个拓展方法呢?个人认为

  Options、Middleware、Extensions、ServicesExtensions这四个是实现一个中间件的标配(除去简单到不行的那些中间件)

  Options给我们的中间件提供了一些可选的处理,提高了中间件的灵活性;

  Middleware是我们中间件最最重要的实现;

  Extensions是我们要在Startup的Configure去表明我们要使用这个中间件;

  ServicesExtensions是我们要在Startup的ConfigureServices去表明我们把这个中间件添加到容器中。

  下面是完整的Startup

 1 using Microsoft.AspNetCore.Builder;
 2 using Microsoft.AspNetCore.Hosting;
 3 using Microsoft.Extensions.Configuration;
 4 using Microsoft.Extensions.DependencyInjection;
 5 using Microsoft.Extensions.Logging;
 6 using System;
 7 using WebApi.Common;
 8 using WebApi.Middlewares;
 9
10 namespace WebApi
11 {
12     public class Startup
13     {
14         public Startup(IHostingEnvironment env)
15         {
16             var builder = new ConfigurationBuilder()
17                 .SetBasePath(env.ContentRootPath)
18                 .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
19                 .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
20
21             if (env.IsEnvironment("Development"))
22             {
23                 // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
24                 builder.AddApplicationInsightsSettings(developerMode: true);
25             }
26
27             builder.AddEnvironmentVariables();
28             Configuration = builder.Build();
29         }
30
31         public IConfigurationRoot Configuration { get; }
32
33         // This method gets called by the runtime. Use this method to add services to the container
34         public void ConfigureServices(IServiceCollection services)
35         {
36             // Add framework services.
37             services.AddApplicationInsightsTelemetry(Configuration);
38             services.Configure<IISOptions>(options =>
39             {
40
41             });
42
43             services.Configure<DapperOptions>(options =>
44             {
45                 options.ConnectionString = Configuration.GetConnectionString("DapperConnection");
46             });
47
48             //api authorized middleware
49             services.AddApiAuthorized(options =>
50             {
51                 options.EncryptKey = Configuration.GetSection("ApiKey")["EncryptKey"];
52                 options.ExpiredSecond = Convert.ToInt32(Configuration.GetSection("ApiKey")["ExpiredSecond"]);
53             });
54
55
56             services.AddMvc();
57
58             services.AddSingleton<DapperHelper>();
59         }
60
61         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline
62         public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
63         {
64
65             loggerFactory.AddConsole(Configuration.GetSection("Logging"));
66             loggerFactory.AddDebug();
67
68             app.UseDapper();
69
70             //api authorized middleware
71             app.UseApiAuthorized();
72
73             app.UseApplicationInsightsRequestTelemetry();
74
75             app.UseApplicationInsightsExceptionTelemetry();
76
77             app.UseMvc();
78         }
79     }
80 }

  万事具备,只欠测试!!

  建个类库项目,写个单元测试看看。

 1 using Common;
 2 using Newtonsoft.Json;
 3 using System;
 4 using System.Collections.Generic;
 5 using System.Net.Http;
 6 using System.Threading.Tasks;
 7 using Xunit;
 8
 9 namespace WebApiTest
10 {
11     public class BookApiTest
12     {
13         private HttpClient _client;
14         private string applicationId = "1";
15         private string applicationPassword = "123";
16         private string timestamp = (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds.ToString();
17         private string nonce = new Random().Next(1000, 9999).ToString();
18         private string signature = string.Empty;
19
20         public BookApiTest()
21         {
22             _client = new HttpClient();
23             _client.BaseAddress = new Uri("http://localhost:8091/");
24             _client.DefaultRequestHeaders.Clear();
25             signature = HMACMD5Helper.GetEncryptResult($"{applicationId}-{timestamp}-{nonce}", "@*api#%^@");
26         }
27
28         [Fact]
29         public async Task book_api_get_by_id_should_success()
30         {
31             string queryString = $"applicationId={applicationId}&timestamp={timestamp}&nonce={nonce}&signature={signature}&applicationPassword={applicationPassword}";
32
33             HttpResponseMessage message = await _client.GetAsync($"api/book/4939?{queryString}");
34             var result = JsonConvert.DeserializeObject<CommonResult<Book>>(message.Content.ReadAsStringAsync().Result);
35
36             Assert.Equal("000", result.Code);
37             Assert.Equal(4939, result.Data.Id);
38             Assert.True(message.IsSuccessStatusCode);
39         }
40
41         [Fact]
42         public async Task book_api_get_by_id_should_failure()
43         {
44             string inValidSignature = Guid.NewGuid().ToString();
45             string queryString = $"applicationId={applicationId}&timestamp={timestamp}&nonce={nonce}&signature={inValidSignature}&applicationPassword={applicationPassword}";
46
47             HttpResponseMessage message = await _client.GetAsync($"api/book/4939?{queryString}");
48             var result = JsonConvert.DeserializeObject<CommonResult<Book>>(message.Content.ReadAsStringAsync().Result);
49
50             Assert.Equal("401", result.Code);
51             Assert.Equal(System.Net.HttpStatusCode.Unauthorized, message.StatusCode);
52         }
53
54         [Fact]
55         public async Task book_api_post_by_id_should_success()
56         {
57             var data = new Dictionary<string, string>();
58             data.Add("applicationId", applicationId);
59             data.Add("applicationPassword", applicationPassword);
60             data.Add("timestamp", timestamp);
61             data.Add("nonce", nonce);
62             data.Add("signature", signature);
63             data.Add("Id", "4939");
64             HttpContent ct = new FormUrlEncodedContent(data);
65
66             HttpResponseMessage message = await _client.PostAsync("api/book", ct);
67             var result = JsonConvert.DeserializeObject<CommonResult<Book>>(message.Content.ReadAsStringAsync().Result);
68
69             Assert.Equal("000", result.Code);
70             Assert.Equal(4939, result.Data.Id);
71             Assert.True(message.IsSuccessStatusCode);
72
73         }
74
75         [Fact]
76         public async Task book_api_post_by_id_should_failure()
77         {
78             string inValidSignature = Guid.NewGuid().ToString();
79             var data = new Dictionary<string, string>();
80             data.Add("applicationId", applicationId);
81             data.Add("applicationPassword", applicationPassword);
82             data.Add("timestamp", timestamp);
83             data.Add("nonce", nonce);
84             data.Add("signature", inValidSignature);
85             data.Add("Id", "4939");
86             HttpContent ct = new FormUrlEncodedContent(data);
87
88             HttpResponseMessage message = await _client.PostAsync("api/book", ct);
89             var result = JsonConvert.DeserializeObject<CommonResult<Book>>(message.Content.ReadAsStringAsync().Result);
90
91             Assert.Equal("401", result.Code);
92             Assert.Equal(System.Net.HttpStatusCode.Unauthorized, message.StatusCode);
93         }
94     }
95 }

  测试用的是XUnit。这里写了get和post的测试用例。

  下面来看看测试的效果。

  测试通过。这里是直接用VS自带的测试窗口来运行测试,比较直观。

  当然也可以通过我们的dotnet test命令来运行测试。

  本文的Demo已经上传到Github:

  https://github.com/hwqdt/Demos/tree/master/src/ASPNETCoreAPIAuthorizedDemo

  Thanks for your reading!

时间: 2024-11-07 21:27:55

用Middleware给ASP.NET Core Web API添加自己的授权验证的相关文章

[转]用Middleware给ASP.NET Core Web API添加自己的授权验证

本文转自:http://www.cnblogs.com/catcher1994/p/6021046.html Web API,是一个能让前后端分离.解放前后端生产力的好东西.不过大部分公司应该都没能做到完全的前后端分离.API的实现方式有很 多,可以用ASP.NET Core.也可以用ASP.NET Web API.ASP.NET MVC.NancyFx等.说到Web API,不同的人有不同的做法,可能前台. 中台和后台各一个api站点,也有可能一个模块一个api站点,也有可能各个系统共用一个a

asp.net core web api token验证和RestSharp访问

对与asp.net core web api验证,多种方式,本例子的方式采用的是李争的<微软开源跨平台移动开发实践>中的token验证方式. Asp.net core web api项目代码: 首先定义三个Token相关的类,一个Token实体类,一个TokenProvider类,一个TokenProviderOptions类 代码如下: /// <summary> /// Token实体 /// </summary> public class TokenEntity

ASP.NET Core Web API Cassandra CRUD 操作

在本文中,我们将创建一个简单的 Web API 来实现对一个 “todo” 列表的 CRUD 操作,使用 Apache Cassandra 来存储数据,在这里不会创建 UI ,Web API 的测试将使用 Postman 来完成. ASP.NET Core 是 ASP.NET 的重大的重构,ASP.NET Core 是一个全新的开源和跨平台的框架,用于构建如 Web 应用.物联网(IoT)应用和移动后端应用等连接到互联网的基于云的现代应用程序. ASP.NET Core 已经内置了用 MVC 架

docker中运行ASP.NET Core Web API

在docker中运行ASP.NET Core Web API应用程序 本文是一篇指导快速演练的文章,将介绍在docker中运行一个ASP.NET Core Web API应用程序的基本步骤,在介绍的过程中,也会对docker的使用进行一些简单的描述.对于.NET Core以及docker的基本概念,网上已经有很多文章对其进行介绍了,因此本文不会再详细讲解这些内容.对.NET Core和docker不了解的朋友,建议首先查阅与这些技术相关的文档,然后再阅读本文. 先决条件 要完成本文所介绍的演练任

在docker中运行ASP.NET Core Web API应用程序

本文是一篇指导快速演练的文章,将介绍在docker中运行一个ASP.NET Core Web API应用程序的基本步骤,在介绍的过程中,也会对docker的使用进行一些简单的描述.对于.NET Core以及docker的基本概念,网上已经有很多文章对其进行介绍了,因此本文不会再详细讲解这些内容.对.NET Core和docker不了解的朋友,建议首先查阅与这些技术相关的文档,然后再阅读本文. 先决条件 要完成本文所介绍的演练任务,需要准备以下环境: Visual Studio 2015,或者Vi

支持多个版本的ASP.NET Core Web API

基本配置及说明 版本控制有助于及时推出功能,而不会破坏现有系统. 它还可以帮助为选定的客户提供额外的功能. API版本可以通过不同的方式完成,例如在URL中添加版本或通过自定义标头和通过Accept-Header作为查询字符串参数. 在这篇文章中,我们来看看如何支持多版本的ASP.NET Core Web API 创建一个ASP.NET Core Web API应用程序.通过 NuGet 安装此软件包:Microsoft.AspNetCore.Mvc.Versioning,打开Startup.c

Docker容器环境下ASP.NET Core Web API

Docker容器环境下ASP.NET Core Web API应用程序的调试 本文主要介绍通过Visual Studio 2015 Tools for Docker – Preview插件,在Docker容器环境下,对ASP.NET Core Web API应用程序进行调试.在自己做实验的过程中也碰到了一些问题,经过一些测试和搜索资料,基本解决了这些问题,本文也会对这些问题进行介绍,以免有相同需求的朋友多走弯路. 插件的下载与安装 至撰写本文为止,Visual Studio 2015 Tools

Gitlab CI 自动部署 asp.net core web api 到Docker容器

为什么要写这个? 在一个系统长大的过程中会经历不断重构升级来满足商业的需求,而一个严谨的商业系统需要高效.稳定.可扩展,有时候还不得不考虑成本的问题.我希望能找到比较完整的开源解决方案来解决持续集成.监控报警.以及扩容和高可用性的问题.是学习和探索的过程分享给大家,也欢迎同行的人交流. 先来一个三步曲,我们将完成通过GitLab CI 自动部署 net core web api 到Docker 容器的一个示例.这是第一步,通过此文您将了解如何将net core web api 运行在Docker

使用 Swagger 自动生成 ASP.NET Core Web API 的文档、在线帮助测试文档(ASP.NET Core Web API 自动生成文档)

对于开发人员来说,构建一个消费应用程序时去了解各种各样的 API 是一个巨大的挑战.在你的 Web API 项目中使用 Swagger 的 .NET Core 封装 Swashbuckle 可以帮助你创建良好的文档和帮助页面. Swashbuckle 可以通过修改 Startup.cs 作为一组 NuGet 包方便的加入项目.Swashbuckle 是一个开源项目,为使用 ASP.NET Core MVC 构建的 Web APIs 生成 Swagger 文档.Swagger 是一个机器可读的 R