4.创建并调用自动控制器(api)

创建应用程序服务后, 通常需要创建API控制器以将此服务公开为HTTP(REST)API端点. 典型的API控制器除了将方法调用重定向到应用程序服务并使用[HttpGet],[HttpPost],[Route]等属性配置REST API之外什么都不做.

ABP可以按照惯例 自动 将你的应用程序服务配置为API控制器. 大多数时候你不关心它的详细配置,但它可以完全被自定义.

ABP在确定服务方法的HTTP Method时使用命名约定:

  • Get: 如果方法名称以GetList,GetAllGet开头.
  • Put: 如果方法名称以PutUpdate开头.
  • Delete: 如果方法名称以DeleteRemove开头.
  • Post: 如果方法名称以Create,Add,InsertPost开头.
  • Patch: 如果方法名称以Patch开头.
  • 其他情况, Post 为 默认方式.

如果需要为特定方法自定义HTTP Method, 则可以使用标准ASP.NET Core的属性([HttpPost], [HttpGet], [HttpPut]... 等等.). 这需要添加Microsoft.AspNetCore.Mvc.Core的Nuget包.

 

本篇使用的类库

*****.Application :编写自动控制器service的地方 

*****.HttpApi.Host:启动项目所有控制器存放地。指向swagger

 下边我们使用自动api控制器(service)创建几个api,然后在host中去调用

官方文档地址:https://docs.abp.io/zh-Hans/abp/latest/API/Auto-API-Controllers

上一篇文章我们已经建好了表,现在我们在.Application创建自动控制器

 

1.在.Application类库里创建service

using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Repositories;

namespace Test1111.Books
{
    [RemoteService(IsEnabled = false)]//此注释是将本service的api禁用,因为自动api所有方法名一样只有请求方式不一样不易区分,我们改用host调用service的方法
    public class BookAppService :
         CrudAppService<
             Book, //The Book entity
             BookDto, //Used to show books
             Guid, //Primary key of the book entity
             PagedAndSortedResultRequestDto, //Used for paging/sorting
             CreateUpdateBookDto> //Used to create/update a book
                                  //IBookAppService //implement the IBookAppService
    {

        private readonly IDistributedCache<BookDto> _cache;

        public BookAppService(IRepository<Book, Guid> repository, IDistributedCache<BookDto> cache)
            : base(repository)
        {
            _cache = cache;
        }

        public async Task<BookDto> GetBookAsync(Guid bookId)
        {
            return await _cache.GetOrAddAsync(
                bookId.ToString(), //Cache key
                async () => await GetBookFromDatabaseAsync(bookId),
                () => new DistributedCacheEntryOptions
                {
                    AbsoluteExpiration = DateTimeOffset.Now.AddHours(1)
                }
            );
        }

        private async Task<BookDto> GetBookFromDatabaseAsync(Guid bookId)
        {
            return await this.GetAsync(bookId);
        }




    }
}

2.在.HttpApi.Host中创建自定义控制器

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Test1111.Books;
using Volo.Abp.AspNetCore.Mvc;
using static Test1111.QuickDb.CurrentHttpContext;

namespace Test1111.Functions.Books
{
    [Route("api/[controller]/[action]")]
    [Authorize]
    public class BooksController : AbpController
    {
        private BookAppService _bookAppService;

        public BooksController(BookAppService bookAppService)
        {
            _bookAppService = bookAppService;
        }

        /// <summary>
        /// 查询    本查询为自定义方式 使用Dapper框架,一些复杂的查询我们就用Dapper不使用自动控制器了,
        /// 其实下边的几个增删改查我们完全也可以不适用自动控制器,本篇文章只是介绍一下新特性自动控制器
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public dynamic GetAll()
        {
            return Db.Query<dynamic>("select * from AppBooks");
            //使用dapper需要安装   包包管理工具搜索Dapper
        }

        /// <summary>
        /// 查询
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<BookDto> Get(Guid id)
        {
            return await _bookAppService.GetBookAsync(id);
        }
        /// <summary>
        /// 创建
        /// </summary>
        /// <param name="createUpdateBookDto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<BookDto> Create([FromBody] CreateUpdateBookDto createUpdateBookDto)
        {
            return await _bookAppService.CreateAsync(createUpdateBookDto);
        }
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="id"></param>
        /// <param name="createUpdateBookDto"></param>
        /// <returns></returns>
        [HttpPut]
        public async Task<BookDto> Update(Guid id, [FromBody] CreateUpdateBookDto createUpdateBookDto)
        {
            return await _bookAppService.UpdateAsync(id, createUpdateBookDto);
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete]
        public async Task Delete(Guid id)
        {
            await _bookAppService.DeleteAsync(id);
        }
    }
}

3.在.HttpApi.Host创建与数据库链接类

 

using Microsoft.AspNetCore.Http;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Web;

namespace Test1111.QuickDb
{
    public static class CurrentHttpContext
    {

        /// <summary>
        /// Shortcut to HttpContext.Current.
        /// </summary>
        public static HttpContext Context => MyHttpContext.Current;

