2013-07-08 55 views
2

我有一個ASP.NET MVC 3應用程序。ASP.NET MVC設計模式最佳實踐與服務

我有一個ModelViewModel,View,Controller。作爲IoC使用Ninject

我的Controller使用ViewModel將數據傳遞給View

我已經開始使用Service s(具體和接口類型)從ViewModel獲取信息,並根據數據庫對其進行查詢以對其進行處理。

我可以使用相同的Service來設置ViewModel嗎?或者這是否違背設計模式的五穀?

I.e.我可以在Service圖層中抽象設置ViewModel嗎?

情景

的場景是;我的Model有很多參考Models,所以當我在控制器中設置ViewModel它是冗長的,我覺得Controller做得太多了。所以我想能夠只是像做:

var vm = _serviceProvider.SetupViewModel(Guid model1Id, Guid model2Id, /*etc..*/)

而且在ServiceProviderSetupViewModel功能應該是這樣的:

public MyModelViewModel SetupViewModel(Guid model1Id, Guid model2Id, /*etc...*/) 
{ 
    var vm = new MyModelViewModel(); 
    var model1 = _repository.Model1s.FirstOrDefault(x => x.Id.Equals(model1Id)); 
    var model2 = _repository.Model2s.FirstOrDefault(x => x.Id.Equals(model2Id)); 
// etc.... 

    vm.Model1 = model1; 
    vm.Model2 = model2; 

    return vm; 
} 

通過這樣做,我也可以添加一些null條件而且,不用擔心讓我的Controller真的真的很大!

我使用1 ViewModel作爲創建/編輯操作。我不在其他地方重複使用ViewModel

+0

如何提供關於您特定架構的更多信息?也許是一個簡短的代碼示例,解釋你想要做什麼? –

+0

我已經編輯了我的問題,但我沒有把它放在它的代碼 –

+1

這聽起來像你重複使用ViewModels是不好的。 – Phill

回答

5

我會讓服務層返回一個域模型並將其映射到控制器中的ViewModel。

通過這種方式,您可以將多種ViewModel的服務方法用於桌面和移動視圖。

您可以讓AutoMapper爲您做些辛苦的工作,或者通過在採用域模型的ViewModel中創建構造函數來手動完成。

域模型:

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

    public string FirstName { get; set; } 

    public string LastName { get; set; } 

    public string Telephone { get; set; } 

    public string Email { get; set; } 

    public virtual ICollection<Order> Orders { get; set; } 
} 

的視圖模型:

public class CustomerWithOrdersModel 
{ 
    public CustomerWithOrdersModel(Customer customer) 
    { 
     Id = customer.Id; 
     FullName = string.Format("{0}, {1}", customer.LastName, customer.FirstName); 
     Orders = customer.Orders.ToList(); 
    } 

    public int Id { get; set; } 

    public string FullName { get; set; } 

    public IEnumerable<Order> Orders { get; set; } 
} 

編輯:AutoMapper例如:

從含有映射的AutoMapper輪廓CustomerCustomerWithOrdersModel

public class ViewModelProfile : Profile 
{ 
    public override string ProfileName 
    { 
     get { return "ViewModel"; } 
    } 

    protected override void Configure() 
    { 
     CreateMap<Customer, CustomerWithOrdersModel>() 
      .ForMember(dest => dest.FullName, opt => opt.MapFrom(src => string.Format("{0}, {1}", src.LastName, src.FirstName))) 
      .ForMember(dest => dest.Orders, opt => opt.MapFrom(src => src.Orders.ToList())); 
    } 
} 
按慣例映射

Id

ViewModelProfile擴展方法:

public static class ViewModelProfileExtensions 
{ 
    public static CustomerWithOrdersModel ToModel(this Customer customer) 
    { 
     return Mapper.Map<CustomerWithOrdersModel>(customer); 
    } 

    public static Customer ToEntity(this CustomerWithOrdersModel customerWithOrdersModel) 
    { 
     return Mapper.Map<Customer>(customerWithOrdersModel); 
    } 
} 

控制器動作:

public ActionResult Details(int customerId) 
{ 
    Customer customer = _customerService.GetById(customerId); 
    CustomerWithOrdersModel customerWithOrders = customer.ToModel(); 
    return View(customerWithOrders); 
} 

如果您創建CustomerWithOrdersModelCustomer的映射,您可以使用customerWithOrdersModel.ToEntity()來映射回它的域模型。

那就是它!您可以使用ViewModel中的Customer域模型刪除構造函數。

+0

你能用AutoMapper給出一個例子來說明爲什麼它更好用嗎?我目前創建和使用'ViewModels'的方法遠遠好於你正在展示的方法,當我有一個複雜的'Business Model'時,我只想從詳細的'ViewModels'和'Controllers'移除 –

+0

@ No1_Melman更新我的答案。 –

+0

這非常酷,我將不得不啓動一個全新的項目來找出所有使用AutoMapper的複雜性。 –

1

如果你有視圖模型作爲他們自己的項目,並處理你的服務層中的視圖模型的映射和返回,我沒有看到任何錯誤。爲了分離問題,你總是可以有另一個處理映射的組件。

+0

因此,這將是具體和接口實現的另一項服務? –

+0

是的。這將允許您將其注入到控制器中,並有助於進行單元測試。正如您可以獨立測試服務一樣,並且不用擔心每次在您的某個控制器中使用相同的方法時都需要進行測試。在你的控制器測試中,你可以嘲笑服務。 – Maess

+0

我已經在問題中添加了一些信息,是否仍然與您的答案保持一致? –