2012-07-15 133 views
0

謝謝你的任何想法。MVC體系結構和自定義membershipProvider

我想了解有關MVC體系結構的知識,並且正在研究一個小項目,這個項目與我學習該工具的程度相比要低於項目的要求。

我需要弄清楚什麼是良好的,可接受的和不良的做法,以及爲什麼。我完全明白,沒有具體的正確答案,但必須有適合任何良好 - >可怕範圍的架構。儘管從某種意義上說,不止一個問題,但我希望良好設計實踐的邏輯流程意味着它們都與一個封裝答案有關。

我米使用Code First Membership provider由達科佩奇尼克

用戶實現一個接口IUSER其中隱藏許多性能如主鍵和密碼,這應被訪問/經由屬於成員類中的方法改變的。它還使用一個getter和setter方法通過字符串而不是User.Roles收集的數組:

public virtual String[] RoleNames 
{ 
    set 
    { 
     this.Roles = (ICollection<Role>)value.Select(r => 
      new Role { RoleName = r }).ToList(); 

問題1)我懷疑這個屬性可能是不好的做法,但究竟爲什麼我不確定。作爲方法GetRoleNames和SetRoleNames,這些會更好嗎?或者Icollection本身會更好地包含在IUser接口中嗎?

存在兩個使用AutoMapper從IUser映射的獨立視圖模型。這些模型涉及用戶是否正在註冊/更新自己的詳細信息,或者由網站管理員註冊/更新。

one viewModel包含一個用於角色和部門的IEnumerable。這些特性,目前正在通過automapper映射:

internal class RoleStringArrayToSelectListResolver 
    : ValueResolver<String[], IEnumerable<SelectListItem>> 
{ 
    protected override IEnumerable<SelectListItem> ResolveCore(String[] source) 
    { 
     return Roles.GetAllRoles().Select(x => new SelectListItem 
     { 
      Value = x, 
      Text = StringExtensions.ToSeparatedWords(x), 
      Selected = source.Contains(x) 

問題2)是autoMapper把這樣的邏輯可以接受的地方,如果它不應該在哪裏去了?

問題3.)回發後,通過存儲庫方法createUser和updateUser驗證業務邏輯。對於這些方法來說,接受一個I​​User實例作爲參數還是最佳的,或者更適合接受各種viewModels作爲參數的一些重載,以及爲什麼?

非常感謝您的任何想法的想法和幫助我的理解。

回答

1

爲什麼要創建一個IUser接口?我在你的問題中沒有看到任何解釋爲什麼它有用的原因。你是否期望換掉它的不同實現?還是1項目取決於其屬性,而無需訪問具體的用戶類?

問題1)我懷疑這個屬性可能是不好的做法,但是 不確定原因。這些會更好,因爲方法GetRoleNames 和SetRoleNames,或者Icollection本身會更好地包含在IUser接口中的 ?

在我看來,你希望能夠做的只是使用角色名字符串訪問和操作ICollection Roles屬性中的角色項。你可以離開類單獨(不創建一個屬性或方法),只是實現這個作爲一個擴展的方法:

public static class UserExtensions 
{ 
    public static string[] GetRoleNames(this User user) 
    { 
     return user.Roles.Select(r => r.Name).ToArray(); 
    } 

    public static void SetRoleNames(this User user, params string[] roleNames) 
    { 
     user.Roles = roleNames.Select(s => new Role { RoleName = s }).ToList(); 
    } 
} 

有了這個,你可以獲取並設置相應角色名稱。擴展方法只是針對已經在User類中定義的內容進行工作,而不會使用重載混淆它。擴展方法可以輕鬆地寫入IUser接口而不是具體的User類。你只寫this IUser user而不是this User user

var user = MethodToGetOrCreateUser(); 
string[] roleNames = user.GetRoleNames(); 
if (!roleNames.Any()) 
    user.SetRoleNames("StandardUser", "SomeOtherRole"); 

問題2)是autoMapper把這樣的邏輯可以接受的地方,如果 它不應該在哪裏去了?

我想我明白你在做什麼:你有一個字符串[]的角色名稱(可能來自你的User.GetRoleNames屬性/方法)。鑑於該字符串數組,你想創建一個IEnumerable的SelectListItems。對於每個角色都應該有一個SelectListItem,但只應選擇與數組中的字符串匹配的那個。由於您的客戶端代碼沒有所有角色名稱,因此您將此職責交給了值解析器。然後,您的客戶端代碼可能是這個樣子:

var user = MethodToGetOrCreateUser(); 
string[] roleNames = user.GetRoleNames(); 
var rolesMenu = Mapper.Map<IEnumerable<SelectListItem>>(roleNames); 

從本質上說,你正在automapper「聰明」,足以知道如何得到所有其他角色名是該用戶不在Automapper不應該。這很聰明;有任何種類的automapper解析器訪問數據存儲通常不是一個好主意,如果可能的話,你應該避免它。否則,您最終將獲得訪問數據存儲的靜態引用。像這樣的東西可能會在你的控制器,更清晰:

// this should actually go in Application_Start 
Mapper.CreateMap<IEnumerable<Role>, IEnumerable<SelectListItem>>() 
    .ForMember(d => d.Value, o => o.MapFrom(s => s.RoleName)) 
    .ForMember(d => d.Text, o => o.MapFrom(s => s.RoleName.ToSeparatedWords())) 
; 

// create your menu with all roles 
var rolesMenu = Mapper.Map<IEnumerable<SelectListItem>>(Roles.GetAllRoles()); 

// select only the roles that the user is in 
var user = MethodToGetOrCreateUser(); 
user.GetRoleNames().ToList().ForEach(r => 
{ 
    var match = rolesMenu.SingleOrDefault(i => i.Value == r); 
    if (match != null) match.Selected = true; 
}); 

我發現你可以完全避免ValueResolver類。任何你可以用ValueResolver類做的事情,你也可以用lambda超載.ResolveUsing()來做。

問題3.)回發後,業務邏輯通過 存儲庫方法createUser和updateUser進行驗證。它會爲 是最佳的這些方法來接受IUSER實例作爲論據,或 最好接受不同的ViewModels 作爲參數幾個重載,如果是這樣,爲什麼?

業務層應該不會接受的ViewModels作爲參數。他們是觀點的模型,而不是業務模型。將業務代碼視爲您的MVC項目的客戶端。如果您曾將業務代碼移出MVC項目,並且您擁有將ViewModel作爲參數的業務代碼,則代碼將無法編譯。爲什麼?因爲視圖模型在MVC項目中,並且MVC項目依賴於業務項目 - 反之亦然。

+0

謝謝你 - 你完整的答案在我的編程理論的理解幫助很大。 – Brent 2012-08-03 10:31:36