欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 幼教 > Web开发:ABP框架5——入门级别的常见问题和报错解析

Web开发:ABP框架5——入门级别的常见问题和报错解析

2025/2/27 0:20:02 来源:https://blog.csdn.net/m0_67412019/article/details/142961014  浏览:    关键词:Web开发:ABP框架5——入门级别的常见问题和报错解析

目录

一、常见问题

1. Swagger界面找不到接口

2.注释不显示

步骤一:新建xml输出

步骤二:代码引用xml文件

 3.日期格式化带T

4.输出变量格式化(小驼峰->大驼峰)

二、报错解析

1.Swagger界面报错

 2.底层代码调用失败

3.仓储引用失败 

三、通用错误排查方法

1.查控制台程序输出

2.查日志

四、疑难解答

1. 两个仓储的区别

 2.EFcore如何打印sql

3.ABP和 Volo.ABP区别

五、开发人员对接口测试流程 

六、EFcore疑难专项

1.主键配置

2.映射失败的几大原因

3.任务中途取消

4.派生类型无法配置密钥


一、常见问题

1. Swagger界面找不到接口

  • 代码问题:WebApi控制器(服务)没有继承ApplicationService
  • 缓存问题:给浏览器清理下缓存,重启VS2022

2.注释不显示

步骤一:新建xml输出

方法一:哪个类库不显示,改对应类库的工程文件

    <GenerateDocumentationFile>true</GenerateDocumentationFile><DocumentationFile>bin\Debug\net6.0\Acme.BookStore.HttpApi.Host.xml</DocumentationFile>

方法二: 对应类库的右键属性设置

 输入框填写的内容应该和工程文件种的一致:

bin\Debug\net6.0\Acme.BookStore.HttpApi.Host.xml

步骤二:代码引用xml文件

        API模块种补上代码,当然也可以直接字符串写死  xmlFile = " Acme.BookStore.HttpApi.Host.xml " ,怎么命名都好,总之,xmlFile这个文件名和上面步骤一设置的文件名一致。

private static void ConfigureSwaggerServices(ServiceConfigurationContext context, IConfiguration configuration)
{var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";//"Acme.BookStore.HttpApi.Host.xml"var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);context.Services.AddAbpSwaggerGenWithOAuth(configuration["AuthServer:Authority"],new Dictionary<string, string>{{"BookStore", "BookStore API"}},options =>{options.SwaggerDoc("v1", new OpenApiInfo { Title = "BookStore API", Version = "v1" });options.DocInclusionPredicate((docName, description) => true);options.CustomSchemaIds(type => type.FullName);options.IncludeXmlComments(xmlPath); // 添加这一行});
}

修改后的效果:

注意:工程文件只需要配置对应的应用层即可!不要再配置Host,否则会覆盖你应用层生成的xml。

 3.日期格式化带T

需求如下,输出的日期带T,我们不需要显示T

代码编写位置 

 加上这个:

Configure<AbpJsonOptions>(options =>
{options.DefaultDateTimeFormat = "yyyy-MM-dd HH:mm:ss";
});

如果你想全局配置,那也可以将上述代码加在Program.cs这里,所有模块都会实现这样的效果:

(注意:我觉得日期格式化,虽然上面的方法可以解决问题,但是始终是不够灵活,因为有时候返回出去的是yyyy-MM-dd而不是完整的时间,因此我觉得用tostring方法手动调整,返回字符串出去 或者让前端处理,或许会更好) 

4.输出变量格式化(小驼峰->大驼峰)

方法一:全局配置

builder.Services.AddMvc().AddJsonOptions(options =>
{options.JsonSerializerOptions.PropertyNamingPolicy = null;
});

 效果:

方法二:每个字段都用特性配置

例如:


 效果:

二、报错解析

1.Swagger界面报错

错误:Fetch errorInternal Server Error /swagger/v1/swagger.json

方法:查看控制台程序报错情况

可能情况:

  1. WebApi控制器(服务)某个方法使用了public修饰符,但是没有[HTTPGet]或其他请求标识特性,ABP 框架默认将其视为接口,因此会报错。(解决方法:①加上请求特性,用作接口;②或者用private修饰符声明私有方法,供其他接口使用,不作为对外开放接口)
  2. WebApi控制器(服务)出现路由同名现象,引发冲突。

 2.底层代码调用失败

错误:Castle.Proxies.BookAppServiceProxy

原因:底层代码接口未注入到依赖容器,服务找不到这个底层代码接口

解决方案:底层代码继承ApplicationService或实现ITransientDependency

3.仓储引用失败 

报错信息:“Acme.BookStore.Books.Book”不能用作泛型类型或方法“IRepository<TEntity, TKey>”中的类型参数“TEntity”。没有从“Acme.BookStore.Books.Book”到“Volo.Abp.Domain.Entities.IEntity<System.Guid>”的隐式引用转换。

 原因:实体类没有继承AuditedAggregateRoot<Guid>或者AggregateRoot<Guid>或者DOEntity,因为IRepository<TEntity, TKey>需要继承自 IEntity<TKey> 接口。

