Общий вид и контроллер, чтобы избежать дублирования кода в MVC - PullRequest
2 голосов
/ 01 апреля 2019

У меня есть много моделей с одинаковой базовой структурой в моем проекте 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 });

        }
    }

Может кто-нибудь направить меня в правильном направлении, нужно создать универсальный контроллер и просмотреть все аналогичные модели в моем проекте.

1 Ответ

1 голос
/ 04 апреля 2019

Я не запускал его, но я вполне уверен, что это должно сработать!На самом деле единственная действительно общая часть - это контроллер.Другое дело просто обычный полиморфизм.И спасибо за вдохновение.Было весело думать о таком решении.Может быть, я построю нечто подобное в будущем.

Предостережение: вы будете привязывать имя ваших контроллеров к названию каждой модели.Просто знайте об этом!Существует схема именования, которую необходимо сохранить, иначе вы ее нарушите.открытый класс [ModelName] Контроллер: MasterController {}Конечные точки 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 .

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>
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...