شروع به کار با DNTFrameworkCore - قسمت 6 - پیادهسازی عملیات CRUD موجودیتها با استفاده از ASP.NET Core MVC
نویسنده: سالار ربال
تاریخ: ۱۳۹۸/۰۳/۱۴ ۸:۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
PM> Install-Package DNTFrameworkCore.Web
public class BlogsController : CrudController<IBlogService, int, BlogModel>
{
public BlogsController(IBlogService service) : base(service)
{
}
protected override string CreatePermissionName => PermissionNames.Blogs_Create;
protected override string EditPermissionName => PermissionNames.Blogs_Edit;
protected override string ViewPermissionName => PermissionNames.Blogs_View;
protected override string DeletePermissionName => PermissionNames.Blogs_Delete;
protected override string ViewName => "_BlogModal";
}
<form asp-action="@(Model.IsNew() ? "Create" : "Edit")" asp-controller="Blogs" asp-modal-form="BlogForm">
<div>
<input type="hidden" name="save-continue" value="true"/>
<input asp-for="RowVersion" type="hidden"/>
<input asp-for="Id" type="hidden"/>
<div>
<div>
<label asp-for="Title"></label>
<input asp-for="Title" autocomplete="off"/>
<span asp-validation-for="Title"></span>
</div>
</div>
<div>
<div>
<label asp-for="Url"></label>
<input asp-for="Url" type="url"/>
<span asp-validation-for="Url"></span>
</div>
</div>
</div>
...
</form>
<div>
<a asp-modal-delete-link asp-model-id="@Model.Id" asp-modal-toggle="false"
asp-controller="Blogs" asp-action="Delete" asp-if="!Model.IsNew()" asp-permission="@PermissionNames.Blogs_Delete"
title="Delete Blog">
<i></i>
</a>
<a title="Refresh Blog" asp-if="!Model.IsNew()" asp-modal-link asp-modal-toggle="false"
asp-controller="Blogs" asp-action="Edit" asp-route-id="@Model.Id">
<i></i>
</a>
<a title="New Blog" asp-modal-link asp-modal-toggle="false"
asp-controller="Blogs" asp-action="Create">
<i></i>
</a>
<button type="button" data-dismiss="modal">
<i></i> Cancel
</button>
<button type="submit">
<i></i> Save Changes
</button>
</div>
public class RoleModalViewModel : RoleModel
{
public IReadOnlyList<LookupItem> PermissionList { get; set; }
} protected override IActionResult RenderView(RoleModel role)
{
var model = _mapper.Map<RoleModalViewModel>(role);
model.PermissionList = ReadPermissionList();
return PartialView(ViewName, model);
}
برای مدیریت سناریوهای Master-Detail به مانند قسمت مدیریت دسترسیها در تب Permissions فرم بالا، امکاناتی در زیرساخت تعبیه شده است ولی پیادهسازی آن را به عنوان یک تمرین و با توجه به سری مطالب «Editing Variable Length Reorderable Collections in ASP.NET MVC» به شما واگذار میکنم.
نکته تکمیلی: برای ارسال اطلاعات اضافی به ویو Index متناظر با یک موجودیت میتوانید متد RenderIndex را به شکل زیر بازنویسی کنید:
protected override IActionResult RenderIndex(IPagedQueryResult<RoleReadModel> model)
{
var indexModel = new RoleIndexViewModel
{
Items = model.Items,
TotalCount = model.TotalCount,
Permissions = ReadPermissionList()
};
return Request.IsAjaxRequest()
? (IActionResult) PartialView(indexModel)
: View(indexModel);
} مدل RoleIndexViewModel استفاده شده در تکه کد بالا نیز به شکل زیر خواهد بود:
public class RoleIndexViewModel : PagedQueryResult<RoleReadModel>
{
public IReadOnlyList<LookupItem> Permissions { get; set; }
}
فرآیند بارگذاری یک پارشالویو در مودال
به عنوان مثال برای استفاده از مودالهای بوت استرپ، ایده کار به این شکل است که یک مودال را به شکل زیر در فایل Layout قرار دهید:
<div class="modal fade" @*tabindex="-1"*@ id="main-modal" data-keyboard="true" data-backdrop="static" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-body">
Loading...
</div>
</div>
</div>
</div> سپس در زمان کلیک بروی یک دکمه Ajaxای، ابتدا main-modal را نمایش داده و بعد از دریافت پارشالویو از سرور، آن را با محتوای modal-content جایگزین میکنیم. به همین دلیل Tag Halperهای مطرح شده در مطلب جاری، callbackهای failure/complete/success متناظر با unobtrusive-ajax را نیز مقداردهی میکنند. برای این منظور نیاز است تا متدهای جاوااسکریپتی زیر نیز در سطح شیء window تعریف شده باشند:
/*---------------------------------- asp-modal-link ---------------------------*/
window.handleModalLinkLoaded = function (data, status, xhr) {
prepareForm('#main-modal.modal form');
};
window.handleModalLinkFailed = function (xhr, status, error) {
//....
};
/*---------------------------------- asp-modal-form ---------------------------*/
window.handleModalFormBegin = function (xhr) {
$('#main-modal a').addClass('disabled');
$('#main-modal button').attr('disabled', 'disabled');
};
window.handleModalFormComplete = function (xhr, status) {
$('#main-modal a').removeClass('disabled');
$('#main-modal button').removeAttr('disabled');
};
window.handleModalFormSucceeded = function (data, status, xhr) {
if (xhr.getResponseHeader('Content-Type') === 'text/html; charset=utf-8') {
prepareForm('#main-modal.modal form');
} else {
hideMainModal();
}
};
window.handleModalFormFailed = function (xhr, status, error, formId) {
if (xhr.status === 400) {
handleBadRequest(xhr, formId);
}
};
public async Task<IActionResult> List(TFilteredPagedQueryModel query)
{
if (!await CheckPermissionAsync(ViewPermissionName)) return Forbid();
query = query ?? Factory<TFilteredPagedQueryModel>.CreateInstance();
var result = await ReadPagedListAsync(query);
var model = new PagedListModel<TReadModel, TFilteredPagedQueryModel>
{
Query = query,
Result = result
};
return PartialView(ListViewName, model);
} //_EntityFormLayout.cshtml
@inherits EntityFormRazorPage<dynamic>
@{
Layout = null;
}
<div class="modal-header">
<h4 class="modal-title" asp-if="IsNew">Create New @EntityDisplayName</h4>
<h4 class="modal-title" asp-if="!IsNew">Edit @EntityDisplayName</h4>
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<form asp-action="@(IsNew ? CreateActionName : EditActionName)" asp-modal-form="@FormId">
<div class="modal-body">
<input type="hidden" name="continue-editing" value="true" asp-permission="@EditPermission"/>
<input asp-for="@Version" type="hidden"/>
<input asp-for="@Id" type="hidden"/>
@RenderBody()
</div>
<div class="modal-footer">
<a class="btn btn-light btn-circle" asp-modal-delete-link asp-model-id="@Id" asp-modal-toggle="false"
asp-action="@DeleteActionName" asp-if="!IsNew" asp-permission="@DeletePermission"
title="Delete Role">
<i class="fa fa-trash text-danger"></i>
</a>
<a class="btn btn-light btn-circle" title="Refresh Role" asp-if="!IsNew" asp-modal-link asp-modal-toggle="false"
asp-action="@EditActionName" asp-route-id="@Id">
<i class="fa fa-repeat"></i>
</a>
<a class="btn btn-light btn-circle mr-auto" title="New Role" asp-modal-link asp-modal-toggle="false"
asp-permission="@CreatePermission"
asp-action="@CreateActionName">
<i class="fa fa-plus"></i>
</a>
<button type="button" class="btn btn-light" data-dismiss="modal">
<i class="fa fa-ban"></i> Cancel
</button>
<button type="submit" class="btn btn-outline-primary">
<i class="fa fa-save"></i> Save Changes
</button>
</div>
</form> public abstract class EntityFormRazorPage<T> : RazorPage<T>
{
protected string EntityName
{
get => ViewData[nameof(EntityName)].ToString();
set => ViewData[nameof(EntityName)] = value;
}
protected string EntityDisplayName
{
get => ViewData[nameof(EntityDisplayName)].ToString();
set => ViewData[nameof(EntityDisplayName)] = value;
}
protected string DeletePermission
{
get => ViewData[nameof(DeletePermission)].ToString();
set => ViewData[nameof(DeletePermission)] = value;
}
protected string CreatePermission
{
get => ViewData[nameof(CreatePermission)].ToString();
set => ViewData[nameof(CreatePermission)] = value;
}
protected string EditPermission
{
get => ViewData[nameof(EditPermission)].ToString();
set => ViewData[nameof(EditPermission)] = value;
}
protected string CreateActionName
{
get => ViewData.TryGetValue(nameof(CreateActionName), out var value) ? value.ToString() : "Create";
set => ViewData[nameof(CreateActionName)] = value;
}
protected string EditActionName
{
get => ViewData.TryGetValue(nameof(EditActionName), out var value) ? value.ToString() : "Edit";
set => ViewData[nameof(EditActionName)] = value;
}
protected string DeleteActionName
{
get => ViewData.TryGetValue(nameof(DeleteActionName), out var value) ? value.ToString() : "Delete";
set => ViewData[nameof(DeleteActionName)] = value;
}
protected string FormId => $"{EntityName}Form";
protected bool IsNew => (Model as dynamic).IsNew();
protected string Id => (Model as dynamic).Id.ToString(CultureInfo.InvariantCulture);
protected byte[] Version => (Model as dynamic).Version;
} //_BlogPartial.cshtml
@inherits EntityFormRazorPage<BlogModel>
@{
Layout = "_EntityFormLayout";
EntityName = "Blog";
DeletePermission = PermissionNames.Blogs_Delete;
CreatePermission = PermissionNames.Blogs_Create;
EditPermission = PermissionNames.Blogs_Edit;
EntityDisplayName = "Blog";
} //_BlogPartial.cshtml
@inherits EntityFormRazorPage<BlogModel>
@{
Layout = "_EntityFormLayout";
...
}
<div class="form-group row">
<div class="col col-md-8">
<label asp-for="Title" class="col-form-label text-md-left"></label>
<input asp-for="Title" autocomplete="off" class="form-control"/>
<span asp-validation-for="Title" class="text-danger"></span>
</div>
</div>
<div class="form-group row">
<div class="col">
<label asp-for="Url" class="col-form-label text-md-left"></label>
<input asp-for="Url" class="form-control" type="url"/>
<span asp-validation-for="Url" class="text-danger"></span>
</div>
</div> //_BlogPartial.cshtml
@inherits EntityFormRazorPage<BlogModel>
@{
Layout = "_EntityFormLayout";
EntityName = "Blog";
DeletePermission = PermissionNames.Blogs_Delete;
CreatePermission = PermissionNames.Blogs_Create;
EditPermission = PermissionNames.Blogs_Edit;
EntityDisplayName = "Blog";
}
@Html.EditorForModel()