首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Asp.Net-Mvc-5中的瘦控制器

Asp.Net-Mvc-5中的瘦控制器
EN

Stack Overflow用户
提问于 2017-10-03 12:53:18
回答 2查看 909关注 0票数 0

关于在Asp.net Mvc 5应用程序中创建“瘦控制器”的实现,我有一个问题。在过去的几天里,我一直在研究这个话题,我相信我现在需要一个具体的例子来联系我理解中的点。

因此,我想在我的应用程序中使用Unit测试。我研究过创建视图模型工厂和构建器、瘦控制器-fat模型,但我不确定如何实现这些设计模式中的任何一个,我已经在这个特定的场景中读到过。

下面您会发现在我的管理控制器中有5个不同的操作。我担心,为了简化测试/单元测试,它们会嗅到并需要一些清理。我知道这类问题通常没有“正确的答案”,所以我非常感谢所有有助于简化我的应用程序测试的答案。

以下是我的行动:

行动1:

代码语言:javascript
复制
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "DM_Admin")]

public async Task<ActionResult> Users_Create([DataSourceRequest] DataSourceRequest request, ManageUsersViewModel model)

{
    if (model != null && ModelState.IsValid)
    {
        // instantiate new application user
        var user = new ApplicationUser
        {
            UserName = model.Email,
            Email = model.Email,
            FirstName = model.FirstName,
            LastName = model.LastName
        };

        // format the RolesList to type List<string> for entry  
        List<string> rolesToAssign = getRoleNameList(model);

        try
        {
            // persist user to User Db
            var createResult = await UserManager.CreateAsync(user, model.Password);
            if (createResult.Succeeded)
            {
                // persist user roles to User Db
                var rolesResult = await UserManager.AddToRolesAsync(user.Id, rolesToAssign.ToArray());
                if (rolesResult.Succeeded)
                {
                    return RedirectToAction("ManageUsers");
                }
                AddErrors(rolesResult);
            }
            else
            {
                AddErrors(createResult);
            }
        }
        catch (Exception ex)
        {
            ErrLog.LogError(ex, "ManageController.Users_Create");
        }
    }

    return Json(new[] { model }.AsQueryable().ToDataSourceResult(request, ModelState));
}

行动2:

代码语言:javascript
复制
[Authorize(Roles = "DM_Admin")]
public async Task<ActionResult> Users_Read([DataSourceRequest] DataSourceRequest request)

{
    List<ManageUsersViewModel> users = null;
List<ApplicationUser> allUsers = null;

try
{
    // get all Data Management roles
    var dmRoles = await RoleManager.Roles.Where(r => r.Name.Contains("DM_")).ToListAsync();

    // find all the users for each Data Management role
    foreach (var id in dmRoles.Select(r => r.Id).ToList())
    {
        if(allUsers == null)
        {
            allUsers = await UserManager.Users.Where(u => u.Roles.Any(r => r.RoleId == id)).ToListAsync();
        }
        else
        {
            allUsers.AddRange(await UserManager.Users.Where(u => u.Roles.Any(r => r.RoleId == id)).ToListAsync());
        }
    }

    // list of users may have repeats, so remove repeated users in list 
    allUsers = allUsers.Distinct().ToList();
    // instantiate view model with list of users and their respective roles
    users = allUsers.Select(u => new ManageUsersViewModel
    {
        Id = u.Id,
        FirstName = u.FirstName,
        LastName = u.LastName,
        Email = u.Email,
        Password = u.PasswordHash,
        ConfirmPassword = u.PasswordHash,
        RolesList = dmRoles.Where(r => r.Users.Any(user => user.UserId == u.Id)).Select(r => new RoleModel
                {
                    Id = r.Id,
                    Name = r.Name
                }).ToList()
    }).ToList();
}
catch (Exception ex)
{
    ErrLog.LogError(ex, "ManageController.Users_Read");
}

return Json(users.ToDataSourceResult(request));
}

行动3:

