在开发Web API时,经常会遇到需要处理多种操作的情况。随着时间的推移,这些操作可能会不断增加。为了避免在控制器中添加大量的操作,可以使用一种可扩展的架构。这样,只需要添加新的操作类型即可。本文将介绍如何使用Visual Studio 2017的Web API 2项目模板,结合Autofac,创建一个简单的、可扩展的Web API架构。
整个项目结构非常简单。创建了一个名为OperationsController
的API控制器,它包含一个名为Process
的操作。为了实现操作的可扩展性,定义了一个IOperation
接口,所有的操作都必须实现这个接口。此外,还提供了一个名为OperationBase
的基类,用于处理一些通用的代码。
首先,定义了IOperation
接口,如下所示:
public interface IOperation
{
string Name { get; }
string Description { get; }
Type ParameterClassType { get; }
object Execute(object prm);
}
在这个接口中,ParameterClassType
属性用于指定执行方法所需的参数对象类型。这个类型用于解析请求体中的JSON数据。如果Execute
方法返回非空值,则将其作为结果返回给调用者;否则,返回一个Ok
响应。
接下来,定义了OperationsController
控制器及其Process
操作,如下所示:
public class OperationsController : ApiController
{
private readonly List _supportedOperations;
public OperationsController(IEnumerable supportedOperations)
{
_supportedOperations = new List(supportedOperations);
}
[HttpPost]
public async Task Process(string operationName)
{
IOperation operation = _supportedOperations.FirstOrDefault(x => x.Name == operationName);
if (operation == null)
return BadRequest($"'{operationName}' is not supported.");
string jsonBody = await Request.Content.ReadAsStringAsync();
object operationParams = null;
try
{
if (operation.ParameterClassType != null)
operationParams = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonBody, operation.ParameterClassType);
object result = operation.Execute(operationParams);
if (result != null)
return Json(result);
}
catch (Exception ex)
{
return InternalServerError(ex);
}
return Ok();
}
}
在这个控制器中,通过构造函数注入实现了操作的注入。Process
操作接受一个操作名称,并从请求体中读取操作参数。然后,它找到相应的操作并执行它。如果操作返回结果,则将结果作为JSON返回;否则,返回一个Ok
响应。
路由配置如下所示:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{operationName}",
defaults: new { controller = "operations", action = "process", operationName = "help" }
);
这个路由配置将所有请求路由到OperationsController
的Process
操作。如果没有提供操作名称,则执行help
操作。
Autofac依赖注入配置如下所示:
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(t => t.IsAssignableTo())
.As();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
在这个配置中,注册了控制器和所有实现了IOperation
接口的操作。然后,将Autofac容器设置为Web API管道的依赖解析器。
可以使用Postman来测试这个Web API。首先,测试没有参数的help
操作。然后,测试需要参数的sum
操作。
为了演示这个想法,只提供了一个简单的实现。在实际应用中,应该将命令处理操作与控制器类分离。此外,应该提供更详细的操作信息,例如操作是否需要参数以及参数的类型和名称。由于操作不是控制器动作,Swagger无法提供参数信息。
此外,还没有实现自动验证。可以在Execute
方法之前进行验证,或者每个操作可以执行自己的验证逻辑。