English 中文(简体)
MVC 减少重复代码
原标题:MVC Reducing repetitive code

我刚刚开始使用并爱上了MVC的设计模式。

我唯一讨厌的宠物就是 它似乎产生了很多重复代码。例如。

我有一个标准的MVC App和我的DB(模型)在一个项目中,与我的控制器/观点/视觉模型在另一个项目中分离,又与我的测试方法在另一个项目中分离。所有工作都很好。

Models: Now, I have a bunch of nice EF4 classes in my DB project, which I have to use ViewModels for in my real project to access my data. No problem here.

Controllers: However, every controller I have, essentially does the very same thing. It gets and sets the data from the ViewModels so while each controller is different in that it gets only different data, they are all essentially doing the very same job, in the very same way. (I currently have 9, but this could easily explode to well over 50).

例如:

public class Dummy1Controller : Controller
{
    private MyProj.Data.Entities _entities = new Data.Entities();
    private MyProj.Data.Entities2 _coreEntities = new Data.Entities2();

    //GET: /Customers/
    public ActionResult Index()
    {
        if (_entities.table1.Count() == 0) return View();

        var pastObj = _entities.table1.First();
        return View(new Table1ViewModel()
        {
            Id = pastObj.Id,
            FirstName = pastObj.FirstName,
            LastName = pastObj.LastName,
            .
            .
            .
            .
        });
    }
}

public class Dummy2Controller : Controller
{
    private MyProj.Data.Entities _entities = new Data.Entities();
    private MyProj.Data.Entities2 _coreEntities = new Data.Entities2();

    //GET: /Vehicles/
    public ActionResult Index()
    {
        if (_entities.table2.Count() == 0) return View();

        var pastObj = _entities.table2.First();
        return View(new Table1ViewModel()
        {
            RegNo = pastObj.RegNo,
            Make = pastObj.Make,
            Model = pastObj.Model,
            .
            .
            .
            .
        });
    }
}

public class Dummy3Controller : Controller
{
    private MyProj.Data.Entities _entities = new Data.Entities();
    private MyProj.Data.Entities2 _coreEntities = new Data.Entities2();

    //GET: /Invoices/
    public ActionResult Index()
    {
        if (_entities.table3.Count() == 0) return View();

        var pastObj = _entities.table3.First();
        return View(new Table1ViewModel()
        {
            InvNo = pastObj.InvNo,
            Amount = pastObj.Amount,
            Tax = pastObj.Tax,
            .
            .
            .
            .
        });
    }
}

Views: Every view generated from the contollers work great. Execpt, that only thing that changes is the data (fields with labels and text boxes). Once again, they all do the very same job (but with different datasets).

@model MyProject.Web.ViewModels.Table1ViewModel

@{
    ViewBag.Title = "Index";
}

<link href="@Url.Content("~/Content/CSS/GenericDetailStyles.css")" rel="stylesheet" type="text/css" />

<section id="content">
    <div id="table">
        <div>
            <h2>Customer</h2>
        </div>
        <div class="row">
            <div class="left">@Html.LabelFor(x=>x.Id)</div>
            <div class="right">@Html.TextBoxFor(model => model.Id)</div>
        </div>
        <div class="row">
            <div class="left">@Html.LabelFor(x=>x.FirstName)</div>
            <div class="right">@Html.TextBoxFor(model => model.FirstName)</div>
        </div>
        <div class="row">
            <div class="left">@Html.LabelFor(x=>x.LastName)</div>
            <div class="right">@Html.TextBoxFor(model => model.LastName)</div>
        </div>
        .
        .
        .
        .
    </div>
</section>

@{Html.RenderAction("Index", "FooterPartial");}


--------------------------------------------------------------------------------------


@model MyProject.Web.ViewModels.Table2ViewModel

@{
    ViewBag.Title = "Index";
}

<link href="@Url.Content("~/Content/CSS/GenericDetailStyles.css")" rel="stylesheet" type="text/css" />

<section id="content">
    <div id="table">
        <div>
            <h2>Vehicle</h2>
        </div>
        <div class="row">
            <div class="left">@Html.LabelFor(x=>x.RegNo)</div>
            <div class="right">@Html.TextBoxFor(model => model.RegNo)</div>
        </div>
        <div class="row">
            <div class="left">@Html.LabelFor(x=>x.Make)</div>
            <div class="right">@Html.TextBoxFor(model => model.Make)</div>
        </div>
        <div class="row">
            <div class="left">@Html.LabelFor(x=>x.PatientID)</div>
            <div class="right">@Html.TextBoxFor(model => model.Model)</div>
        </div>
        .
        .
        .
        .
    </div>
</section>

@{Html.RenderAction("Index", "FooterPartial");}


