You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用EF与Web API开发电商用户层时登录遇空引用错误

电商网站用户层登录空引用错误排查

问题背景

基于Entity Framework和Web API构建电商网站用户层,调用登录API时触发空引用错误,无法定位具体空值来源,怀疑与GetList方法或AutoMapper映射相关。

核心代码展示

1. EF基础仓储实现

namespace Core.DataAccess.EntityFramework
{
    public class EfBaseRepository<TEntity, TContext> : IBaseRepository<TEntity>
        where TEntity : class, IEntity, new()
        where TContext : DbContext, new()
    {
        public async Task<TEntity> AddAsync(TEntity entity)
        {
            using (TContext context = new TContext())
            {
                await context.Set<TEntity>().AddAsync(entity);
                await context.SaveChangesAsync();
                return entity;
            }
        }

        public async Task<bool> DeleteAsync(int id)
        {
            using (TContext context = new TContext())
            {
                var deleteEntity = await context.Set<TEntity>().FindAsync(id);
                context.Set<TEntity>().Remove(deleteEntity);
                var data = await context.SaveChangesAsync();
                if (data > 0)
                    return true;
                return false;
            }
        }

        public async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> filter)
        {
            using (TContext context = new TContext())
            {
                return await context.Set<TEntity>().SingleOrDefaultAsync(filter);
            }
        }

        public async Task<IEnumerable<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> filter = null)
        {
            using (TContext context = new TContext())
            {
                return filter == null
                    ? await context.Set<TEntity>().ToListAsync() :
                     await context.Set<TEntity>().Where(filter).ToListAsync();
            }
        }


        public async Task<TEntity> UpdateAsync(TEntity entity)
        {
            using (TContext context = new TContext())
            {
                context.Set<TEntity>().Update(entity);
                await context.SaveChangesAsync();
                return entity;
            }
        }
    }
}

2. UserService业务逻辑

namespace Business.Concrete
{
    public class UserService : IUserService
    {
        private readonly IUserDal _userDal;
        AppSettings _appSettings;
        IMapper _mapper;
        public UserService(IUserDal userDal, IOptions<AppSettings> appSettings, IMapper mapper)
        {
            _userDal = userDal;
            _appSettings = appSettings.Value;
            _mapper = mapper;
        }
        public async Task<ApiDataResponse<UserDto>> AddAsync(UserAddDto userAddDto)
        {
            var user = _mapper.Map<User>(userAddDto);
            user.CreatedDate = DateTime.UtcNow;
            user.CreatedUserId = 1;
            var userAdd = await _userDal.AddAsync(user);
            var userDto = _mapper.Map<UserDto>(userAdd);

            return new SuccessApiDataResponse<UserDto>(userDto, Messages.Added);
        }

        public async Task<ApiDataResponse<bool>> DeleteAsync(int id)
        {
            return new SuccessApiDataResponse<bool>(await _userDal.DeleteAsync(id), Messages.Deleted);
        }

        public async Task<ApiDataResponse<UserDto>> GetByIdAsync(int id)
        {
            var user = await _userDal.GetAsync(x => x.Id == id);
            if (user != null)
            {
                var userDto = _mapper.Map<UserDto>(user);
                return new SuccessApiDataResponse<UserDto>(userDto, Messages.Listed);
            }
            return new ErrorApiDataResponse<UserDto>(null, Messages.NotListed);
        }

        public async Task<ApiDataResponse<IEnumerable<UserDetailDto>>> GetListAsync(Expression<Func<User, bool>> filter = null)
        {
            if (filter == null)
            {
                var response = await _userDal.GetListAsync();
                var userDetailDtos = _mapper.Map<IEnumerable<UserDetailDto>>(response);
                return new  SuccessApiDataResponse<IEnumerable<UserDetailDto>>(userDetailDtos, Messages.Listed);
            }
            else
            {
                var response = await _userDal.GetListAsync(filter);
                var userDetailDtos = _mapper.Map<IEnumerable<UserDetailDto>>(response);
                return new SuccessApiDataResponse<IEnumerable<UserDetailDto>>(userDetailDtos, Messages.Listed);
            }
        }

        public async Task<ApiDataResponse<UserDto>> GetAsync(Expression<Func<User, bool>> filter = null)
        {
            var user = await _userDal.GetAsync(filter);
            if (user!= null)
            {
                var userDto= _mapper.Map<UserDto>(user);
                return new SuccessApiDataResponse<UserDto>(userDto, Messages.Listed);
            }
            return new ErrorApiDataResponse<UserDto>(null, Messages.NotListed);
        }