        /// <summary>
        /// Shortcut to HttpContext.Current.Request.
        /// </summary>
        public static HttpRequest Request => Context.Request;




        /// <summary>
        /// Gets the single data context for this current request.
        /// </summary>
        public static DbConnection Db
        {
            get
            {
                DbConnection dbConnection = null;

                if (Context != null)
                {
                    dbConnection = Context.Items["DB"] as DbConnection;
                }

                if (dbConnection == null)
                {
                    var configuration = BuildConfiguration();
                    var ConnectionString = configuration.GetConnectionString("Default");
                    dbConnection = new SqlConnection(ConnectionString);
                    if (Context != null)
                    {
                        Context.Items["DB"] = dbConnection;

                        Context.Response.RegisterForDispose(dbConnection);
                    }
                }

                return dbConnection;
            }
        }

        /// <summary>
        /// Allows end of reqeust code to clean up this request's DB.
        /// </summary>
        public static void DisposeDB()
        {
            if (Context != null)
            {
                var db = Context.Items["DB"] as DbConnection;
                db?.Close();
                db?.Dispose();
                Context.Items["DB"] = null;
            }

        }

        private static IConfigurationRoot BuildConfiguration()
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../Test1111.DbMigrator/"))//这里不要照搬我的代码不然会报错,改成自己的命名空间
                .AddJsonFile("appsettings.json", optional: false);

            return builder.Build();
        }



    }
}
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace System.Web
{
    public static class MyHttpContext
    {
        private static IHttpContextAccessor _contextAccessor;

        public static Microsoft.AspNetCore.Http.HttpContext Current => _contextAccessor.HttpContext;

        internal static void Configure(IHttpContextAccessor contextAccessor)
        {
            _contextAccessor = contextAccessor;
        }
    }
}
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Test1111.QuickDb
{
    public static class StaticHttpContextExtensions
    {
        public static void AddHttpContextAccessor(this IServiceCollection services)
        {
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        }

        public static IApplicationBuilder UseStaticHttpContext(this IApplicationBuilder app)
        {
            var httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
            System.Web.MyHttpContext.Configure(httpContextAccessor);
            return app;
        }
    }
}

.host中的starup添加

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Test1111.QuickDb;

namespace Test1111
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            StaticHttpContextExtensions.AddHttpContextAccessor(services);
            services.AddApplication<Test1111HttpApiHostModule>();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            app.UseStaticHttpContext();
            app.InitializeApplication();
        }
    }
}

4.在.host的***HttpApiHostModule文件的ConfigureSwaggerServices中添加以下代码

options.CustomSchemaIds(type => type.FullName);



                    foreach (var xml in Directory.EnumerateFiles(AppContext.BaseDirectory, "*.xml"))
                    {
                        options.IncludeXmlComments(xml, true);
                    }

                    options.DocInclusionPredicate((docName, description) => true);

                    options.OperationFilter<AddResponseHeadersFilter>();

                    options.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();

                    options.OperationFilter<SecurityRequirementsOperationFilter>();

                    options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
                    {
                        Type = SecuritySchemeType.OAuth2,
                        Flows = new OpenApiOAuthFlows()
                        { 
                            Password = new OpenApiOAuthFlow
                            {
                                AuthorizationUrl = new("http://localhost:44308/connect/authorize"),//改成自己的地址
                                TokenUrl = new($"http://localhost:44308/connect/token"),
                                Scopes = new Dictionary<string, string>()
                            {
                                { IdentityServerConstants.StandardScopes.OpenId,IdentityServerConstants.StandardScopes.OpenId },
                                { IdentityServerConstants.StandardScopes.Profile,IdentityServerConstants.StandardScopes.Profile },
                            }
                            }
                        },
                    });

                    var scheme = new OpenApiSecurityScheme()
                    {
                        Scheme = JwtBearerDefaults.AuthenticationScheme,
                        BearerFormat = "JWT",
                        In = ParameterLocation.Header,
                        Name = "Authorization",
                        Type = SecuritySchemeType.ApiKey,
                        Description = "Bearer Token"
                    };
                    options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, scheme);
                    options.AddSecurityRequirement(new OpenApiSecurityRequirement()
                 {
                     {
                         new OpenApiSecurityScheme
                         {
                             Reference = new OpenApiReference
                             {
                                 Type = ReferenceType.SecurityScheme,
                                 Id = "Bearer"
                             }
                         },
                         Array.Empty<string>()
                     }
                 });

5.在.host的***HttpApiHostModule文件的ConfigureAuthentication中添加以下代码

private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
        {
            context.Services.AddAuthentication(options => {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

            })
                .AddJwtBearer(options =>
                {
                    options.Authority = configuration["AuthServer:Authority"];
                    options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
                    options.Audience = "Test1111";
                    options.BackchannelHttpHandler = new HttpClientHandler
                    {
                        ServerCertificateCustomValidationCallback =
                            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
                    };
                });
        } 

6.所有工作完成后我们启动.host项目

启动前先将项目的ssl去掉

7.启动项目   登录之后方可使用api