2012-10-05 96 views
0

我有以下型號:用於ASP.Net MVC創建控制器邏輯爲登錄用戶

public class Expense 
{ 
    [Key] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int ID { get; set; } 
    [Required] 
    public string Name { get; set; } 
    [Required] 
    [Column(TypeName = "Money")] 
    public decimal Limit { get; set; } 
    [Required] 
    [ForeignKey("UserProfile")] 
    public int UserProfileId { get; set; } 
    [Required] 
    public virtual UserProfile UserProfile { get; set; } 
} 

[Table("UserProfile")] 
public class UserProfile 
{ 
    [Key] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int UserId { get; set; } 
    public string UserName { get; set; } 
    public virtual ICollection<Expense> Expenses { get; set; } 
} 

我有一個登錄的用戶,我想的是用戶能夠添加新的費用。在創建控制器操作如下所示:

// 
    // GET: /Expenses/Create 

    public ActionResult Create() 
    { 

     return View(); 
    } 

    // 
    // POST: /Expenses/Create 

    [HttpPost] 
    public ActionResult Create(Expense expense) 
    {    
     if (ModelState.IsValid) 
     { 
      UserProfile user = db.UserProfiles.Single(u => u.UserName == User.Identity.Name) 
      user.Expenses.Add(expense);     
      db.SaveChanges(); 
      return RedirectToAction("Index"); 
     } 

     return View(expense); 
    } 

隨着視圖:

@model MoneyDrainPlug.Models.Expense 

@{ 
    ViewBag.Title = "Create"; 
} 

<h2>Create</h2> 

@using (Html.BeginForm()) { 
    @Html.ValidationSummary(true) 

    <fieldset> 
     <legend>Expense</legend> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.Name) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.Name) 
      @Html.ValidationMessageFor(model => model.Name) 
     </div> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.Limit) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.Limit) 
      @Html.ValidationMessageFor(model => model.Limit) 
     </div>   
     <p> 
      <input type="submit" value="Create" /> 
     </p> 
    </fieldset> 
} 

<div> 
    @Html.ActionLink("Back to List", "Index") 
</div> 

@section Scripts { 
    @Scripts.Render("~/bundles/jqueryval") 
} 

當發生後,ModelState.IsValid是在控制器錯誤。這是因爲在費用中沒有設置UserProfileId。如果我在調用ModelState.IsValid之前設置UserProfile和\或UserProfileId,這沒有幫助。

什麼是正確和安全的處理方式?當然,我不應該相信從客戶端發送的UserProfileId?

在它的事項的情況下,我使用asp.net MVC 4

在此先感謝

回答

1

可能的解決方案

去除UserProfileIdRequired屬性(DataAnnotation只是涉及到的意見:如果你不想在你的意見中有什麼東西,不要將其標記爲RequiredRequiredAttribute不是數據庫約束)

刪除UserProfileId屬性(你有UserProfile廣告載體,它可能是不夠的)

創建ViewModel沒有UserProfileId財產

編輯: 要明確:可以完美使用一個ViewModel。只要保證必需的屬性與你的數據庫沒有直接關係。如果您不直接在視圖中使用Expense類,則可以刪除Expense中的所有Required屬性,它們將永遠不會使用。

+0

謝謝。 'UserProfileId'是一個dbconstraint,它是必需的。我可能是錯的,但認爲我需要'UserProfile'和'UserProfileId'以使實體框架正常工作。我想我可以使用視圖模型,但仍然需要驗證費用。我可以嘗試保存它並按照這裏http://msdn.microsoft.com/en-us/data/gg193959.aspx捕獲異常。 – Daryn

+1

@Daryn它可能是一個DbConstraint,但RequiredAttribute與數據庫約束無關。它與視圖有關(「我的表單提交時必須設置哪些字段」)。如果你將你的UserProfile加載到你的控制器中,那麼你的數據庫就可以了,就這些了。不,EF不需要兩者。您可以使用ViewModel。 –

+0

@Daryn還要記住,只要UserProfileId是模型的一部分,並且您正在使用模型綁定(即ActionResult Create(費用支出)),該值可以由客戶端發送 - 即使它不在您的查看(閱讀黑客)。我同意@Raphael;刪除[Required]屬性並在Action中顯式設置它,以覆蓋客戶端發送的任何值。 – andes

1

一個,你應該確保這些網頁只能由授權用戶(添加[授權]在控制器中的每一個方法要求用戶先登錄以上)

有一對夫婦的方式訪問其實這樣做的:

其中之一是隱藏字段與標識 登錄的用戶這將是做它作爲ID的最不安全的方法將被從客戶端發佈到名UserProfileId和值服務器可以由客戶端操作。

我注意到,這些領域有必要的註釋,以便要麼你刪除[必填]使它驗證或者你做一個新的視圖模型所有這些屬性,而不需要UserProfileId有(顯然你不包括虛擬屬性,因爲在這種情況下不需要)。

它會變成這樣的事情:

public class ExpenseModel 
{ 
    [Required] 
    public string Name { get; set; } 
    [Required] 
    public decimal Limit { get; set; } 
    public int UserProfileId { get; set; } 
} 

作爲點睛之筆,你改變了看法預計模型:

@model MoneyDrainPlug.Models.ExpenseModel 

而且控制器希望收到後的模型一個帖子:

[Authorize] 
[HttpPost] 
    public ActionResult Create(ExpenseModel expense) 
    {    
     if (ModelState.IsValid) 
     { 
      UserProfile user = db.UserProfiles.Single(u => u.UserName == User.Identity.Name) 
      _expense = new Expense() { Name = expense.Name, Limit = expense.Limit, UserProfile = user }; 
      user.Expenses.Add(_expense);     
      db.SaveChanges(); 
      return RedirectToAction("Index"); 
     } 

     return View(expense); 
    }