如何在 .NET Core 中创建具有 api 个端点的中间件
How create a middleware with api endpoints in .NET Core
我已经用 web api 创建了 web 应用程序。该应用程序包含一些 Controllers
例如 TodoController
:
namespace TodoApi.Controllers
{
[Route("api/[controller]")]
public class TodoController : Controller
{
private readonly TodoContext _context;
public TodoController(TodoContext context)
{
_context = context;
}
[HttpGet]
public IEnumerable<TodoItem> GetAll()
{
return _context.TodoItems.ToList();
}
}
}
如果我创建 GET
请求 - /api/todo
- 我从数据库中获取待办事项列表。
我有一个控制器列表和 api 端点,如上所示。
我想将此 api 分发到另一个应用程序,最好像中间件一样 - 我的想法是在 Startup.cs
中注册,如下所示:
public void ConfigureServices(IServiceCollection services)
{
services.AddTodoApi();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseTodoApi();
}
这对我的 api 来说是很棒的用例,但我不知道这个控制器 api 端点如何像中间件和 return 相同的 JSON 数据一样重写方法就像使用经典 Controllers
.
如何在 .NET Core
中写入 middleware
以创建 API endpoints
?
您可以将 MVC 中间件配置为从另一个程序集中发现控制器,而不是单独的中间件:
// using System.Reflection;
public void ConfigureServices(IServiceCollection services)
{
...
services
.AddMvc()
.AddApplicationPart(typeof(TodoController).GetTypeInfo().Assembly);
控制器是 MVC 中间件的一部分,它们不是请求管道的独立部分(但这就是中间件)。当您注册自定义中间件时,默认情况下它会在每个请求上调用并且您将 HttpContext context
作为输入参数来工作 with/edit
Request/Response 数据。但是 ASP.NET 核心 provides Map* extensions 被用作分支管道的约定。
Map branches the request pipeline based on matches of the given request path. If the request path starts with the given path, the branch is executed.
示例:
private static void HandleMapTodo(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("/api/todo was handled");
});
}
public void Configure(IApplicationBuilder app)
{
app.Map("/api/todo", HandleMapTodo);
}
请注意,由于中间件对 MVC 中间件一无所知,您只能访问 "raw" 请求,而没有模型绑定或 MVC 操作过滤器等功能。
因为它看起来像是完美的微服务方法(类似于我的团队现在正在做的)我会创建一个可以使用您的 API 的客户端程序集,其中包含您的 TodoController,如果您为此 API 定义契约和接口,您可以在其他程序集中注册它,因为它是一个中间件,您也可以在单元测试中模拟该行为。
所以,正如我所说,您可以在 ConfigureServices 方法中注入您的客户端,您可以创建:
public static IServiceCollection AddTodoRestClient(this IServiceCollection services)
{
services.AddSingleton<ITodoRestClient, TodoRestClient>();
return services;
}
还要考虑到您需要提供 enpoint,它可能看起来像:
public static IServiceCollection AddConfiguredTodoClient(this IServiceCollection services, string todoEndpoint)
{
AddTodoClient(services);
ITodoRestClient todoRestClient = services.BuildServiceProvider().GetService<ITodoRestClient>();
// Imagine you have a configure method...
todoRestClient.Configure(services, todoEndpoint);
return services;
}
您可以在 TodoRestClientInjector class 中创建这些方法,并在启动时在 Configure 方法中使用它们。
希望对你有帮助
--- 回复评论的更多细节---
对我来说,TodoClient 是一个 Rest 客户端库,它实现了对 ToDo API 的调用,(我已经将之前的代码编辑为 TodoRestClient)方法,例如 CreateTodoItem(TodoDto todoItem) 实现将调用到 TodoController.Post([FromBody] item) 或 GetTodos() which wuold call TodoController.Get() 等等....
关于 enpoints... 这种方法意味着有(至少)两个不同的应用程序(.NET Core 应用程序),一方面是 ASP 具有 TodoController 的 NET Core 应用程序,另一方面另一方面,控制台应用程序或另一个 ASP NET Core API 在启动时 class 你将执行 inyection 和 Rest 客户端(Todo Rest 客户端)配置 ...
在使用 docker 的微服务方法中,在开发环境中,您将使用 docker-compose-yml,但在传统方法中,您将使用具体端口来定义端点...
所以,假设您在第二个服务中有一个需要使用 TodoController 的控制器来实现,所以我将使用上面的方法,"SecondController" 看起来像:
public class SecondController : Controller
{
private readonly SecondContext _context;
private readonly TodoRestClient _todoRestClient;
public TodoController(SecondContext context, ITodoRestClient todoRestClient)
{
_context = context;
_todoRestClient= todoRestClient;
}
// Whatever logic in this second controller... but the usage would be like:
_todoRestClient.GetTodos()
}
最后几个提示:减少服务之间的调用是关键,因为它会增加延迟,如果发生在级联上,延迟会越来越多。还要考虑 Docker 用法,看起来很有挑战性,但它很容易上手,而且实际上被认为可用于您介绍的场景和像我这样的解决方案。
再说一遍,希望对你有帮助。
胡安
我已经用 web api 创建了 web 应用程序。该应用程序包含一些 Controllers
例如 TodoController
:
namespace TodoApi.Controllers
{
[Route("api/[controller]")]
public class TodoController : Controller
{
private readonly TodoContext _context;
public TodoController(TodoContext context)
{
_context = context;
}
[HttpGet]
public IEnumerable<TodoItem> GetAll()
{
return _context.TodoItems.ToList();
}
}
}
如果我创建 GET
请求 - /api/todo
- 我从数据库中获取待办事项列表。
我有一个控制器列表和 api 端点,如上所示。
我想将此 api 分发到另一个应用程序,最好像中间件一样 - 我的想法是在 Startup.cs
中注册,如下所示:
public void ConfigureServices(IServiceCollection services)
{
services.AddTodoApi();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseTodoApi();
}
这对我的 api 来说是很棒的用例,但我不知道这个控制器 api 端点如何像中间件和 return 相同的 JSON 数据一样重写方法就像使用经典 Controllers
.
如何在 .NET Core
中写入 middleware
以创建 API endpoints
?
您可以将 MVC 中间件配置为从另一个程序集中发现控制器,而不是单独的中间件:
// using System.Reflection;
public void ConfigureServices(IServiceCollection services)
{
...
services
.AddMvc()
.AddApplicationPart(typeof(TodoController).GetTypeInfo().Assembly);
控制器是 MVC 中间件的一部分,它们不是请求管道的独立部分(但这就是中间件)。当您注册自定义中间件时,默认情况下它会在每个请求上调用并且您将 HttpContext context
作为输入参数来工作 with/edit
Request/Response 数据。但是 ASP.NET 核心 provides Map* extensions 被用作分支管道的约定。
Map branches the request pipeline based on matches of the given request path. If the request path starts with the given path, the branch is executed.
示例:
private static void HandleMapTodo(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("/api/todo was handled");
});
}
public void Configure(IApplicationBuilder app)
{
app.Map("/api/todo", HandleMapTodo);
}
请注意,由于中间件对 MVC 中间件一无所知,您只能访问 "raw" 请求,而没有模型绑定或 MVC 操作过滤器等功能。
因为它看起来像是完美的微服务方法(类似于我的团队现在正在做的)我会创建一个可以使用您的 API 的客户端程序集,其中包含您的 TodoController,如果您为此 API 定义契约和接口,您可以在其他程序集中注册它,因为它是一个中间件,您也可以在单元测试中模拟该行为。
所以,正如我所说,您可以在 ConfigureServices 方法中注入您的客户端,您可以创建:
public static IServiceCollection AddTodoRestClient(this IServiceCollection services)
{
services.AddSingleton<ITodoRestClient, TodoRestClient>();
return services;
}
还要考虑到您需要提供 enpoint,它可能看起来像:
public static IServiceCollection AddConfiguredTodoClient(this IServiceCollection services, string todoEndpoint)
{
AddTodoClient(services);
ITodoRestClient todoRestClient = services.BuildServiceProvider().GetService<ITodoRestClient>();
// Imagine you have a configure method...
todoRestClient.Configure(services, todoEndpoint);
return services;
}
您可以在 TodoRestClientInjector class 中创建这些方法,并在启动时在 Configure 方法中使用它们。
希望对你有帮助
--- 回复评论的更多细节---
对我来说,TodoClient 是一个 Rest 客户端库,它实现了对 ToDo API 的调用,(我已经将之前的代码编辑为 TodoRestClient)方法,例如 CreateTodoItem(TodoDto todoItem) 实现将调用到 TodoController.Post([FromBody] item) 或 GetTodos() which wuold call TodoController.Get() 等等....
关于 enpoints... 这种方法意味着有(至少)两个不同的应用程序(.NET Core 应用程序),一方面是 ASP 具有 TodoController 的 NET Core 应用程序,另一方面另一方面,控制台应用程序或另一个 ASP NET Core API 在启动时 class 你将执行 inyection 和 Rest 客户端(Todo Rest 客户端)配置 ...
在使用 docker 的微服务方法中,在开发环境中,您将使用 docker-compose-yml,但在传统方法中,您将使用具体端口来定义端点...
所以,假设您在第二个服务中有一个需要使用 TodoController 的控制器来实现,所以我将使用上面的方法,"SecondController" 看起来像:
public class SecondController : Controller
{
private readonly SecondContext _context;
private readonly TodoRestClient _todoRestClient;
public TodoController(SecondContext context, ITodoRestClient todoRestClient)
{
_context = context;
_todoRestClient= todoRestClient;
}
// Whatever logic in this second controller... but the usage would be like:
_todoRestClient.GetTodos()
}
最后几个提示:减少服务之间的调用是关键,因为它会增加延迟,如果发生在级联上,延迟会越来越多。还要考虑 Docker 用法,看起来很有挑战性,但它很容易上手,而且实际上被认为可用于您介绍的场景和像我这样的解决方案。
再说一遍,希望对你有帮助。
胡安