代码语言:javascript
复制
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "DM_Admin")]
public async Task<ActionResult> Users_Edit([DataSourceRequest] DataSourceRequest request, ManageUsersViewModel model)
{
    if (model != null && ModelState.IsValid)
    {
        // format the RolesList to type List<string> with name and List<string> with Id for entry and comparison
        List<string> rolesToAssign = getRoleNameList(model);
        List<string> modelRoleIds = getRoleIdList(model);
    try
    {
        var currentUser = await UserManager.FindByIdAsync(model.Id);
        // create list of current user's roles to determine if they have been modified
        List<string> currentUserRoleIds = new List<string>();
        foreach (var role in currentUser.Roles)
        {
            currentUserRoleIds.Add(role.RoleId);
        }

        // persist user roles to User Db if changes have been made
        if (currentUserRoleIds.Except(modelRoleIds).Any() || modelRoleIds.Except(currentUserRoleIds).Any())
        {
            var updateRolesResult = await AssignRolesToUser(model.Id, rolesToAssign.ToArray());
            if (updateRolesResult.Succeeded)
            {
                return RedirectToAction("ManageUsers", new { Message = ManageMessageId.AccountUpdateSuccess });
            }
            AddErrors(updateRolesResult);
        }
        // persist user info to User Db if changes have been made
        else if(currentUser.Email != model.Email || currentUser.FirstName != model.FirstName || currentUser.LastName != model.LastName)
        {
            currentUser.UserName = model.Email;
            currentUser.Email = model.Email;
            currentUser.FirstName = model.FirstName;
            currentUser.LastName = model.LastName;

            var updateUserResult = await UserManager.UpdateAsync(currentUser);
            if (updateUserResult.Succeeded)
            {
                return RedirectToAction("ManageUsers", new { Message = ManageMessageId.AccountUpdateSuccess });
            }
            AddErrors(updateUserResult);
        }
        // persist user password to User Db if changes have been made
        else
        {
            var token = await UserManager.GeneratePasswordResetTokenAsync(currentUser.Id);
            var updatePasswordResult = await UserManager.ResetPasswordAsync(currentUser.Id, token, model.Password);
            if (updatePasswordResult.Succeeded)
            {
                return RedirectToAction("ManageUsers", new { Message = ManageMessageId.AccountUpdateSuccess });
            }
            AddErrors(updatePasswordResult);
        }
    }
    catch (Exception ex)
    {
        ErrLog.LogError(ex, "ManageController.Users_Edit");
    }
}

return Json(new[] { model }.AsQueryable().ToDataSourceResult(request, ModelState));
}

行动4:

代码语言:javascript
复制
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "DM_Admin")] 
public async Task<ActionResult> Users_Delete([DataSourceRequest] DataSourceRequest request, ManageUsersViewModel model)
{
    if (model != null && ModelState.IsValid)
    {
        // format the RolesList to type List<string> for removal  
        List<string> rolesToRemove = getRoleNameList(model);
    try
    {
        // get the user to be deleted by id
        var user = await UserManager.FindByIdAsync(model.Id);

        // remove roles from user in User Db
        var removeRolesResult = await UserManager.RemoveFromRolesAsync(user.Id, rolesToRemove.ToArray());
        if (removeRolesResult.Succeeded)
        {
            // remove user from User Db
            var removeUserResult = await UserManager.DeleteAsync(user);
            if (removeUserResult.Succeeded)
            {
                return RedirectToAction("ManageUsers", new { Message = ManageMessageId.AccountDeleteSuccess });
            }
            AddErrors(removeUserResult);
        }
        else
        {
            AddErrors(removeRolesResult);
        }
    }
    catch (Exception ex)
    {
        ErrLog.LogError(ex, "ManageController.Users_Delete");
    }
}

return Json(new[] { model }.AsQueryable().ToDataSourceResult(request, ModelState));
}

行动5:

代码语言:javascript
复制
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "DM_Admin")] 
public async Task<IdentityResult> AssignRolesToUser(string id, string[] rolesToAssign)
{
    if (rolesToAssign != null)
    {
        try
        {
            // find the user to assign roles to
            var user = await UserManager.FindByIdAsync(id);
            if (user != null)
            {
                // check if the user currently has any roles
                var currentRoles = await UserManager.GetRolesAsync(user.Id);
                var rolesNotExist = rolesToAssign.Except(RoleManager.Roles.Select(x => x.Name)).ToArray();
            if (!(rolesNotExist.Count() > 0))
            {
                // remove current roles from user, if any, in User Db
                var removeRolesResult = await UserManager.RemoveFromRolesAsync(user.Id, currentRoles.ToArray());
                if (!removeRolesResult.Succeeded)
                {
                    AddErrors(removeRolesResult);
                    return removeRolesResult;
                }

                // assign new roles to user in User Db
                var addRolesResult = await UserManager.AddToRolesAsync(user.Id, rolesToAssign);
                if (!addRolesResult.Succeeded)
                {
                    AddErrors(addRolesResult);
                }
                return addRolesResult;
            }
            else
            {
                ModelState.AddModelError("", string.Format("Roles '{0}' do not exist in the system", string.Join(",", rolesNotExist)));
            }
        }
        else
        {
            ModelState.AddModelError("", string.Format("Unable to find user"));
        }
    }
    catch (Exception ex)
    {
        ErrLog.LogError(ex, "ManageController.AssignRolesToUser");
    }
}
else
{
    ModelState.AddModelError("", string.Format("No roles specified"));
}
return null;
}

