ASP.NET MVC3 Automapper Viewmodel / Model View проверки - PullRequest
5 голосов
/ 14 мая 2011

(Опять же, вопрос проверки MVC. Я знаю, я знаю ...)

Я хотел бы использовать AutoMapper (http://automapper.codeplex.com/) для проверки полей в моих представлениях Create для полей, которых нет в моей базе данных (и, следовательно, нет в моей DataModel).

Пример: у меня есть учетная запись / представление создания для пользователей, чтобы создать новую учетную запись, и я хочу, чтобы оба поля - Пароль и ConfirmPassword, чтобы пользователям приходилось дважды вводить пароль для подтверждения.

Таблица учетных записей в базе данных выглядит следующим образом:

Account[Id(PK), Name, Password, Email]

Я сгенерировал модель данных сущности ADO.NET, и из этого я сгенерировал модели с использованием самоконтролируемого генератора сущностей ADO.NET.

Я также написал собственный AccountViewModel для аннотаций валидации, например [Обязательный].

Итак, подведем итог, это моя структура проекта:

Controllers:
   AccountController

Models:
   Database.edmx (auto-generated from database)
   Model.Context.tt (auto-generated from edmx)
   Model.tt (auto-generated from edmx)
   AccountViewModel.cs

Views:
   Account
      Create.cshtml

Код моей AccountViewModel выглядит следующим образом:

public class AccountViewModel
    {
        public int Id { get; set; }

        [Required]
        public string Name { get; set; }

        [Required]
        public string Password { get; set; }

        [Required]
        [Compare("Password")]
        public string ConfirmPassword { get; set; }
    }

Теперь мой Create View выглядит так:

@model AutoMapperTest.Models.Account
<script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Account</legend>
        <div class="editor-label">
            Name
        </div>
        <div class="editor-field">
            @Html.TextBox("Name")
            @Html.ValidationMessageFor(model => model.Name)
        </div>
        <div class="editor-label">
            Email
        </div>
        <div class="editor-field">
            @Html.TextBox("Email")
            @Html.ValidationMessageFor(model => model.Email)
        </div>
        <div class="editor-label">
            Password
        </div>
        <div class="editor-field">
            @Html.TextBox("Password")
            @Html.ValidationMessageFor(model => model.Password)
        </div>
        <div class="editor-label">
            Confirm your password
        </div>
        <div class="editor-field">
            @Html.TextBox("ConfirmPassword");
            @Html.ValidationMessageFor(model => model.ConfirmPassword)
        </div>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Мой код не работает, потому что моя Модель, конечно, не содержит поля ConfirmPassword. Теперь маленькая птичка прошептала мне, что AutoMapper может исправить это для меня. Но я не могу понять ... Может кто-нибудь сказать мне, что я должен сделать, чтобы сделать эту работу? Мой AccountController теперь выглядит так:

private readonly AccountViewModel _viewModel = new AccountViewModel();
private readonly DatabaseEntities _database = new DatabaseEntities();

//
        // GET: /Account/Create

        public ActionResult Create()
        {
            Mapper.CreateMap<AccountViewModel, Account>();
            return View("Create", _viewModel);
        } 

        //
        // POST: /Account/Create

        [HttpPost]
        public ActionResult Create(AccountViewModel accountToCreate)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    var newAccount = new Account();
                    Mapper.Map(accountToCreate, newAccount);
                   _database.Account.AddObject(newAccount);
        _database.SaveChanges();
                }

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

Но это не работает ... (Вот пример из http://weblogs.asp.net/shijuvarghese/archive/2010/02/01/view-model-pattern-and-automapper-in-asp-net-mvc-applications.aspx)

Может кто-нибудь, пожалуйста, просветите меня по этому вопросу? Большое спасибо и мои извинения за стену текста и сотни вопросов на ту же тему ...

Ответы [ 2 ]

18 голосов
/ 15 мая 2011

Несколько замечаний по поводу вашего кода:

  1. Ваше представление строго типизировано (объявление @model) для модели Account, тогда как оно должно быть напечатано для модели представления AccountViewModel (нет смысла объявлять модель представления, если вы не используете ее вид).
  2. AutoMapper не используется для проверки, только для преобразования между типами
  3. Вам не нужно объявлять поле readonly для вашей модели представления (AccountViewModel) внутри контроллера. Вы можете создать экземпляр модели представления внутри действия GET и оставить связыватель модели по умолчанию для его экземпляра в качестве аргумента действия для действия POST.
  4. Вы должны выполнить настройку AutoMapper (Mapper.CreateMap<TSource, TDest>) только один раз для всего приложения (в идеале в Application_Start), а не внутри действия контроллера
  5. В вашей модели представления нет поля Email, которое может быть причиной сбоя обновления (особенно если это поле является обязательным в вашей базе данных)

Вот как может выглядеть ваш код:

public ActionResult Create()
{
    var model = new AccountViewModel();
    return View("Create", model);
} 

[HttpPost]
public ActionResult Create(AccountViewModel accountToCreate)
{
    try
    {
        if (ModelState.IsValid)
        {
            var newAccount = Mapper.Map<AccountViewModel, Account>(accountToCreate);
           _database.Account.AddObject(newAccount);
           _database.SaveChanges();
        }
        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}
3 голосов
/ 15 мая 2011

замените первую строку вашего просмотра на

@model AutoMapperTest.AccountViewModel

Также вам нужно всего лишь вызвать Mapper.CreateMap один раз для срока службы приложения (например, при запуске приложения)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...