簡體   English   中英

MVC體系結構和自定義的MembershipProvider

[英]MVC architecture and custom membershipProvider

謝謝您的任何想法。

我正在嘗試學習MVC架構,並致力於一個小項目,這對我來說學習工具遠勝於項目的需求。

我需要弄清楚什么是好的,可接受的和不良的做法,以及原因。 我完全理解,沒有具體的正確答案,但是必須有適合任何良好->糟糕范圍的架構。 盡管從某種意義上說,這不僅僅是一個問題,但我希望良好的設計實踐的邏輯流程意味着它們都與單個封裝答案相關。

我正在使用DarkoPečnik的Code First Membership提供商

用戶實現一個接口IUser,該接口隱藏許多屬性,例如主鍵和密碼,應該通過屬於Membership類的方法來訪問/更改這些屬性。 它還通過字符串而不是User.Roles集合將getter和setter用於字符串數組:

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

問題1.)我懷疑此屬性可能是不正確的做法,但不確定確切原因。 這些作為方法GetRoleNames和SetRoleNames會更好,還是將Icollection本身更好地包含在IUser接口中?

存在兩個單獨的viewModel,它們是使用AutoMapper從IUser映射的。 這些模型與用戶是自己注冊/更新有關其自身的詳細信息還是由網站管理員進行注冊/更新有關。

一個viewModel包含一個用於角色和部門的IEnumerable。 這些屬性當前正在通過自動映射器進行映射:

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驗證業務邏輯。 對於這些方法,將IUser實例作為參數是最佳選擇,還是對於接受各種viewModels作為參數的幾個重載來說是最佳選擇,如果可以,為什么?

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

為什么要創建一個IUser界面? 在您的問題中,我沒有看到任何解釋其用途的理由。 您期望換掉它的不同實現嗎? 還是1個項目依賴於它的屬性而不訪問具體的User類?

問題1.)我懷疑此屬性可能是不正確的做法,但不確定確切原因。 這些作為方法GetRoleNames和SetRoleNames會更好,還是將Icollection本身更好地包含在IUser接口中?

在我看來,您想要做的就是僅使用角色名稱字符串訪問和操作ICollection Roles屬性中的Role項目。 您可以不理會類(不創建屬性或方法),而僅將其實現為擴展方法:

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是否可以放置這樣的邏輯,如果不是,應該放在哪里?

我想我知道您在做什么:您有一個string []角色名稱(可能來自User.GetRoleNames屬性/方法)。 給定該字符串數組,您要創建一個IEnumerable的SelectListItems。 每個角色都應該有一個SelectListItem,但是只能選擇與數組中的字符串匹配的角色。 由於您的客戶代碼沒有所有的角色名稱,因此您將責任交給了價值解析器。 您的客戶代碼可能看起來像這樣:

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

從本質上講,您使自動映射器“足夠聰明”,足以知道如何獲取該用戶不在的所有其他角色名稱。自動映射器不應該這么聰明; 通常,讓任何類型的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作為參數的幾個重載來說是最佳選擇,如果可以,為什么?

您的業​​務層永遠不應接受將視圖模型作為參數。 它們是視圖的模型,而不是業務的模型。 將業務代碼視為您的MVC項目的客戶。 如果您曾經將業務代碼移出MVC項目,並且您有將ViewModels作為參數的業務代碼,則該代碼將無法編譯。 為什么? 因為視圖模型在MVC項目中,並且MVC項目依賴於業務項目-而不是相反。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM