使用SelectListItem时“干掉”MVC模型

时间:2015-02-18 11:07:12

标签: c# asp.net asp.net-mvc asp.net-mvc-5 dry

我刚刚开始使用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>
}

2 个答案:

答案 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

使用这种方法为我节省了大量的数据库查找,因为我正在填充包含多个选择列表的表单,这些列表很少 - 如果有的话 - 更改。