三、通用错误排查方法

1.查控制台程序输出

2.查日志

  • 位置参考:\src\xxxx.HttpApi.Host\Logs

四、疑难解答

1. 两个仓储的区别

        一个指定了主键类型,调用GetAsync(根据id查表)、DeleteAsync(根据id删数据)等方法时,直接传入对应类型的id即可,否则需要传入LINQ的表达式树

private readonly IRepository<Book, Guid> _bookRepository;//await _bookRepository.DeleteAsync(id);
private readonly IRepository<Book> _bookRepository;//await _bookRepository.DeleteAsync(x=>x.Id==Guid.NewGuid());

 2.前端传入枚举,让传参更清晰

//前端传入方式:post请求或者get请求直接传一个枚举值(string) 或者 索引(int) 都可(例如querytype="Grade1",或者querytype=1)//接收前端的实体:
public class SearchInput
{//可以写其他属性public StudentEnum querytype { set; get; }
}//枚举示例:
public enum StudentEnum
{Grade1 = 1,Grade2 = 2,Grade3 = 3
}//后端可以这样判断:
bool isgrade1 =  input.querytype == StudentEnum.Grade1;// 上述两种入参,都可以输出True

3.ABP和 Volo.ABP区别

        ABP和 Volo.ABP 是两个不同的框架,后者版本更加新,有基于最新的 ASP.NET Core 技术栈且ORM-EFcore采用高版本的。

五、开发人员对接口测试流程 

  1. 检索条件是否生效
  2. 分页效果(测试第一到第三页)
  3. 比对数据
  4. 查看控制台程序和日志是否存在报错现象

六、EFcore疑难专项

1.主键配置

protected override void OnModelCreating(ModelBuilder modelBuilder)
{modelBuilder.Entity<xxxModel>(b => {b.ConfigureByConvention();// b.HasKey(x => new { x.Id }); // 其实不需要显式指定主键,只要你的实体中含有属性名称为Id的属性,EF Core 会自动识别 Id 为主键(注意不可识别id)});
}

        不需要显式指定主键,只要你的实体中含有属性名称为Id的属性,EF Core 会自动识别 Id 为主键(注意不可识别id,是区分大小写的)

2.映射失败的几大原因

  1. 配置问题:Dbcontext写错字段类型,例如NUMBER(8,2)写成了NUMBER(8),如果高级版本采用ConfigureByConvention配置,不存在这个问题。
  2. 入参问题:前端传入和后端接收字段类型不一致,例如Guid和string
  3. 映射关系问题:没有创建CreateMap,导致映射失败(Mapping failed)

3.任务中途取消

报错:A Task was canceled

Update操作:根据传递实体的主键,查不到数据(检查主键是否正确)

4.派生类型无法配置密钥

A key cannot be configured on 'xxxx' because it is a derived type

实体字段配置问题:数据库实体不能继承另一个实体

反例:

public class A 
{}
public class B : A
{}

正例:

//抽取公共字段出来,写在Common类中
public class A : Common
{}
public class B : Common
{}

5.实体继承 Entity<int>和继承AuditedAggregateRoot<id>的区别

讲直白点:

①仓储查表

        必须继承一个,才能使用下述方式(注入仓储)来通过EFcore查表

private readonly IRepository<Book, Guid> _bookRepository;

②少写字段

        继承Entity<int> ,实体可以少写一个 Id 字段
        继承AuditedAggregateRoot<int>,实体可以少写很多字段例如创建时间、修改时间、操作用户等

③查表拼接

        查表会拼接你这个实体所有的字段,包括继承的,这说明强制要求我们的表主键字段含有Id,否则就会出错。

        不过也可以强制修改,例如我有一个表,继承了Entity<int>:

        查表生成的sql是这样的:

SELECT Id,[pid],[pname] FROM [TestABP].[dbo].[Parent]

         我没有Id字段,就会导致查这张表失败,解决方案二选一如下:

        ①改名,pid改为Id(不区分大小写,改成id Id ID iD都可以)

        ②忽略Id字段,让EFcore拼接查询sql的时候忽略它,以下两个步骤都必不可少,没有主键标记EFcore也会报错:

        builder.Entity<Parent>(b =>{//b.ToTable(BookStoreConsts.DbTablePrefix + "Books", BookStoreConsts.DbSchema);b.HasKey(x => x.pid);// 声明本表主键【步骤一】b.Ignore(x => x.Id); //忽略继承的主键【步骤二】b.ConfigureByConvention();// 自动配置基本属性});

        说了那么多,建议还是按它们那套标准来:建表必定含有Id字段作为主键,然后实体继承了Entity<int>后就不要重复写id字段了(重复写id字段可以查表,但是EFcore不支持这样映射,还是会报如下的错)。

 6.EFcore如何打印sql

在上下文类加上以下代码即可:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{optionsBuilder// 输出到 VS 输出窗口.LogTo(msg => System.Diagnostics.Trace.WriteLine(msg), new[] { Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.CommandExecuting });}

(吐槽一下:EFcore又难用,拼出来的SQL又复杂,还不如用主流的ORM框架!)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词