Как удалить зависимость от System.Web.Mvc в сборке модели домена, содержащей POCO - PullRequest
3 голосов
/ 30 ноября 2010

У меня есть сборка, созданная с использованием шаблона POCO с использованием Entity Framework (например, «Company.Models.dll»). Помимо сгенерированных POCO, у меня также есть «отслеживание» частичных классов, которые определяют метаданные с использованием System.ComponentModel.DataAnnotations.Так, например, Company.Models.Customer генерируется автоматически (в отдельной папке), а затем у меня есть частичный класс с тем же пространством имен.В этом частичном классе я определяю внутренний класс для метаданных ... Например:

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace Company.Models
{
    [MetadataType(typeof (CustomerMetaData))]
    public partial class Customer
    {
        public override string ToString()
        {
            return String.Format("Id: {0}, Name: {1}", Id, Name);
        }

        //[Bind(Exclude = "Id")]
        public class CustomerMetaData
        {
            [ScaffoldColumn(false)]
            public int Id { get; set; }

            [DisplayName("Name")]
            [Required(ErrorMessage = "Customer Name is required.")]
            [StringLength(100, ErrorMessage = "Customer name cannot exceed 100 characters.", MinimumLength = 2)]
            public string Name { get; set; }
        }
    }
}

Проблема, с которой я столкнулся, заключается в том, что теперь я хочу использовать эту сборку в своем проекте MVC и хочу использовать специфичные для MVC атрибуты.(как закомментированный атрибут Bind выше). Однако для этого требуется сделать мою Company.Models.dll зависимой от System.Web.Mvc.dll.

Я хотел бы избежать этого любой ценой, если это возможно, нокак?

До сих пор я знаю о 2 возможных решениях и прошу сообщество высказать свое мнение или более эффективные подходы ...

Решение 1

Это решение обсуждалось здесь: Использование аннотаций данных в POCO с MVC для удаленной проверки «Хитрость» заключалась в том, чтобы использовать ViewModels и отображать (вручную или с помощью AutoMapper) POCO для MVC-проекта конкретных ViewModels.Затем примените все необходимые атрибуты к ViewModels вместо POCO модели домена.Хотя это имеет смысл для больших проектов, для небольших простых решений это немного излишне ...

Solution 2

Использовать атрибут Bind в параметрах действия контроллера (как видно на некоторых http://www.asp.net/mvc учебники).Например:

//
// POST: /Customer/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude="Id")]Customer customerToCreate)
{
        if (!ModelState.IsValid)
        return View();

        // TODO: Add insert logic here
    return RedirectToAction("Index");
    }

Использование этого решения позволит пропустить зависимость от System.Web.Mvc из моей библиотеки POCO за счет необходимости не забывать вставлять атрибут Bind во все соответствующие действия контроллера.Кроме того, если у меня несколько проектов ASP.NET MVC, проблема усугубляется ...

Итак, есть ли другой путь?;)

Ответы [ 3 ]

2 голосов
/ 30 ноября 2010

Я бы предположил, что ваши объекты POCO не содержат какого-либо кода, специфичного для пользовательского интерфейса.В идеале они не должны содержать какой-либо код, специфичный для персистентности данных, но EF делает это непросто.

Первое решение, безусловно, является лучшим решением для того, чтобы сделать ваше приложение более масштабируемым и лучше разделить ваши проблемы.

Другим решением может быть создание собственных атрибутов домена (MyRequiredAttribute, MyStringLengthAttribute и т. Д.) И размещение их в сборке ядра.Затем вы можете создать пользовательский поставщик метаданных, чтобы MVC распознавал эти атрибуты.Вот пример того, как создать это: http://bradwilson.typepad.com/blog/2009/10/enterprise-library-validation-example-for-aspnet-mvc-2.html

0 голосов
/ 30 ноября 2010

Самое простое решение: поместите Partial Class Customer в свой проект MVC. Никаких других изменений не требуется.

0 голосов
/ 30 ноября 2010

Третий вариант, аналогичный решению 2, связан с типом клиента.

Вы бы создали Связыватель модели.

Смотреть презентацию Джимми Богардса MVC Conf по теме: http://www.viddler.com/explore/mvcconf/videos/1/

Пример кода:

Global ASAX

    protected void Application_Start()
    {

        ModelBinders.Binders.Add(typeof(Media), new MediaModelBinder());
        ModelBinders.Binders.Add(typeof(Album), new AlbumModelBinder());

    }

ModelBinder Класс

public class MediaModelBinder : BaseModelBinder, IModelBinder 
{
    /// <summary>
    /// Initializes a new instance of the <see cref="MediaModelBinder"/> class.
    /// </summary>
    public MediaModelBinder() : base(DependencyInjection.Resolve<IUserAuthorization>()) { }

    /// <summary>
    /// Binds the model to a value by using the specified controller context and binding context.
    /// </summary>
    /// <param name="controllerContext">The controller context.</param>
    /// <param name="bindingContext">The binding context.</param>
    /// <returns>The bound value.</returns>
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var mediaRepository = DependencyInjection.Resolve<IMediaRepository>();
        User user = GetUser(controllerContext);

        int mediaId = Convert.ToInt32(controllerContext.RouteData.Values["id"]);
        Media media = mediaRepository.RetrieveByPrimaryKeyAndUserId(mediaId, user.Id);

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