我刚刚开始使用MVC,我可以在线找到大多数DRY原则的例子。虽然我不会全部使用,因为我发现一些制作代码更难阅读。
我找到了一个我找不到的例子,我觉得必须有办法去做。
基本上,我在控制器中填充模型选择列表类型对象,这意味着我必须重用代码。我知道我可以把它放在一个方法中,但我想知道是否还有将它放在模型中,这样无论何时使用model / viewmodel,都会调用此操作来填充选择列表内容。
我在下面提供了我的代码示例。
模型
using System;
using System.Data.Entity;
namespace MyWebsite.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
namespace CustomerWebsites.Models
{
public class CustomerWebsites
{
public int Id { get; set; }
public Guid UserGuid { get; set; }
public string WebsiteAddress { get; set; }
public string WebsiteType { get; set; }
public DateTime ReleaseDate { get; set; }
public string Description { get; set; }
public decimal Budget { get; set; }
public DateTime CreationDate { get; set; }
public string DevelopmentStatus { get; set; }
public int CompletedPercentage { get; set; }
public bool Completed { get; set; }
public decimal TotalCost { get; set; }
public decimal TotalPaid { get; set; }
}
public class CustomerWebsitesDBContext : DbContext
{
public CustomerWebsitesDBContext()
: base("DefaultConnection")
{
}
public static CustomerWebsitesDBContext Create()
{
return new CustomerWebsitesDBContext();
}
public DbSet<CustomerWebsites> CustomerWebsites { get; set; }
}
}
}
视图模型
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace MyWebsite.ViewModels
{
public class CreateCustomerWebsites
{
public int Id { get; set; }
public Guid UserGuid { get; set; }
[Required]
public string WebsiteAddress { get; set; }
public string WebsiteType { get; set; }
public DateTime ReleaseDate { get; set; }
public string Description { get; set; }
public decimal Budget { get; set; }
public DateTime CreationDate { get; set; }
public string DevelopmentStatus { get; set; }
public int CompletedPercentage { get; set; }
public bool Completed { get; set; }
public decimal TotalCost { get; set; }
public decimal TotalPaid { get; set; }
public IEnumerable<SelectListItem> AllUsers { get; set; }
}
}
的Controler
// GET: CustomerWebsites/Create
public ActionResult Create()
{
var db = new ApplicationDbContext();
var users = db.Users.ToArray();
var allUsers = users.Select(x => new SelectListItem
{
Value = x.Id,
Text = x.Email
});
var model = new CreateCustomerWebsites
{
AllUsers = allUsers
};
return View(model);
}
// POST: CustomerWebsites/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateCustomerWebsites model)
{
if (ModelState.IsValid)
{
var userGuid = new Guid(User.Identity.GetUserId());
var developmentStatus = "Pending MyWebsite Review";
if (User.IsInRole("Administrator"))
{
userGuid = model.UserGuid;
developmentStatus = model.DevelopmentStatus;
}
db.CustomerWebsites.Add(new CustomerWebsites
{
UserGuid = userGuid,
WebsiteAddress = model.WebsiteAddress,
CreationDate = DateTime.Now,
ReleaseDate = model.ReleaseDate,
Budget = model.Budget ,
Description = model.Description,
DevelopmentStatus = developmentStatus,
CompletedPercentage = model.CompletedPercentage,
Completed = model.Completed,
TotalCost = model.TotalCost,
TotalPaid = model.TotalPaid
});
db.SaveChanges();
return RedirectToAction("Index");
}
var dbUsers = new ApplicationDbContext();
var users = dbUsers.Users.ToArray();
var allUsers = users.Select(x => new SelectListItem
{
Value = x.Id,
Text = x.Email
});
model = new CreateCustomerWebsites
{
AllUsers = allUsers
};
return View(model);
}
查看
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>CustomerWebsites</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@if (User.IsInRole("Administrator"))
{
<div class="form-group">
@Html.LabelFor(model => model.UserGuid, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.UserGuid, Model.AllUsers, "-- Select a user --")
@Html.ValidationMessageFor(model => model.UserGuid, "", new { @class = "text-danger" })
</div>
</div>
}
<div class="form-group">
@Html.LabelFor(model => model.WebsiteAddress, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.WebsiteAddress, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.WebsiteAddress, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.WebsiteType, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.WebsiteType, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.WebsiteType, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ReleaseDate, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ReleaseDate, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ReleaseDate, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Description, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.TextAreaFor(model => model.Description, new { rows = "10", @class = "form-control" })
@Html.ValidationMessageFor(model => model.Description, "", new { @class = "text-danger" })
</div>
</div>
@if (User.IsInRole("Administrator"))
{
<div class="form-group">
@Html.LabelFor(model => model.DevelopmentStatus, htmlAttributes: new {@class = "control-label col-md-2"})
<div class="col-md-10">
@Html.EditorFor(model => model.DevelopmentStatus, new {htmlAttributes = new {@class = "form-control"}})
@Html.ValidationMessageFor(model => model.DevelopmentStatus, "", new {@class = "text-danger"})
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.CompletedPercentage, htmlAttributes: new {@class = "control-label col-md-2"})
<div class="col-md-10">
@Html.EditorFor(model => model.CompletedPercentage, new {htmlAttributes = new {@class = "form-control"}})
@Html.ValidationMessageFor(model => model.CompletedPercentage, "", new {@class = "text-danger"})
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Completed, htmlAttributes: new {@class = "control-label col-md-2"})
<div class="col-md-10">
<div class="checkbox">
@Html.EditorFor(model => model.Completed)
@Html.ValidationMessageFor(model => model.Completed, "", new {@class = "text-danger"})
</div>
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.TotalCost, htmlAttributes: new {@class = "control-label col-md-2"})
<div class="col-md-10">
@Html.EditorFor(model => model.TotalCost, new {htmlAttributes = new {@class = "form-control"}})
@Html.ValidationMessageFor(model => model.TotalCost, "", new {@class = "text-danger"})
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.TotalPaid, htmlAttributes: new {@class = "control-label col-md-2"})
<div class="col-md-10">
@Html.EditorFor(model => model.TotalPaid, new {htmlAttributes = new {@class = "form-control"}})
@Html.ValidationMessageFor(model => model.TotalPaid, "", new {@class = "text-danger"})
</div>
</div>
}
<div class="form-group">
@Html.LabelFor(model => model.Budget, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Budget, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Budget, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
答案 0 :(得分:2)
基本上我现在填充模型选择列表类型对象 控制器,这意味着我必须重用代码。我知道我可以 只是把它放在一个方法,但我想知道是否有任何方式放 它在模型中,以便随时使用model / viewmodel 调用action来填充选择列表内容。
在视图模型中放置任何方法通常不是一个好主意,特别是对于数据访问和人口。 Viewmodels应该是普通的数据容器,没有知识或行为。您通过从控制器操作填充SelectList来做正确的事。
就DRY来说,它看起来已经很干了。您只重复一行或两行代码。你可以使用AutoMapper之类的东西为你做投影来干掉它:
var users = dbUsers.Users.ToArray();
model = new CreateCustomerWebsites
{
AllUsers = Mapper.Map<IEnumerable<SelectListItem>>(users)
};
...但要这样做,您必须添加更多代码来定义映射。您可能也喜欢在您的问题中提到将投影移动到控制器上的私有方法,但这也意味着添加更多代码,并将一些相关代码从控制器操作体移开。而且你实际上只删除了2行代码(每个代码需要保存下拉列表中的一行)。就个人而言,我现在的方式并没有出现问题。
另一种选择可能是在ActionFilterAttribute
期间写一个ResultExecuted
来填充SelectList。但重点是,不要从ViewModel中执行此操作:在操作执行期间执行此操作。
答案 1 :(得分:0)
这可能是OTT满足您的需求,但我刚才看了一下,并且还试图解决每次填充选择列表时都执行数据库查找的事实。
我有一个位于Controllers和dbcontext之间的服务类,因此在您的示例中,我将有一个名为UserService.cs
的类。服务类处理业务逻辑和保持控制器方法合理“薄”。在UserService类中,您有一个名为GetAsSelectList()
的方法:
public SelectList GetAsSelectList()
{
var b = CacheHelper.GetCacheItem("UserSelectList", UsersDelegate, CacheHelper.SlidingParam, CacheHelper.AbsoluteParam);
return new SelectList((IEnumerable)b, "Id", "Name");
}
这使用CacheHelper类来检查内存中是否存在选择列表。如果是,则返回它,从而保存数据库查找。如果不在缓存中,则运行以下方法以生成选择列表&amp;将其存储在缓存中,名称为“UserSelectList”。
private object UsersDelegate()
{
return (from c in _context.Set<Users>()
select new
{
c.Id, c.Name
}).ToList();
}
可以找到实际的CacheHelper
课程here
使用这种方法为我节省了大量的数据库查找,因为我正在填充包含多个选择列表的表单,这些列表很少 - 如果有的话 - 更改。