Законно ли расширить сущностную модель функциональностью в ASP.NET MVC? - PullRequest
2 голосов
/ 01 марта 2012

Прежде всего, вот моя ситуация.Я программирую приложение для интрасети, используя ASP.NET MVC 3 с Entity Framework 4.1.Мое приложение было разработано с использованием шаблонов проектирования «Единица работы» и «Хранилище».

Однако, по моему мнению, должно происходить то, что мое приложение имеет единицу работы, которая обеспечивает централизованный доступ ко всемрепозитории, которые дополнительно обеспечивают доступ к сущностям.

Допустим, у меня есть сущность с именем «ProductApprovalDocument» со свойствами «id», creationDate »и« compatibilityDecission », сохраненными в базе данных.Теперь я хочу, чтобы пользователь мог получить доступ к PDF-файлу документа, который кратко описан сущностью.Поскольку файлы хранятся в центральном каталоге на файловом сервере, используя формат URL «[fileServerDirectoryPath] / [ProductApprovalDocument.id] .pdf», я не хочу сохранять дополнительное свойство для этого пути к файлу в базе данных.То, что я хотел бы сделать, это дать объекту дополнительное свойство, называемое «filepath», которое автоматически создает путь с заданной информацией и возвращает его.

Теперь проблема:

Я используюинтерфейс под названием FileService для абстрагирования доступа к файлу от остальной части приложения.Теперь в моем случае мне нужно было бы получить доступ к объекту UnitOfWork из модели объекта, чтобы получить текущую реализацию FileService и получить предварительно настроенный путь к файлу.Я думаю, что это совершенно неправильный путь, потому что для меня модель сущностей должна использоваться только как контейнер данных, не более или менее.

Теперь вопрос:

Как мне справиться с такой ситуацией.Я не хотел бы всегда устанавливать свойство filepath через контроллер, потому что он более или менее статичен и, следовательно, может быть каким-то образом сделан автоматически моделью.

Редактировать (окончательное решение):

Благодаря ответу Андре Локера я получил еще одну точку зрения на мою проблему.

  • Какую цель я хотел достичь?
    • Я хотел, чтобы пользователь получил доступ к файлу, хранящемуся на файловом сервере.
  • Должен ли я предоставить каждому отображаемому объекту общий путь к файлу?
    • Нет!Подумайте о принципе MVC!Действия пользователя обрабатываются контроллером как раз вовремя.Вам не нужно предоставлять информацию, пока она действительно не будет использована.

Таким образом, решение состоит в том, чтобы просто отобразить все данные как обычно, а не отображать статическую ссылку html нафайлы, вы должны включить ActionLink в контроллер, который вычисляет путь к файлу на лету и автоматически перенаправляет пользователя в файл.

В представлении сделайте это:

@Html.ActionLink(Model.ID.ToString(), "ShowProductApprovalDocumentFile", "ProductApprovalDocument", new { ProductApprovalDocumentID = Model.ID }, null)

вместоэто:

<a href="@Model.FilePath">@Model.ID</a>

И добавьте соответствующее действие к контроллеру:

public ActionResult ShowProductApprovalDocumentFile(int ProductApprovalDocumentID )
{
   return Redirect(_unitOfWork.FileService.GetFilePathForProductApprovalDocument(ProductApprovalDocumentID));
}

Спасибо ребятам, которые нашли время, чтобы дать мне ответ, и особую благодарность Андре, который привел меняна удовлетворительный ответ!:)

Ответы [ 2 ]

1 голос
/ 01 марта 2012

Если я правильно понимаю свойство, есть несколько вариантов:

1) Сделайте так, чтобы свойство FilePath использовало локатор службы для поиска FileService:

public string FilePath {
    get {
        FileService fileService = DependencyResolver.Current.GetService<FileService>();
        return fileService.GetFilePathForDocument(this);
    }
}

Хотя я не большой поклонник статических сервисных локаторов, поскольку они затрудняют тестирование, это может быть приемлемым вариантом. Чтобы сделать его более легко тестируемым, вы можете сделать локатор файловой службы инъекционным:

private static readonly Func<FileService> defaultFileServiceLocator = ()=>DependencyResolver.Current.GetService<FileService>():
private Func<FileService> fileServiceLocator = defaultFileServiceLocator;

