编辑:已经过了PUT中的问题(是一个空值进入非空字段),但仍然遇到POST问题
我正在尝试使用EF Core 2在我的项目中设置一个简单的通用存储库。获取和更新工作正常,但我遇到了Create的问题。具体而言,控制器中HttpPost接收的值为空。奇怪的是,HttpPut在控制器中运行良好,公司收到了所有数据。
这是我的通用回购类:
public class GenericRepository<TEntity> : IGenericRepository<TEntity>
where TEntity : class, IEntity
{
protected DriverDbContext _dbContext;
protected DbSet<TEntity> _dbSet;
public GenericRepository(DriverDbContext dbContext)
{
_dbContext = dbContext;
_dbSet = dbContext.Set<TEntity>();
}
public async Task<IEnumerable<TEntity>> GetAll()
{
return await _dbSet.AsNoTracking().ToListAsync();
}
public async Task<TEntity> GetById(long id)
{
return await _dbSet
.AsNoTracking()
.FirstOrDefaultAsync(e => e.Id == id);
}
public async Task Create(TEntity entity)
{
_dbSet.Add(entity);
await _dbContext.SaveChangesAsync();
}
public async Task Update(TEntity entity)
{
// entity has good data but SavaChangesAsync does nothing
_dbSet.Update(entity);
await _dbContext.SaveChangesAsync();
}
public async Task Delete(long id)
{
var entity = await _dbSet.FindAsync(id);
_dbSet.Remove(entity);
await _dbContext.SaveChangesAsync();
}
}
这是我的控制器:
[Produces("application/json")]
[Route("api/Company")]
public class CompanyController : Controller
{
private ICompanyRepository _repository;
public CompanyController(ICompanyRepository repository)
{
_repository = repository;
}
[HttpGet]
public async Task<IActionResult> GetCompanies()
{
return Json(await _repository.GetAll());
}
[HttpGet("{id}")]
public async Task<IActionResult> GetCompany(int id)
{
var company = await _repository.GetById(id);
if (company == null)
{
return NotFound();
}
return Json(company);
}
[HttpPost()]
public async Task<IActionResult> CreateCompany([FromBody]CompanyViewModel company)
{
if (company == null)
{
return BadRequest();
}
var newCompany = Mapper.Map<Company>(company);
await _repository.Create(newCompany);
return Created($"/api/company/{company.Name}", Mapper.Map<CompanyViewModel>(newCompany));
}
[HttpPut()]
public async Task<IActionResult> UpdateCompany([FromBody]CompanyViewModel company)
{
if (company==null)
{
return BadRequest();
}
if (_repository.GetById(company.Id) == null)
{
return NotFound();
}
var updatedCompany = Mapper.Map<Company>(company);
await _repository.Update(updatedCompany);
return new NoContentResult();
}
}
以下是公司实体:
public class Company : IEntity
{
public long Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string Comments { get; set; }
public string Type { get; set; }
public bool Blacklisted { get; set; }
public string BlacklistedComments { get; set; }
public string BrokerAgreementStatus { get; set; }
public float CompanyInvoiceDiscount { get; set; }
public float PassThroughFee { get; set; }
public int StandardHoursBilled { get; set; }
public float StandardGM { get; set; }
public float StandardMarkupFromBase { get; set; }
public float StandardMarkupFromLoaded { get; set; }
public float StandardEquipmentCost { get; set; }
public long LastEditByUserID { get; set; }
public DateTime? LastEditDate { get; set; }
}
以下是公司视图模型:
public class CompanyViewModel
{
public long Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string Comments { get; set; }
public string Type { get; set; }
public bool Blacklisted { get; set; }
public string BlacklistedComments { get; set; }
public string BrokerAgreementStatus { get; set; }
public float CompanyInvoiceDiscount { get; set; }
public float PassThroughFee { get; set; }
public int StandardHoursBilled { get; set; }
public float StandardGM { get; set; }
public float StandardMarkupFromBase { get; set; }
public float StandardMarkupFromLoaded { get; set; }
public float StandardEquipmentCost { get; set; }
public long LastEditByUserId { get; set; }
public DateTime LastEditDate { get; set; }
}
这是我有棱有角的公司服务:
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Rx';
import { of } from 'rxjs/observable/of';
import { catchError, map, tap } from 'rxjs/operators';
import { Company } from './company';
import { MessageService } from '../message/message.service';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
@Injectable()
export class CompanyService {
private baseUrl = 'api/company';
constructor(
private http: HttpClient,
private messageService: MessageService) {
}
private log(message: string) {
this.messageService.add('CompanyService: ' + message);
}
getCompanies(): Observable<Company[]> {
return this.http.get<Company[]>(this.baseUrl)
.pipe(
tap(companies => this.log(`fetched companies`)),
catchError(this.handleError('getCompanies', []))
);
}
//Handle Http operation that failed.
//Let the app continue.
//@param operation - name of the operation that failed
//@param result - optional value to return as the observable result
getCompany(id: number): Observable<Company> {
if (id === 0) {
return Observable.of(this.initializeCompany());
}
return this.http.get<Company>(`${this.baseUrl}/${id}`).pipe(
tap(_ => this.log(`fetched Company id=${id}`)),
catchError(this.handleError<Company>(`getCompany id=${id}`))
);
}
initializeCompany(): Company {
return {
id: 0,
name: null,
address: null,
city: null,
state: null,
};
}
saveCompany(company: Company): Observable<Company> {
if (company.id === null) {
return this.addCompany(company);
}
return this.updateCompany(company);
}
updateCompany(company: Company): Observable<Company> {
return this.http.put<Company>(this.baseUrl, company, httpOptions).pipe(
tap((company: Company) => this.log(`updated company id=${company.id}`)),
catchError(this.handleError<any>('updateCompany'))
);
}
addCompany(company: Company): Observable<Company> {
return this.http.post<Company>(this.baseUrl, company, httpOptions).pipe(
tap((company: Company) => this.log(`added company id=${company.id}`)),
catchError(this.handleError<any>('addCompany'))
);
}
private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
// TODO: send the error to remote logging infrastructure
console.error(error); // log to console instead
// TODO: better job of transforming error for user consumption
//this.log(`${operation} failed: ${error.message}`);
// Let the app keep running by returning an empty result.
return of(result as T);
};
}
}
这是startup.cs
public class Startup
{
private IConfiguration _config;
public Startup(IConfiguration config)
{
_config = config;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DriverDbContext>(options => options.UseSqlServer(_config.GetConnectionString("DriverDBConnection")));
services.AddMvc();
services.AddScoped<ICompanyRepository, CompanyRespository>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true
});
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
Mapper.Initialize(config =>
{
config.CreateMap<CompanyViewModel, Company>().ReverseMap();
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
}
}
CompanyRespository是GenericRepository的空子类
以下是Post的请求有效负载:
{"id":null,
"name":"Some Company",
"address":null,
"city":null,
"state":"",
"zipcode":null,
"phone":null,
"email":null,
"comments":null,
"type":null,
"blacklisted":false,
"blacklistedComments":null,
"brokerAgreementStatus":"N/A",
"companyInvoiceDiscount":0,
"passThroughFee":0,
"standardHoursBilled":0,
"standardGM":0,
"standardMarkupFromBase":0,
"standardMarkupFromLoaded":0,
"standardEquipmentCost":0,
"lastEditByUserID":0,
"lastEditDate":"2018-01-10T23:03:05.303Z"}
这是请求标题
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.9
Connection:keep-alive
Content-Length:447
Content-Type:application/json
Host:localhost:56241
Origin:http://localhost:56241
Referer:http://localhost:56241/companies/0/edit
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
答案 0 :(得分:0)
public async Task Create(TEntity entity)
{
_dbSet.Add(entity);
await _dbContext.SaveChangesAsync();
}
public async Task Update(TEntity entity)
{
// entity has good data but SavaChangesAsync does nothing
_dbSet.Update(entity);
_dbContext.Entry(entity).State = EntityState.Modified;
await _dbContext.SaveChangesAsync();
}
public async Task Delete(long id)
{
var entity = await _dbSet.FindAsync(id);
if (_dbContext.Entry(entity).State = EntityState.Detached)
_dbSet.Attach(entity);
_dbSet.Remove(entity);
await _dbContext.SaveChangesAsync();
}