--------------------------------------------------------------------------------------


@model MyProject.Web.ViewModels.Table3ViewModel

@{
    ViewBag.Title = "Index";
}

<link href="@Url.Content("~/Content/CSS/GenericDetailStyles.css")" rel="stylesheet" type="text/css" />

<section id="content">
    <div id="table">
        <div>
            <h2>Invoice</h2>
        </div>
        <div class="row">
            <div class="left">@Html.LabelFor(x=>x.InvNo)</div>
            <div class="right">@Html.TextBoxFor(model => model.InvNo)</div>
        </div>
        <div class="row">
            <div class="left">@Html.LabelFor(x=>x.Amount)</div>
            <div class="right">@Html.TextBoxFor(model => model.Amount)</div>
        </div>
        <div class="row">
            <div class="left">@Html.LabelFor(x=>x.Tax)</div>
            <div class="right">@Html.TextBoxFor(model => model.Tax)</div>
        </div>
        .
        .
        .
        .
    </div>
</section>

@{Html.RenderAction("Index", "FooterPartial");}

Problem: I want to make a single controller, and make it dynamic. So that it can read data from different view models. (Why have 9 or 50 controllers esentially doing the same job)

然后,我想对视图也这样做。这样,不同的字段就可以动态生成。 (为什么有9或50个视图都做同样的工作) 如果视图基于控制器, 则该视图应该能够根据其属性而改变 。

我所要做的基本上就是让控制器从 X 或 VM - Y 或 VM - Z 的视图模型中读取它, 它应该能够生成属性, 恢复相关数据, 并将其传递到视图中, 接收后, 它将生成带有标签和文字框的字段 。

我想我要知道是否有办法使用反射来做到这一点。 因为查看模型是基本类别, 具有简单的属性。 人们可能会创建一个基础控制器类, 该类可使用特定查看模型对象的读取方法, 获取其属性, 也可以在相关表格中读取, 并将该表格中的字段与该类属性匹配。 最后, 人们可以从表格中记录下来显示。 这样的话, 可以使用某种剃刀、 c# 或 javascript 来自动生成此视图 。

任何教书,如果有可能或不可以的话,都欢迎。

最佳回答

您可以使用“ http://automapper.codeplex.com/” rel=“ noreferrer” >AutoMapper 来删除模型/实体之间复制值的所有代码 。

另外,考虑使用布局、数据注释属性和模板(与 Html. Displayfor 和 Html. Editorfor 一起)来压缩您的观点 。

http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html>http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html

你可以调查是否有可能建立一个通用的基础控制器类别,该类别将采用模型和实体的类型,并将包含CRUD业务的共同逻辑,但这可能是一个太远的步骤,妨碍你以后的发展。

问题回答

我认为,一个动态控制器可能是一个太远的一步 — — 当你把所有的东西都变成通用的,然后你的观点之一需要比简单的数据库地图更复杂的东西 — — 你是否扩大您的通用控制器来解决这个问题? 可能最终会到“ http://www.thedailywtf.com” rel=“ no follow”这里。

你也许应该看看自动造影机 来消除一些重复性 与你的视觉模型打交道。

< a href=> http://automapper.codeplex.com/" rel="no follow" > http://automapper.codeplex.com/

You can generate an EditFor/Model templates for object, or ur base class, whatever it is, and then just make one view, which will accept your model, its metadata (with the help of mvc metadataproviders), and build the fields dynamicly according.
this post covers hwo it can be done in mvc2, but u can easily adapt this technique to mvc 3 as well..
Im using such a template in a project mi working on, where i have few dozens of different entities, all sharing same look and feel. With the helpe of my own Metadataprovider, which also helps me to get the order of the fields and wheteher they should be visibile in each view, i built one view exactly to show all my entities

我同意其他人的看法, 拥有一个能动控制器来处理您应用程序中的所有模型和视图太过远了 。 还有其他方法可以减少控制器中的代码数量 。 其它答案也提到了 AutoMapper, 这是一个伟大的工具。 AutoMapper 的发明家Jimmy Bogard 还有一个< href=> http://www. viddr. com/v/b568679c' rel = “ nofollow” > great video < / a>, 包括您可以做的其他事情来减少控制器中的代码数量 。

至于视图, 您可以使用编辑器模板来操作您的全部控制器。 您可以创建一个定制的编辑器模板, 它将使用反射来检查模型并相应输入字段。 所有这些都使用“ 模型元数据 ”, 并且有 < href=" http:// bradwilson. typepad. com/blog/ wo10/ aspnet- mvc-2- templates- part-2- modelmetadata. html" rel=“ nofollow” 。 布拉德· 威尔逊在此 < / a> 上有一个不错的文章 。





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签