public Func<FileService> FileServiceLocator { 
    get { return fileServiceLocator; }
    set { fileServiceLocator = value ?? defaultFileServiceLocator; }
}

А затем используйте это в FilePath

public string FilePath {
    get {
        FileService fileService = fileServiceLocator();
        return fileService.GetFilePathForDocument(this);
    }
}

Таким образом, вы можете внедрить свой собственный локатор файловой службы во время тестирования.

2) Явно требует FileService при получении пути к файлу. Вместо свойства FilePath у вас будет:

public string GetFilePath(FileService service){
    service.GetFilePathForDocument(this);
}

Проблема в этом, конечно, в том, что теперь вызывающему GetFilePath необходимо иметь FileService. Это не является большой проблемой для контроллеров, потому что если вы используете IoC, вы можете внедрить FileService в конструктор контроллера. Этот подход является более чистым, так как он не зависит от сервисных локаторов, но, как вы видите, он немного более неудобен для вызывающего абонента.

3) Вставить FileService в сам класс документа.

Вместо использования локатора файловой службы вы должны внедрить сам файловую службу, когда создаете свой ProductApprovalDocument. При таком подходе вы можете снова использовать простое свойство FilePath. Основная проблема заключается в том, что это часто не слишком хорошо работает с ORM, поскольку они часто конструируют объекты, используя конструктор по умолчанию, и вам нужно каким-то образом подключиться к процессу конструирования объекта, чтобы ввести зависимости. Кроме того, я не большой поклонник внедрения сервисов в доменные объекты.

4) Вы устанавливаете FilePath снаружи сущности. Как вы сказали, это должно быть сделано несколько автоматически, так как вы не хотите делать это каждый раз вручную. Для этого потребуется некоторый слой, через который должны пройти все объекты, который устанавливает свойство FilePath.

5) Не делайте FilePath свойством ProductApprovalDocument вообще. Это был бы разумный выбор тоже. ProductApprovalDocument ничего не знает о своем FilePath, так почему оно должно быть свойством? Это FileService, который вычисляет значение. У вас все еще может быть отдельная версия модели представления ProductApprovalDocument, у которой действительно есть свойство FilePath. Вы устанавливаете свойство при создании модели вида:

var model = new ProductApprovalDocumentViewModel();
mapper.Map(realDocument, model); // map common properties with AutoMapper or so
model.FilePath = fileService.GetFilePathForDocument(realDocument);

Однако, если ProductApprovalDocument нужно что-то делать со своим FilePath (зачем это нужно?), Этот подход больше не работает.

Лично я бы пошел с решением 5, 2 или 1 в том порядке приоритета, где это применимо.

0 голосов
/ 01 марта 2012

Хотя я не решался бы рассчитывать на возможность вычисления пути к файлу, и я бы предпочел хранить его как часть сущности (на случай, если когда-либо потребуется изменить его по какой-либо причине), в вашей ситуации, если бы я был непреклонен, я Я хотел бы сделать это так, как вы сказали, я думаю, я бы расширил FileService / ViewModel, чтобы иметь свойство Filepath, которое было получено указанным вами способом.

например. если бы я хотел создать ссылку для скачивания, я бы сделал это в ViewModel

public string FilePath
{
   get
   {
      return String.Format(@"thehardcodedbit{0}.pdf",ID);
   }
}

РЕДАКТИРОВАТЬ: Если у вас есть объект, сгенерированный EF4.x, то он будет сгенерирован как частичный класс, так что вы всегда можете расширить его следующим образом (я сделал такую ​​вещь, и она работает хорошо):

Скажем, сгенерированный объект выглядит так:

Namespace Da_Wolf.Model.Entities.File
{
   public partial class UploadedFile
   {....}
}

Тогда вы можете создать частичный класс, подобный этому:

Namespace Da_Wolf.Model.Entities.File
{
   public partial class UploadedFile
   {
     public string FilePath
     {
        get
        {
           return String.Format(@"thehardcodedbit{0}.pdf",ID);
        }
     }  
   }
}

Теперь у вас есть свойство, которое вы хотите использовать везде, без добавления чего-либо в ViewModels.

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