c# - 通用视图和控制器以避免 MVC 中的重复代码
问题描述
我的 MVC 项目中有很多具有相同基本结构的模型。所以,我创建了一个像下面这样的大师班。
public class MasterTemplate
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Description { get; set; }
public DateTime? UpdatedOn { get; set; }
public string UpdatedBy { get; set; }
}
我创建了我所有的模型类,如下所示。
public class Industry : MasterTemplate
{
}
public class Caste : MasterTemplate
{
}
public class Gender : MasterTemplate
{
}
public class Qualification : MasterTemplate
{
}
public class BloodGroup: MasterTemplate
{
}
还有很多这样的。以下是我的 IndustryController 代码。
public class IndustryController : Controller
{
private ApplicationDbContext _context { get; set; }
private string UserId { get; set; }
public IndustryController()
{
_context = new ApplicationDbContext();
UserId = System.Web.HttpContext.Current.User.Identity.GetUserId();
}
public ActionResult Index(int id = 0)
{
Industry data = new Industry();
if (id > 0)
data = _context.Industries.SingleOrDefault(c => c.Id == id);
if (data == null)
data = new Industry();
return View("Industry", data);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Save(Industry data)
{
if (!ModelState.IsValid)
return View("Industry", data);
var record = _context.Industries.Where(c => c.Description.Trim().ToLower() == data.Description.Trim().ToLower() && c.Id != data.Id);
if (record.Count() > 0)
{
ModelState.AddModelError("Duplicate Industry", "Industry already exist");
return View("Industry", data);
}
Industry cm = new Industry();
if (data.Id >= 1)
{
cm = _context.Industries.SingleOrDefault(c => c.Id == data.Id);
cm.Description = data.Description;
cm.UpdatedOn = DateTime.Now;
cm.UpdatedBy = UserId;
}
else
{
cm = data;
_context.Industries.Add(cm);
}
_context.SaveChanges();
return RedirectToAction("Index", new { id = 0 });
}
以下是我的 IndustryView 代码
@model Industry
@{
ViewBag.Title = "Industries";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h3>Industries Management</h3>
<div class="row">
<div class="col-md-4">
@using (@Html.BeginForm("Save", "Industry"))
{
@Html.ValidationSummary("Please correct the following")
@Html.HiddenFor(m => m.Id)
<div class="form-group">
<div>
@Html.LabelFor(m => m.Description)
@Html.TextBoxFor(m => m.Description, new { @class = "form-control", autocomplete = "off" })
@Html.ValidationMessageFor(m => m.Description)
</div>
</div>
@Html.AntiForgeryToken()
<button type="submit" class="btn btn-primary btn-sm">Save</button>
}
</div>
<div class="col-md-8">
<table class="table table-sm" id="mydata">
<thead>
<tr>
<th>
Industries
</th>
<th>
</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
@section scripts
{
@Scripts.Render("~/bundles/jqueryval")
<script>
$(document).ready(function () {
$("#mydata").DataTable({
ajax: {
url: "/api/get/industries",
dataSrc: ""
},
columns: [
{
data: "description"
},
{
data: "id",
render: function (data) {
var url = '@Url.Action("Index", "Industry", new { id = "__data__" })';
return '<a href="' + url.replace('__data__', data) + '">Edit</a>';
}
}
]
});
});
</script>
}
现在我的问题是,我项目中所有模型的控制器和视图代码几乎相似。如上。所以,我想概括它们并创建一个可用于我所有其他模型的控制器和视图。我是泛型新手,尝试了以下代码,但仍然无法弄清楚前进的方向。这对我来说太混乱了。
public interface IMaster
{
int Id { get; set; }
string Description { get; set; }
}
public class GenericController : Controller
{
private ApplicationDbContext _context { get; set; }
private string UserId { get; set; }
public GenericController()
{
_context = new ApplicationDbContext();
UserId = System.Web.HttpContext.Current.User.Identity.GetUserId();
}
public ActionResult Index(int id = 0)
{
IMaster data = null;
if (id > 0)
data = _context.Industries.SingleOrDefault(c => c.Id == id);
if (data == null)
data = new Industry();
return View("Generic", data);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Save(IMaster data)
{
if (!ModelState.IsValid)
return View("Generic", data);
var record = _context.Industries.Where(c => c.Description.Trim().ToLower() == data.Description.Trim().ToLower() && c.Id != data.Id);
if (record.Count() > 0)
{
ModelState.AddModelError("Duplicate Industry", "Industry already exist");
return View("Generic", data);
}
Industry cm = new Industry();
if (data.Id >= 1)
{
cm = _context.Industries.SingleOrDefault(c => c.Id == data.Id);
cm.Description = data.Description;
cm.UpdatedOn = DateTime.Now;
cm.UpdatedBy = UserId;
}
else
{
cm.Id = data.Id;
cm.Description = data.Description;
_context.Industries.Add(cm);
}
_context.SaveChanges();
return RedirectToAction("Index", new { id = 0 });
}
}
有人可以指导我正确的方向吗,需要为我的项目中的所有类似模型创建一个通用控制器和视图。
解决方案
我没有运行它,但我非常有信心,这应该可以解决问题!实际上唯一真正通用的部分是控制器。其他东西只是通常的多态性。谢谢你的灵感。考虑这样的解决方案很有趣。也许我将来会建立类似的东西。
请注意:您将控制器的名称绑定到每个模型的名称。请注意这一点!必须保留一个命名模式,否则您会破坏它。
public class [ModelName]Controller : MasterController<ModelName>
{
}
ajax 端点将以 [PluralName] 的值结束
(在视图中继续阅读以了解我的意思。)
您将需要 MasterTemplate 中的其他属性。理想情况下使其抽象化,这样您就不会忘记在派生类中实现它。这是针对视图标题中的复数名称和视图中的 ajax 调用。
public abstract class MasterTemplate
{
[Key]
public int Id { get; set; }
public abstract string PluralName {get;}
[Required]
[StringLength(255)]
public string Description { get; set; }
public DateTime? UpdatedOn { get; set; }
public string UpdatedBy { get; set; }
}
工业将看起来像这样
public class Industry: MasterTemplate
{
public override string PluralName => "Industries"
}
制作一个真正通用的控制器并从中派生所有其他控制器,例如
public class IndustryController : MasterController<Industry>
{
//done everthing else is in the master :)
}
这里是通用的 MasterController<T>。
public class MasterController<T> : Controller where T : MasterTemplate, new()
{
private ApplicationDbContext _context { get; set; }
private string UserId { get; set; }
public MasterController()
{
_context = new ApplicationDbContext();
UserId = System.Web.HttpContext.Current.User.Identity.GetUserId();
}
public ActionResult Index(int id = 0)
{
T data = (id > 0)
? data = _context.Set<T>().SingleOrDefault(c => c.Id == id) ?? new T()
: new T();
return View("View", data);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Save(T data)
{
if (!ModelState.IsValid)
return View("View", data);
var record = _context.Set<T>().Where(c => c.Description.Trim().ToLowerInvariant() == data.Description.Trim().ToLowerInvariant() && c.Id != data.Id);
if (record.Count() > 0)
{
ModelState.AddModelError($"Duplicate {typeof(T).Name}", $"{typeof(T).Name} already exist");
return View("View", data);
}
if (data.Id >= 1)
{
T cm = _context.Set<T>().SingleOrDefault(c => c.Id == data.Id);
cm.Description = data.Description;
cm.UpdatedOn = DateTime.Now;
cm.UpdatedBy = UserId;
}
else
{
_context.Set<T>().Add(data);
}
_context.SaveChanges();
return RedirectToAction("Index", new { id = 0 });
}
将视图命名为“视图”(或与您在 MasterController 中调用的名称相同)并将其放置在共享文件夹中,以便每个控制器都可以在那里找到它。
@model MasterTemplate
@{
string name = Model.GetType().Name;
ViewBag.Title = name;
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h3>@Model.PluralName Management</h3>
<div class="row">
<div class="col-md-4">
@using (@Html.BeginForm("Save", name))
{
@Html.ValidationSummary("Please correct the following")
@Html.HiddenFor(m => m.Id)
<div class="form-group">
<div>
@Html.LabelFor(m => m.Description)
@Html.TextBoxFor(m => m.Description, new { @class = "form-control", autocomplete = "off" })
@Html.ValidationMessageFor(m => m.Description, $"{name} is required.", new { @class = "text-danger" })
</div>
</div>
@Html.AntiForgeryToken()
<button type="submit" class="btn btn-primary btn-sm">Save</button>
}
</div>
<div class="col-md-8">
<table class="table table-sm" id="mydata">
<thead>
<tr>
<th>
@(name)
</th>
<th>
</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
@section scripts
{
@Scripts.Render("~/bundles/jqueryval")
<script>
$(document).ready(function () {
$("#mydata").DataTable({
ajax: {
url: "/api/get/@(Model.PluralName)",
dataSrc: ""
},
columns: [
{
data: "description"
},
{
data: "id",
render: function (data) {
var url = '@Url.Action("Index", "@(name)", new { id = "__data__" })';
return '<a href="' + url.replace('__data__', data) + '">Edit</a>';
}
}
]
});
});
</script>
}
推荐阅读
- java - 我的应用程序无法在 android 6 上运行,但如果在 android 9-11 上运行则可以运行
- bash - bash while 循环给出语法错误,说缺少'['
- android - 如何使用适用于 Android 和 iOS 的 Xamarin 表单在特定频道上的 youtube 上上传视频?
- javascript - 部署到 github 页面时不显示图像
- c# - MassTransit - 未消耗随机中介响应
- javascript - 单击按钮时如何删除特定元素
- sql - 在sql中计算百分位数和用例
- javascript - 将数据传递给 RDK LightningJS 中的子组件
- video - 即使在关闭模式后视频也会播放
- javascript - jquery mobile draggable() .. [containment] 在调整浏览器大小时没用