        public async Task<ApiDataResponse<UserUpdateDto>> UpdateAsync(UserUpdateDto userUpdateDto)
        {
            var getUser = await _userDal.GetAsync(x => x.Id == userUpdateDto.Id);
            var user = _mapper.Map<User>(userUpdateDto);
            user.CreatedDate = getUser.CreatedDate;
            user.CreatedUserId = getUser.CreatedUserId;
            user.UpdatedDate = DateTime.Now;
            user.UpdatedUserId = 1;
            user.Token = userUpdateDto.Token;
            user.TokenExpireDate = userUpdateDto.TokenExpireDate;
            var resultUpdate = await _userDal.UpdateAsync(user);
            var userUpdateMap = _mapper.Map<UserUpdateDto>(resultUpdate);

            return new SuccessApiDataResponse<UserUpdateDto>(userUpdateMap, Messages.Updated);
        }
    }
}

3. AuthService登录逻辑

namespace Business.Concrete
{
    public class AuthService : IAuthService
    {
        private IUserService _userService;
        private ITokenService _tokenService;
        private IMapper _mapper;

        public AuthService(IUserService userService, ITokenService tokenService, IMapper mapper)
        {
            _userService = userService;
            _tokenService = tokenService;
            _mapper = mapper;
        }

        public async Task<ApiDataResponse<UserDto>> LoginAsync(LoginDto loginDto)
        {
            var user = await _userService.GetAsync(x => x.UserName == loginDto.UserName && x.Password == loginDto.Password);

            if (user == null)
            {
                return new ErrorApiDataResponse<UserDto>(null, Messages.UserNotFound);
            }
            else
            {
                if (user.Data.TokenExpireDate == null || String.IsNullOrEmpty(user.Data.Token))
                {
                    var accessToken = _tokenService.CreateToken(user.Data.Id, user.Data.UserName);
                    var userUpdateDto = _mapper.Map<UserUpdateDto>(user.Data);
                    userUpdateDto.Token = accessToken.Token;
                    userUpdateDto.TokenExpireDate = accessToken.Expiration;
                    userUpdateDto.UpdatedUserId = user.Data.Id;
                    var resultUserUpdateDto = await _userService.UpdateAsync(userUpdateDto);
                    var userDto = _mapper.Map<UserDto>(resultUserUpdateDto.Data);
                    return new SuccessApiDataResponse<UserDto>(userDto, Messages.LoginSuccessful);
                }

                if (user.Data.TokenExpireDate < DateTime.Now)
                {
                    var accessToken = _tokenService.CreateToken(user.Data.Id, user.Data.UserName);
                    var userUpdateDto = _mapper.Map<UserUpdateDto>(user.Data);
                    userUpdateDto.Token = accessToken.Token;
                    userUpdateDto.TokenExpireDate = accessToken.Expiration;
                    userUpdateDto.UpdatedUserId = user.Data.Id;
                    var resultUserUpdateDto = await _userService.UpdateAsync(userUpdateDto);
                    var userDto = _mapper.Map<UserDto>(resultUserUpdateDto.Data);
                    return new SuccessApiDataResponse<UserDto>(userDto, Messages.LoginSuccessful);
                }
            }

            return new SuccessApiDataResponse<UserDto>(user.Data, Messages.LoginSuccessful);
        }
    }
}

空引用错误定位与修复

1. AuthService中错误的空判断逻辑

UserService.GetAsync永远不会返回null,它会返回SuccessApiDataResponse或ErrorApiDataResponse对象。当用户不存在时,user.Data为null,直接访问user.Data.TokenExpireDate会触发空引用。

修复代码:

var user = await _userService.GetAsync(x => x.UserName == loginDto.UserName && x.Password == loginDto.Password);

// 替换原有的user == null判断
if (!user.Success || user.Data == null)
{
    return new ErrorApiDataResponse<UserDto>(null, Messages.UserNotFound);
}

2. UserService.UpdateAsync中未校验用户存在性

var getUser = await _userDal.GetAsync(x => x.Id == userUpdateDto.Id);可能返回null,后续访问getUser.CreatedDate会触发空引用。

修复代码:

var getUser = await _userDal.GetAsync(x => x.Id == userUpdateDto.Id);
if(getUser == null)
{
    return new ErrorApiDataResponse<UserUpdateDto>(null, Messages.UserNotFound);
}
// 后续映射逻辑

3. EfBaseRepository.DeleteAsync中未校验待删除对象

FindAsync(id)返回null时,Remove(deleteEntity)会触发空引用。

修复代码:

public async Task<bool> DeleteAsync(int id)
{
    using (TContext context = new TContext())
    {
        var deleteEntity = await context.Set<TEntity>().FindAsync(id);
        if(deleteEntity == null)
            return false;
        context.Set<TEntity>().Remove(deleteEntity);
        var data = await context.SaveChangesAsync();
        return data > 0;
    }
}

4. 验证AutoMapper映射配置

检查User与UserDto、UserUpdateDto的映射配置,确保所有必要属性都已正确映射,避免映射后对象属性为null。例如:

CreateMap<User, UserDto>().ReverseMap();
CreateMap<User, UserUpdateDto>().ReverseMap();

内容的提问来源于stack exchange,提问作者Serkan Gün

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 23:49:52