1
我們目前正在爲具有基本CRUD功能的每個數據表構建Web API和控制器。我們遇到的問題是更新。我們創建了自定義綁定模型來引入我們需要的數據,然後將綁定模型轉換爲對象,並將其傳遞給我們的更新函數。Web Api通過綁定模型更新特定屬性
我們遇到的問題是,當客戶端通過POST發送數據時,我們的綁定模型會收到它並填充它們使用值設置的字段,並填充爲空的所有內容。因此,當我們將其轉換爲數據對象並將其發送給Update函數時,它將覆蓋未從客戶端設置爲空的字段。
這顯然會導致問題,因爲我們不希望用戶意外刪除信息。
這裏是我們如何運行的東西與客戶端,結合模型,及更新的例子,
團隊綁定模型
/// <summary>A Binding Model representing the essential elements of the Team table</summary>
public class TeamBindingModel
{
/// <summary>The Id of the team</summary>
[Required(ErrorMessage = "An ID is required")]
public int ID { get; set; }
/// <summary>The name of the team</summary>
[Required(ErrorMessage = "A Team Name is required")]
[Display(Name = "Team Name")]
[StringLength(35)]
public string Team1 { get; set; }
/// <summary>The email associated with the team</summary>
[StringLength(120)]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
public bool ShowDDL { get; set; }
}
的UpdateTeam CRUD方法
// PUT: api/Team
/// <summary>
/// Attempt to update a team with a given existing ID
/// </summary>
/// <param name="team">TeamBindingModel - The binding model which needs an Id and a Team name</param>
/// <returns>IHttpActionResult that formats as an HttpResponseCode string</returns>
[HttpPut]
[Authorize(Roles = "SystemAdmin.Teams.Update")]
public async Task<IHttpActionResult> UpdateTeam(TeamBindingModel team)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
try
{
// Convert the binding model to the Data object
Team teamObject = team.ToObject();
unitOfWork.TeamRepository.Update(teamObject);
await unitOfWork.Save();
}
catch (DbUpdateConcurrencyException)
{
return BadRequest();
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
return Ok();
}
ToObject函數
/// <summary>Takes the Team Binding model and converts it to a Team object</summary>
/// <returns>Team Object</returns>
public virtual Team ToObject()
{
// Setup the data object
Team newObject = new Team();
// Instantiate the basic property fields
newObject.ID = this.ID;
newObject.Team1 = this.Team1;
newObject.Email = this.Email;
newObject.ShowDDL = this.ShowDDL;
return newObject;
}
的更新功能
public virtual void Update(TEntity entityToUpdate)
{
try
{
dbSet.Attach(entityToUpdate);
dbContext.Entry(entityToUpdate).State = EntityState.Modified;
}
catch (Exception ex)
{
throw ex;
}
}
保存功能
public async Task Save()
{
await dbContext.SaveChangesAsync();
}
客戶端調用/測試/錯誤
// Add team to update and remove
var db = new genericDatabase();
var teamDB = new Team { Team1 = "testTeam", Email = "[email protected]", ShowDDL = true};
db.Teams.Add(teamDB);
db.SaveChanges();
// Look for items in the database
var originalTeamInQuestion = (from b in db.Teams
where b.Team1 == "testTeam"
select b).FirstOrDefault();
// Create Team object with the some changes
var team = new
{
ID = originalTeamInQuestion.ID,
Team1 = "changedTestTeam",
ShowDDL = false,
};
// This is the API call which sends a PUT with only the parameters from team
var teamToUpdate = team.PutToJObject(baseUrl + apiCall, userAccount.token);
// Look for items in the database
var changedTeamInQuestion = (from b in db.Teams
where b.Team1 == "changedTestTeam"
select b).FirstOrDefault();
// This Assert succeeds and shows that changes have taken place
Assert.AreEqual(team.Team1, changedTeamInQuestion.Team1);
// This Assert is failing since no Email information is being sent
// and the binding model assigns it to Null since it didn't get that
// as part of the PUT and overrides the object on update.
Assert.AreEqual(originalTeamInQuestion.Email, changedTeamInQuestion.Email);
對此的一些替代方法的任何想法?我們曾想過要求客戶首先通過對API進行GET調用,然後修改對象來獲取整個對象,但如果客戶端不遵循該協議,則可能會非常危險地清除敏感數據。
是客戶端的MVC網站? –
爲什麼不在回購層更新之前進行獲取併合並兩個對象模型和實體,然後將該合併對象傳遞給更新方法。通過這種方式,您將確保只發送udpated值並且其他任何東西保持不變。 – Prashant