目录
介绍
架构
代码
用Postman测试
下一步
- 下载文章的源代码(GitHub存储库)
我最近需要准备一个Web API,它有几个小操作,并且会不断添加新的操作。我决定使用可扩展的架构,而不是添加许多带有少量操作的控制器。因此,只能通过添加新的操作类型来添加新操作。
架构架构和项目非常简单。该项目是使用Visual Studio 2017的Web API 2项目模板创建的。只有一个名为OperationsController的API控制器,其具有一个名为Process的单个操作。操作必须实现一个简单的IOperation接口,并为样板代码命名一个基类OperationBase。
Autofac和Autofac WebAPI2集成包用于自动发现操作类型并将其注入控制器。
代码IOperation 接口如下:
public interface IOperation
{
string Name { get; }
string Description { get; }
Type ParameterClassType { get; }
object Execute(object prm);
}
ParameterClassType是Execute方法所需的参数对象的类型。解析request体内的JSON数据时使用它。如果Execute方法返回非null值,则将其作为结果返回给调用者,否则只返回Ok响应。
OperationController及其Process操作如下:
public class OperationsController : ApiController
{
//Implemented operations are injected in the constructor
public OperationsController(IEnumerable supportedOperations)
{
_supportedOperations = new List(supportedOperations);
}
//Single action that gets the operation name and
//reads the operation parameters as JSON from request body
[HttpPost]
public async Task Process(string operationName)
{
//Find the operation
IOperation operation = _supportedOperations.FirstOrDefault(x => x.Name == operationName);
if (operation == null)
return BadRequest($"'{operationName}' is not supported.");
//Get the request body as string
string jsonBody = await Request.Content.ReadAsStringAsync();
object operationParams = null;
try
{
//Parse the JSON data in the request body t construct operation's parameter object
if (operation.ParameterClassType != null)
operationParams = Newtonsoft.Json.JsonConvert.DeserializeObject
(jsonBody, operation.ParameterClassType);
object result = operation.Execute(operationParams);
//Return the result value as JSON to the caller
if (result != null)
return Json(result);
}
catch(Exception ex)
{
return InternalServerError(ex);
}
//Return Ok if the operation has no return value
return Ok();
}
}
仅需要operationName值的路由配置如下:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{operationName}",
defaults: new { controller = "operations", action = "process", operationName = "help" }
);
该路由配置将所有请求路由到OperationsControlller的Process操作。如果没有提供操作名称,则执行帮助。
配置Autofac依赖注入并将其设置为Web API管道的依赖项解析器:
ContainerBuilder builder = new ContainerBuilder();
//Register controllers
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
//Register all operations
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(t=> t.IsAssignableTo())
.As();
var container = builder.Build();
//Set Autofac container as the dependency resolver
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
用Postman测试
测试无参数操作“help”。
响应从“help”操作返回。
测试期望具有属性“Number1”和“Number2”的对象的“sum”操作。
响应从“sum”操作返回。
为了只展示这个想法,剩下的代码非常简单。将命令处理操作与控制器类分开是很好的。
“帮助”命令仅显示操作的名称和描述,但最好提供特定操作是否需要参数及其名称类型。由于操作不是控制器操作,因此Swagger对参数信息没有帮助。
也没有自动验证。验证可以在操作Execute方法之前完成,或者每个操作可以执行其自己的验证逻辑。
还应添加身份验证和授权操作以保护Web API。
原文地址:https://www.codeproject.com/Articles/5161177/Developing-an-Extensible-Web-API