OData WebAPI实践-与ABP vNext集成

科技资讯 投稿 7900 0 评论

OData WebAPI实践-与ABP vNext集成

本文属于 OData 系列文章


ABP vNext 是一个重新设计的,面向微服务的框架,提供了一些非常有用的特性,包括分页查询等但是它并不能原生支持 OData,我们需要自行实现。

side by side 方式,由于 ABP vNext 官方没有对应的设计,所以你依然需要自己编写控制器。

原理

ABP vNext 有自动生成 Controller 的机制,我们的 ApplicationService,它会帮我们自动生成对应的终结点,并对外提供服务。这个过程是由 ABP 控制的,我们能修改的内容非常有限。

	// TodoAppHttpApiHostModule.cs
    private void ConfigureConventionalControllers(
    {
        Configure<AbpAspNetCoreMvcOptions>(options =>
        {
            options.ConventionalControllers.Create(typeof(TodoAppApplicationModule.Assembly, options =>
                {
                    //// 移除自动生成的控制器
                    //options.ControllerTypes.Remove(typeof(TodoAppController;
                    //options.RootPath = "abp";
                    //// 添加手动实现的控制器
                    //options.ControllerTypes.Add(typeof(TodoAppImplController;
                };
        };
    }

它依照惯例生成,我们可以对类型进行增加或者减少,但是不能控制生成的行为。而 OData 的控制器,需要我们从 ODataController 继承,或者使用 [EnableQuery],因此我们需要阻止自动生成控制器,自己实现对应的逻辑。

实现

首先禁用自动生成控制器功能。

	//TodoAppService.cs
    [RemoteService(false]
    public class TodoAppService : ApplicationService, ITodoAppService
    {
        private readonly IRepository<TodoItem, Guid> _todoItemRepository;

        public TodoAppService(IRepository<TodoItem, Guid> todoItemRepository
        {
            _todoItemRepository = todoItemRepository;
        }

        public async Task<IQueryable<TodoItemDto>> GetListAsync(
        {
            var items = await _todoItemRepository.GetQueryableAsync(;
            return items
        .Select(item => new TodoItemDto
        {
            Id = item.Id,
            Text = item.Text
        }
        }
    }

将应用服务打上 [RemoteService(false] 标记,服务就不会自动生成控制器。接下来在 HttpApi 项目中新建一个与服务同名的控制器,由于 ABP 项目自动生成了控制器抽象类模板,我们继承并实现它即可。

/* Inherit your controllers from this class.
 */
public abstract class TodoAppController : AbpControllerBase
{
    protected TodoAppController(
    {
        LocalizationResource = typeof(TodoAppResource;
    }
}


public class TodoController : TodoAppController
{
    private readonly ITodoAppService todoAppService;

    public TodoController(ITodoAppService todoAppService
       :base( 
    {
        this.todoAppService = todoAppService;
    }

    [EnableQuery]
    public async Task<IEnumerable<TodoItemDto>> GetAsync(
    {
        var result = await todoAppService.GetListAsync(;
        return result.AsQueryable(;
    }
}

注入对应的服务,实现自己的逻辑,如果需要利用 EF Core 的查询功能,请使用 IQueryable 传递数据到控制器层。然后配置 OData :

	//TodoAppHttpApiHostModule.cs
    private IEdmModel GetEdmModels(
    {
        var builder = new ODataConventionModelBuilder(;
        var device = builder.EntitySet<TodoItemDto>("Todo".EntityType.HasKey(w => w.Id;

        return builder.GetEdmModel(;
    }

记得在 PreConfigureServices 中加上调用。

	//TodoAppHttpApiHostModule.cs
    public override void PreConfigureServices(ServiceConfigurationContext context
    {
        PreConfigure<OpenIddictBuilder>(builder =>
        {
            builder.AddValidation(options =>
            {
                options.AddAudiences("TodoApp";
                options.UseLocalServer(;
                options.UseAspNetCore(;
            };
        };
        // 加上这个调用
        PreConfigure<IMvcBuilder>(builder =>
        {
            builder.AddOData(opt =>
            {
                opt.RouteOptions.EnablePropertyNameCaseInsensitive = true;
                opt.RouteOptions.EnableQualifiedOperationCall = false;
                opt.Expand(.Filter(.Count(.OrderBy(.Filter(.SetMaxTop(30;
                opt.AddRouteComponents("api/app/", GetEdmModels(;
            };
        };
    }

运行后,大功告成:

总结

本文实现了 OData 在 ABP vNext 中的使用。请注意,本方案只是一个 Demo,应用到生产前请自行评估风险,期待 ABP 团队在未来正式支持 OData 吧。本文的完整代码在 github,运行前可能需要先执行数据库初始化。

编程笔记 » OData WebAPI实践-与ABP vNext集成

赞同 (42) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