Asp.net mvc 通用CRUD控制器和视图

Asp.net mvc 通用CRUD控制器和视图,asp.net-mvc,Asp.net Mvc,我刚刚学习了一些ASP.NET的入门教程,对于如何实现一个简单的CRUD管理应用程序,我有了一个不错的想法 是否有任何常用的模式来实现通用列表/创建/更新/删除操作?必须为每个模型构建脚手架,然后维护所有的添加、编辑和列表视图和控制器,这看起来相当乏味。实施以下通用操作将更加高效且不易出错: /List/Model /Edit/Model/id /Update/Model/id /Delete/Model/id 这可以处理任何模型。我想,我做了一些类似于您在我构建的管理应用程序中所说的事情。基

我刚刚学习了一些ASP.NET的入门教程,对于如何实现一个简单的CRUD管理应用程序,我有了一个不错的想法

是否有任何常用的模式来实现通用列表/创建/更新/删除操作?必须为每个模型构建脚手架,然后维护所有的添加、编辑和列表视图和控制器,这看起来相当乏味。实施以下通用操作将更加高效且不易出错:

/List/Model
/Edit/Model/id
/Update/Model/id
/Delete/Model/id

这可以处理任何模型。

我想,我做了一些类似于您在我构建的管理应用程序中所说的事情。基本上,关键是使用泛型。换句话说,您可以创建如下控制器:

public abstract class AdminController<TEntity> : Controller
    where TEntity : IEntity, class, new()
{
    protected readonly ApplicationDbContext context;

    public virtual ActionResult Index()
    {
        var entities = context.Set<TEntity>()
        return View(entities);
    }

    public virtual ActionResult Create()
    {
        var entity = new TEntity();
        return View(entity);
    }

    [HttpPost]
    public virtual ActionResult Create(TEntity entity)
    {
        if (ModelState.IsValid)
        {
            context.Set<TEntity>().Add(entity);
            context.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(entity);
    }

    ...
}
这可能是您个人控制器所需的全部功能。另外,这里值得注意的是,我将此设置为在您的上下文中使用依赖项注入。您可以随时将构造函数更改为以下内容:

public WidgetController()
{
    this.context = new ApplicationDbContext();
}
public abstract class AdminController<TEntity> : Controller
    where TEntity : IEntity, class, new()
{
    ...

    public virtual ActionResult Create()
    {
        var entity = new TEntity();
        BeforeReturnView();
        return View(entity);
    }

    ...

    protected virtual void BeforeReturnView()
    {
    }

    ...
 public abstract class AdminController<TEntity, TEntityViewModel, TEntityCreateViewModel, TEntityUpdateViewModel>
     where TEntity : IEntity, class, new()
     where TEntityViewModel : class, new()
     ...
但是,我建议您总体上考虑使用依赖注入。此外,为了便于解释,我在这里直接使用上下文,但通常您会在这里使用服务、存储库等

最后,如果您发现需要自定义CRUD操作的某些部分,但不一定是全部,那么您可以始终添加方法作为扩展点。例如,假设您需要填充一个特定实体的选择列表,您可以执行以下操作:

public WidgetController()
{
    this.context = new ApplicationDbContext();
}
public abstract class AdminController<TEntity> : Controller
    where TEntity : IEntity, class, new()
{
    ...

    public virtual ActionResult Create()
    {
        var entity = new TEntity();
        BeforeReturnView();
        return View(entity);
    }

    ...

    protected virtual void BeforeReturnView()
    {
    }

    ...
 public abstract class AdminController<TEntity, TEntityViewModel, TEntityCreateViewModel, TEntityUpdateViewModel>
     where TEntity : IEntity, class, new()
     where TEntityViewModel : class, new()
     ...
公共抽象类AdminController:Controller
其中tenty:entity,class,new()
{
...
公共虚拟操作结果创建()
{
var entity=新的tenty();
BeforeReturnView();
返回视图(实体);
}
...
受保护的虚拟void BeforeReturnView()
{
}
...
然后:

public class WidgetController : AdminController<Widget>
{
    ...

    protected override void BeforeReturnView()
    {
        ViewBag.MySelectList = new List<SelectListItem>
        {
            ...
        };
    }
}
public class WidgetController : AdminController<Widget, WidgetViewModel, WidgetCreateViewModel, WidgetUpdateViewModel>
{
    ...
}
公共类WidgetController:AdminController
{
...
受保护的覆盖在ReturnView()之前无效
{
ViewBag.MySelectList=新列表
{
...
};
}
}
换句话说,您在基本操作方法中有一个钩子,您可以重写它来更改特定的功能,而不必重写整个操作本身

您还可以进一步将其包括在视图模型中,在视图模型中,您可以将通用类定义扩展为:

public WidgetController()
{
    this.context = new ApplicationDbContext();
}
public abstract class AdminController<TEntity> : Controller
    where TEntity : IEntity, class, new()
{
    ...

    public virtual ActionResult Create()
    {
        var entity = new TEntity();
        BeforeReturnView();
        return View(entity);
    }

    ...

    protected virtual void BeforeReturnView()
    {
    }

    ...
 public abstract class AdminController<TEntity, TEntityViewModel, TEntityCreateViewModel, TEntityUpdateViewModel>
     where TEntity : IEntity, class, new()
     where TEntityViewModel : class, new()
     ...
公共抽象类AdminController
其中tenty:entity,class,new()
其中tentyviewmodel:class,new()
...
然后:

public class WidgetController : AdminController<Widget>
{
    ...

    protected override void BeforeReturnView()
    {
        ViewBag.MySelectList = new List<SelectListItem>
        {
            ...
        };
    }
}
public class WidgetController : AdminController<Widget, WidgetViewModel, WidgetCreateViewModel, WidgetUpdateViewModel>
{
    ...
}
公共类WidgetController:AdminController
{
...
}

这完全取决于您的应用程序需要什么。

这篇文章对我认为您正在尝试做的事情进行了很好的讨论,谢谢。我认为不同的人有不同的用例,我从过去的经验和我们为其他平台构建的解决方案中知道,通用解决方案对我们很有效。谢谢,这非常有用。thx Chris,其他几篇文章的扩展很好,我会把它放在手边:-)@Chris,我欠你很多啤酒,因为你用你的精彩答案拯救了我,这也不例外。Ta。我没有看到一个直接的方法来使用
Create
方法中的
Bind
属性。那么这是否仍然足够安全?你对此有什么想法吗创建公共操作结果([Bind(Include=“Id,SkillName,RatingNumber”)]技能)这是一个问题。但是,您可以通过简单地不使用建议使用的
Bind
来避开它。如果您只使用实体上的属性子集,您应该使用视图模型来表示该子集。
Bind
有许多问题。最大的问题是您必须列出所有属性您要编辑的ies(基于实体,可能是一个实体列表)以及所有这些内容作为字符串。现在您需要维护其他内容。添加属性?删除属性?更改属性名称?最好记住更改所有的
Bind
s。