asp.net mvc-在工作流中重用页面/控制器

asp.net mvc-在工作流中重用页面/控制器,asp.net,asp.net-mvc,Asp.net,Asp.net Mvc,我有两个工作流: 1) 用户第一次注册。他们看到3个不同的屏幕,他们的基本用户信息,他们的信用卡,和一些额外的个人资料信息。他们以类似向导的方式完成这3个步骤,每次点击“提交”按钮,他们都会离开当前屏幕,进入下一个屏幕 2) 用户已注册。他在导航中有指向这3个独立页面的链接。他可以按任何顺序更新它们。当他点击save时,他不会离开他所在的页面,它只是在顶部显示“信用卡信息已保存…”之类的内容。可能使用ajax,也可能是整页刷新 我想在两个工作流之间重用这3个屏幕的代码,不仅是视图,而且是控制器中

我有两个工作流:

1) 用户第一次注册。他们看到3个不同的屏幕,他们的基本用户信息,他们的信用卡,和一些额外的个人资料信息。他们以类似向导的方式完成这3个步骤,每次点击“提交”按钮,他们都会离开当前屏幕,进入下一个屏幕

2) 用户已注册。他在导航中有指向这3个独立页面的链接。他可以按任何顺序更新它们。当他点击save时,他不会离开他所在的页面,它只是在顶部显示“信用卡信息已保存…”之类的内容。可能使用ajax,也可能是整页刷新

我想在两个工作流之间重用这3个屏幕的代码,不仅是视图,而且是控制器中的代码,但不需要大量的if…then逻辑来确定下一步要去哪里,这取决于它是在向导中首次注册还是更新配置文件的各个部分

有什么想法吗

以下是我尝试重用的代码类型:

    public ActionResult Index()
    {
        var model = this.GetModel();
        return this.View(Views.Index, model);
    }

    public ActionResult Save()
    {
        var model = this.GetModel();
        this.TryUpdateModel(model);
        this.UserAccountRepository.Save(model.CurrentUser);
        return this.RedirectToAction<EditCreditCardController>(c => c.Index());
    }

    private EditCreditCardModel GetModel()
    {
        var model = new EditCreditCardModel();
        model.CCTypes = ModelHelper.PopulateDropDownWithModel(this.CardTypeRepository, this.CurrentUser.CreditCard.CardType);
        model.States = ModelHelper.PopulateDropDownWithModel(this.StateRepository, this.CurrentUser.BillingAddress.State);
        model.CurrentUser = this.CurrentUser;
        return model;
    }
public ActionResult Index()
{
var model=this.GetModel();
返回此.View(Views.Index,model);
}
公共操作结果保存()
{
var model=this.GetModel();
此.TryUpdateModel(model);
这个.UserAccountRepository.Save(model.CurrentUser);
返回这个.RedirectToAction(c=>c.Index());
}
私有EditCreditCardModel GetModel()
{
var模型=新的EditCreditCardModel();
model.CCTypes=ModelHelper.PopulateDropDownWithModel(this.CardTypeRepository,this.CurrentUser.CreditCard.CardType);
model.States=ModelHelper.PopulatedDropDownWithModel(this.StateRepository,this.CurrentUser.BillingAddress.State);
model.CurrentUser=此.CurrentUser;
收益模型;
}

作为一般经验法则,控制器方法应该非常精简,类似于:

public ActionResult SomeAction(int foo, string bar)
{
    MyViewModel model = repository.GetData(foo, bar);
    return View("SomeView", model);
}
所以,当您谈论控制器重用时,您不应该真正需要或使用它。如果重用控制器逻辑似乎很困难,那么这可能意味着您的控制器太胖了,它们做的太多了

至于重用视图,您只需要明智地使用局部视图。我想说得更具体一些,但如果不知道这些视图中的细节,就很难做到这一点。类似于一组用户配置文件字段的内容很容易放在局部视图中


在查看您的编辑之后,我能说的最好的一点是
GetModel()
方法不应该是控制器的一部分,它应该是模型的一部分(即某个地方的存储库或服务),因此您不必继续重写这5行代码

至于其余的,尽管。。。我真的看不出你会从任何进一步的抽象中得到什么。
Index
方法只有两行代码,技术上可以简化为一行,而
Save
方法只有三行(第四行是重定向,每个控制器的重定向可能不同)


我完全赞成抽象和代码重用,但对于两个不同的控制器,尝试做比您看起来已经拥有的更多的事情(基于更新的代码示例)可能是过火了(除了
GetModel
部分,可以移动)。如果有5个或20个控制器都重复此代码,那么我可能实现
CreditCardController
基类或
creditcardheloper
实用程序类。但现在还没有,这将进一步模糊控制器逻辑。

基本上,解决方案非常简单,包括创建一个名为“CommonController”(或XController,或您喜欢的任何控制器)的新抽象控制器类,并将代码放在其中,而不是放在实际控制器中。 正常创建控制器时,使用以下代码:

public class HomeController : Controller
创建一个新控制器,并改用此控制器:

public abstract class CommonController : Controller
注意这里的“abstract”关键字,这是唯一的区别。 现在,在实际控制器中,您需要它们继承此CommonController而不是普通控制器,因此,不要使用:

public class HomeController : Controller
您需要使用:

public class HomeController : CommonController
现在,在这个类中,您将有一个如下设置的void方法,而不是通常的ActionResult方法:

public void CommonController() { 
ViewData["MyVariable"] = value; 
}
至此,CommonController中设置的所有ViewData变量将可用于从控制器返回的视图

总之: 设置一个名为“CommonController”的新控制器,如下所示:

public abstract class CommonController : Controller {
    public void CommonController() {
        // PUT ALL OF YOUR COMMON VARIABLES AND STUFF
        // IN HERE!
        ViewData["MyVariable"] = "BOB THE BUILDER!";
        if(isLoggedIn) {
            ViewData["User"] = "BOB";
        }else{
            ViewData["User"[ = "Unknown User";
        }
        // Etc, etc, etc.
    }
}
然后使现有控制器使用CommonController作为其基本控制器类:

public class HomeController : CommonController {
    public ActionResult Index() {
       return View();
    }
}
在您看来,您应该能够编写,并且“BOB THE BUILDER!”将出现!
}

也许我做错了什么,但我确实发现我的控制器在逻辑上变得更加丰富,即使只是从存储库获取数据、填充下拉列表的selectlist对象等简单的事情。下面是一个例子:
public ActionResult Save(){var model=this.GetModel();this.TryUpdateModel(model);this.UserAccountRepository.Save(model.CurrentUser);返回this.View(Views.Index,model);}私有EditCreditCardModel GetModel(){var model=new EditCreditCardModel();model.CCTypes=ModelHelper.PopulateDropDownWithModel(this.CardTypeRepository,this.CurrentUser.CreditCard.CardType);model.States=ModelHelper.PopulateDropDownWithModel(this.StateRepository,this.CurrentUser.BillingAddress.State);model.CurrentUser=this.CurrentUser;return model;}
@fregas:抱歉,我无法真正理解这一点。。。你可能想把它添加到你的问题中。是的,我考虑过使用继承,但是我有一个基类中所有3个屏幕的全部责任。这似乎不是一个很好的关注点分离…也许不是,但至少您可以将所有的向导逻辑放在一个地方,它可以放在WizardController中—应用程序的其余部分