在创建默认Mvc应用程序时,身份框架与Microsoft如何设置身份框架相同,因此,我不太确定如何重构代码。

我知道这是一个较长的帖子,所以非常感谢您抽出时间阅读它,我希望大家尽快收到您的来信。

**注:我增加了5种行动方法,因为我认为它们可能需要显示出来,以便使整个控制器变薄,同时使人们更好地了解正在发生的事情。但是,请不要觉得有必要为列出的所有行动提供例子。**

太感谢你们了!斯纳沃兹

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-10-03 13:53:27

新开发人员的罪魁祸首是:陷入模式地狱,而不是仅仅担心应用程序。

设计模式只是解决特定问题的推荐方法。足够多的开发人员已经做了足够多的相同事情,在某种程度上遵循了一套公认的最佳实践。然而,在这种情况下经常会丢失的是,设计模式的存在是为了解决特定类型的问题。如果您的应用程序没有这个特殊的问题,就没有必要实现这个特定的模式。在使用类似于实体框架的ORM存储库模式时,您会经常看到这种情况。存储库模式的存在是为了对所有原始SQL代码进行洗牌,使用的数据库直接要求将所有代码都放在整洁的位置上。如果周围没有原始SQL代码,则不需要存储库模式。

此外,应用程序的需求超过了任何“最佳做法”。例如,很少有人会认为不应该在应用程序中实现控制反转和依赖注入。在99.999%的应用程序中,这极大地改进了应用程序。但是,堆栈溢出核心团队根本不使用它。为什么?因为它增加了应用程序的份量。核心团队的唯一责任是使堆栈溢出尽可能具有性能,而在这个特定的应用程序中,依赖项注入不起作用。

所有这些都是为了构建你的应用程序。不要担心每件事都是正确的,或者所有的“最佳实践”都会被遵循。就建它吧。然后,你可以回去重构,当你重构的时候,你会找到机会以更好的方式去做事情。在这一点上,您可以参考各种设计模式作为指导。一开始就试图去担心所有这些事情是一个陷阱,它常常会让你陷入停滞,无法向前迈进。

还有一点要注意:你需要给自己时间和自由,让自己变得有经验。我的意思是,一旦你有了做这些事情的经验,你就会做一些应该如何做的事情,因为它开始成为第二天性。然而,你必须首先达到这一点。当你刚开始的时候,你的代码并不完美,这一点也不丢人。我不知道有哪个开发人员在他们还是新手的时候,面对他们编写的代码时,他们会不寒而栗。当您构建更多的应用程序,控制新的挑战,解决新的问题,等等,您将建立一个知识库,这将使您更容易做正确的事情。给自己点喘息的空间。

票数 7
EN

Stack Overflow用户

发布于 2017-10-03 13:06:23

基本上,MVC是一种表示模式。它曾经/不是设计成解决所有设计问题的灵丹妙药。它只应格式化数据供用户查看。不多也不差。

它只应获取数据,将其传递给呈现引擎(Razor)并创建路由(仅此而已)。其他一切都应该在其他层/模式中。这是"Skinny控制器“的关键所在,因为它们包含零逻辑(请记住表示模式)。这些“其他”模式应该是什么完全取决于你的情况。这个问题没有一个解决办法。

为了从示例中提供一个瘦控制器的示例,它看起来像,类似于

代码语言:javascript
复制
private MyLogicClass _logic;

[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "DM_Admin")] 
public async Task<ActionResult> Users_Delete([DataSourceRequest] DataSourceRequest request, ManageUsersViewModel model)
{
    var model = _logic.DoLogic();
    return View(model);
}

示例中的所有“内容”都应该驻留在一个或多个“逻辑类”中,在上面的示例中是MyLogicClass。您的控制器应该非常愚蠢,只需传递数据。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46545093

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档