نکته تکمیلی 1- انتقال قسمتهای مشترک فرمها به یک پارشالویو به عنوان Layout فرمها
//_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>
با توجه به اینکه مدل متناظر با یک ویو در Layout آن نیز قابل دسترس میباشد. بدین ترتیب امکان دسترسی به خصوصیاتی مانند Id و Version یا متد IsNew وجود دارد؛ این خصوصیات در کلاس MasterModel به عنوان پایه مدل/DTO/ویومدلهای ثبت/ویرایش، تعریف شدهاند.
قراداد ما استفاده از همان مدل/DTOها به عنوان ویومدل میباشد که در سناریوهای خاص پیشنهاد شد که از مدلی با نام موجودیت + کلمه ModalViewModel یا FormViewModel استفاده شود. برای انتقال سایر دیتا و متادیتای مورد نیاز برای ساخت فرم میتوان از ViewBag و ViewData پس از امکان تعریف ویومدل پایه (دارای خصوصیات مورد نیاز Layout) که در این طراحی ممکن نیست، استفاده کرد.
2- طراحی یک EntityFormRazorPage پایه
برای رسیدن به کدی با خوانایی بالا کلاسی را به عنوان پایه ویوهای فرمها و پارشالویو EntityFormLayout، به شکل زیر طراحی میکنیم. در اینجا فرم ما یکسری خصوصیات موجود در کلاس پایه خود را مقداردهی خواهد کرد و در ادامه به دلیل ذخیره شدن این اطلاعات در ViewData، در Layout نیز قابل دسترس خواهند بود.
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;
}
3- تنظیم خصوصیات موجود در کلاس پایه
برای این منظور لازم است کلاس پایه را با دایرکتیو inherits مشخص کرده و سپس کار تنظیم Layout و سایر خصوصیات مورد نیاز را انجام دهید:
//_BlogPartial.cshtml
@inherits EntityFormRazorPage<BlogModel>
@{
Layout = "_EntityFormLayout";
EntityName = "Blog";
DeletePermission = PermissionNames.Blogs_Delete;
CreatePermission = PermissionNames.Blogs_Create;
EditPermission = PermissionNames.Blogs_Edit;
EntityDisplayName = "Blog";
}
4 - فرم ثبت و ویرایش متناظر با یک موجودیت
//_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>
و یا اگر از EditorTemplates استفاده میکنید:
//_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()
پ.ن: از همین روش برای ساخت لیستهای یکدست متناظر با موجودیتها نیز میتوان ایده گرفت؛ همچنین امکان تعریف و تنظیم Layoutهای متناسب با شرایط مختلف نیز در این حالت به راحتی ممکن است. در ادامه اگر در سیستم متادیتای غنی متناظر با موجودیتها وجود داشته باشد، چه بسا صرفا با مشخص کردن نام موجودیت به باقی خصوصیات تنظیم شده در کد بالا دسترسی داشته باشیم.