MVC3ߝ ViewModel 和控制器功能:建议的设计模式

发布于 2024-11-06 06:26:02 字数 3181 浏览 0 评论 0原文

我为一个不太可用的呼叫中心应用程序构建了一个简单的基于 MVC3 的票务输入站点,并尝试重构我的原型以更好地遵循设计模式,部分原因是为了使其更易于维护,但主要是作为学习练习。 面向用户的视图是一种由基本用户信息以及允许选择各种资源类型的面板组成的表单。每种资源类型(硬件、软件等)都以相同的方式显示:使用带有添加/删除按钮的双可过滤列表框、一个可选的“理由”文本区域,该文本区域有条件地显示所请求的资源是否需要理由以及一般注释。 我为各个面板构建了以下 ViewModel:

public class RequestableList
{
    // list of requestable items ids requiring justification
    private List<string> _restrictedItems = new List<string>();
    public List<string> RestrictedItems
    {
        get { return _restrictedItems; }
        set { _restrictedItems = value; }
    }

    // the key-value pairs from which to populate available items list
    private Dictionary<string, string> _availableItems = new Dictionary<string, string>();
    public Dictionary<string, string> AvailableItems
    {
        get { return _availableItems; }
        set { _availableItems = value; }
    }

    // item ids requested by user
    private List<string> _requestedItems = new List<string>();
    public List<string> RequestedItems
    {
        get { return _requestedItems; }
        set { _requestedItems = value; }
    }
}

主 ViewModel 然后根据需要由多个 RequestableList 组成:

public class SimpleRequestViewModel
{
    public UserInfo userInfo { get; set; }
    public RequestableList Software {get;set;}
    public RequestableList Hardware {get;set;}
    public RequestableList Access {get;set;}
    public string SoftwareAdditionalInfo { get; set; }
    public string HardwareAdditionalInfo { get; set; }
    public string AccessFileMailShare { get; set; }
    public string AccessAdditionalInfo { get; set; }
    public string SoftwareJustification { get; set; }
    public string HardwareJustification { get; set; }
    public string AccessJustification { get; set; }
    public string Comment { get; set; }
}

我为 SimpleRequestViewModel (及其变体)创建了一个强类型视图,并为 RequestableList 创建了一个强类型 EditorTemplate,用于连接双列表框、过滤和jquery。一切都渲染得很好并且正在工作,但代码目前有味道。

发布到控制器时,如果模型有效,我必须将其转换为可读的文本描述,以便在呼叫中心应用程序中创建新票证。让控制器将转换执行为可读文本感觉不太好,但在尝试设计另一个类来转换视图模型时遇到了障碍。

  1. 仅发布选定的项目值,因此在将请求转换为文本之前,我必须首先查找所提供值的适当文本(描述中需要它们)。控制器是当前唯一有权访问此查找查询的呼叫中心数据模型的对象。
  2. 有 2 个类似的 ViewModel 包含不同的 RequestableList 组合,因此任何翻译人员都必须能够翻译各种组合。一个只有硬件和软件,另一个可能有硬件软件,以及更多的RequestableList。

我考虑过直接在 ViewModel 中覆盖 ToString() 但不喜欢那里的业务逻辑(条件渲染),而且一旦发布,ViewModel 不包含列表框中所选项目的文本,因此需要访问到数据模型。 当前在控制器中处理的发布值到文本的转换闻起来就像在 switch 语句中处理的那样。控制器获取每个发布的 RequestableList 并在构建新的票证描述之前填充原始的“可用”字段。

switch (requestCategory)
{
    case RequestableCategory.Software:
        itemList = sde.GetSoftware();
        break;
    case RequestableCategory.Hardware:
        itemList = sde.GetHardware();
        break;
    case RequestableCategory.Access:
        itemList = sde.GetAccess();
        break;
    case RequestableCategory.Telecom:
        itemList = sde.GetTelecom();
        break;
    default:
        throw new ArgumentException();
}

所以,我的问题是:

  1. 您会推荐哪些模式和技术来执行发布的视图模型到工单描述的翻译?
  2. 当您需要文本和值时,通常如何处理选择框的“仅帖子值”问题?
  3. 我有更好的方法来解决这个问题吗?

再次,我希望这对我来说是一次学习经历,并且如果需要的话我非常愿意提供额外的信息或描述。

I have built a simple MVC3-based ticket entry site for a less-than-usable call center application and am attempting to refactor my prototype to better adhere to design patterns partly to make it more maintainable going forward but mostly as a learning exercise.
The user-facing view is a form consisting of basic user information in addition to a few panels allowing selection of various resource types. Each resource type (hardware, software, etc) is displayed in the same way: using dual, filterable listboxes with add/remove buttons, an optional “justification” textarea that conditionally displays if a requested resource requires justification, and general comments.
I have built the following ViewModel for the individual panels:

public class RequestableList
{
    // list of requestable items ids requiring justification
    private List<string> _restrictedItems = new List<string>();
    public List<string> RestrictedItems
    {
        get { return _restrictedItems; }
        set { _restrictedItems = value; }
    }

    // the key-value pairs from which to populate available items list
    private Dictionary<string, string> _availableItems = new Dictionary<string, string>();
    public Dictionary<string, string> AvailableItems
    {
        get { return _availableItems; }
        set { _availableItems = value; }
    }

    // item ids requested by user
    private List<string> _requestedItems = new List<string>();
    public List<string> RequestedItems
    {
        get { return _requestedItems; }
        set { _requestedItems = value; }
    }
}

The main ViewModel is then comprised of multiple RequestableLists as necessary:

public class SimpleRequestViewModel
{
    public UserInfo userInfo { get; set; }
    public RequestableList Software {get;set;}
    public RequestableList Hardware {get;set;}
    public RequestableList Access {get;set;}
    public string SoftwareAdditionalInfo { get; set; }
    public string HardwareAdditionalInfo { get; set; }
    public string AccessFileMailShare { get; set; }
    public string AccessAdditionalInfo { get; set; }
    public string SoftwareJustification { get; set; }
    public string HardwareJustification { get; set; }
    public string AccessJustification { get; set; }
    public string Comment { get; set; }
}

I have created a strongly typed view for SimpleRequestViewModel (and its variant) and a strongly typed EditorTemplate for RequestableList that wires up the dual listboxes, filtering, and jquery. All renders well and is working but the code currently smells.

When posting to the controller, if the model is valid I must translate it into a readable text description in order to create a new ticket in in the call center app. It doesn’t feel right to have the controller performing that translation into readable text but I run into hurdles when trying to design another class to translate the viewmodels.

  1. Only the selected item values are posted so before translating the request into text I must first lookup the appropriate text for the provided values (they are required in description). The controller is currently the only object that has access to the call center data model for this lookup query.
  2. There are 2 similar ViewModels containing varying combinations of RequestableLists so any translator must be able to translate the various combinations. One has only Hardware and Software, another may have Hardware Software, and a few more RequestableLists.

I considered overriding ToString() directly in the ViewModel but didn’t like that business logic (conditional rendering) there, and again, once posted, the ViewModel doesn’t contain the text for the selected items in the listbox so it would need access to the data model.
The translation of posted values to text as it is currently handled in the controller smells as it’s handled in a switch statement. The controller takes each posted RequestableList and populates the original “Available” fields before it builds the new ticket description.

switch (requestCategory)
{
    case RequestableCategory.Software:
        itemList = sde.GetSoftware();
        break;
    case RequestableCategory.Hardware:
        itemList = sde.GetHardware();
        break;
    case RequestableCategory.Access:
        itemList = sde.GetAccess();
        break;
    case RequestableCategory.Telecom:
        itemList = sde.GetTelecom();
        break;
    default:
        throw new ArgumentException();
}

So, my question(s):

  1. What patterns are techniques would you recommend for performing the posted viewmodel to ticket description translation?
  2. How do you typically handle the “only posts value” issue with select boxes when you need the text as well as the value?
  3. Is there a better way for me to be approaching this problem?

Again, I am hoping this is a learning experience for me and am more than willing to provide additional information or description if needed.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

段念尘 2024-11-13 06:26:02

一些建议:

  1. 将呼叫中心提交的逻辑抽象到它自己的类中。 (从控制器)提供访问呼叫中心数据库所需的任何依赖项。使用重载有不同的方法来处理各种类型的视图模型。据推测,描述来自数据库,因此您可以根据此类中的值从数据库中提取描述。该类还可以负责为显示操作构建视图模型。请注意,使用此模式,类可以通过存储库甚至通过 Web 服务/API 直接与数据库交互。

  2. 如果第二次从数据库查找描述时出现性能问题,请使用实现一些缓存的存储库模式。我怀疑除非您的呼叫中心非常大,否则不会,但这将是优化查询逻辑的地方。存储库可以是控制器传递给提交类的东西。

  3. 如果您不需要在控制器中直接访问数据库,请考虑直接将代理类作为依赖项传递。

它可能看起来像:

private ICallCenterBroker CallCenterBroker { get; set; }

public RequestController( ICallCenterBroker broker )
{
   this.CallCenterBroker = broker;
   // if not using DI, instantiate a new one
   // this.CallCenterBroker = broker ?? new CallCenterBroker( new CallCenterRepository() );
}

[HttpGet]
public ActionResult CreateSimple()
{
    var model = this.CallCenterBroker.CreateSimpleModel( this.User.Identity.Name );
    return View( model );
}


[HttpPost]
public ActionResult CreateSimple( SimpleRequestViewModel request )
{
    if (Model.IsValid)
    {
       var ticket = this.CallCenterBroker.CreateTicket( request );
       // do something with ticket, perhaps create a different model for display?
       this.CallCenterBroker.SubmitTicket( ticket );
       return RedirectToAction( "index" ); // list all requests?
    }
    return View();
}

A few suggestions:

  1. Abstract the logic that does the call center submission into its own class. Provide (from the controller) whatever dependencies it needs to access the call center DB. Have different methods to handle the various types of view models using overloading. Presumably the descriptions come from the DB so you can extract the description from the DB based on the value in this class. This class could also take responsibility for building your view models for the display actions as well. Note that with this pattern the class can interact with the DB directly, through a repository, or even via web services/an API.

  2. Use a repository pattern that implements some caching if performance is an issue in looking up the description from the DB the second time. I suspect it won't be unless your call center is very large, but that would be the place to optimize the query logic. The repository can be the thing that the controller passes to the submission class.

  3. If you don't need to access the DB directly in the controller, consider passing the broker class as a dependency directly.

It might look like:

private ICallCenterBroker CallCenterBroker { get; set; }

public RequestController( ICallCenterBroker broker )
{
   this.CallCenterBroker = broker;
   // if not using DI, instantiate a new one
   // this.CallCenterBroker = broker ?? new CallCenterBroker( new CallCenterRepository() );
}

[HttpGet]
public ActionResult CreateSimple()
{
    var model = this.CallCenterBroker.CreateSimpleModel( this.User.Identity.Name );
    return View( model );
}


[HttpPost]
public ActionResult CreateSimple( SimpleRequestViewModel request )
{
    if (Model.IsValid)
    {
       var ticket = this.CallCenterBroker.CreateTicket( request );
       // do something with ticket, perhaps create a different model for display?
       this.CallCenterBroker.SubmitTicket( ticket );
       return RedirectToAction( "index" ); // list all requests?
    }
    return View();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文