Last active
June 27, 2018 21:47
-
-
Save rockfordlhotka/a8b3253a8ee3b318ce6d30f733529075 to your computer and use it in GitHub Desktop.
In-place edit of list in Razor Pages w/ CSLA
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@page | |
@model WebApplication3.Pages.MyList.CreateModel | |
@{ | |
ViewData["Title"] = "Create"; | |
} | |
<h2>Create</h2> | |
<h4>MyItem</h4> | |
<hr /> | |
<div class="row"> | |
<div class="col-md-4"> | |
<form method="post"> | |
<div asp-validation-summary="ModelOnly" class="text-danger"></div> | |
<div class="form-group"> | |
<label asp-for="MyItem.Name" class="control-label"></label> | |
<input asp-for="MyItem.Name" class="form-control" /> | |
<span asp-validation-for="MyItem.Name" class="text-danger"></span> | |
</div> | |
<div class="form-group"> | |
<label asp-for="MyItem.City" class="control-label"></label> | |
<input asp-for="MyItem.City" class="form-control" /> | |
<span asp-validation-for="MyItem.City" class="text-danger"></span> | |
</div> | |
<div class="form-group"> | |
<input type="submit" value="Create" class="btn btn-default" /> | |
</div> | |
</form> | |
</div> | |
</div> | |
<div> | |
<a asp-page="Index">Back to List</a> | |
</div> | |
@section Scripts { | |
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading.Tasks; | |
using Microsoft.AspNetCore.Mvc; | |
using Microsoft.AspNetCore.Mvc.RazorPages; | |
using Microsoft.AspNetCore.Mvc.Rendering; | |
namespace WebApplication3.Pages.MyList | |
{ | |
public class CreateModel : PageModel | |
{ | |
public async Task<IActionResult> OnGet() | |
{ | |
MyItem = await Csla.DataPortal.CreateAsync<MyItem>(); | |
return Page(); | |
} | |
[BindProperty] | |
public MyItem MyItem { get; set; } | |
public async Task<IActionResult> OnPostAsync() | |
{ | |
if (!ModelState.IsValid) | |
{ | |
return Page(); | |
} | |
MyItem = await MyItem.SaveAsync(); | |
return RedirectToPage("./Index"); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@page | |
@model WebApplication3.Pages.MyList.IndexModel | |
@{ | |
ViewData["Title"] = "Index"; | |
} | |
<h2>Index</h2> | |
<p> | |
<a asp-page="Create">Create New</a> | |
</p> | |
<div class="row"> | |
<div class="col-md-4"> | |
<form method="post"> | |
<table class="table"> | |
<thead> | |
<tr> | |
<th> | |
@Html.DisplayNameFor(model => model.DataList[0].Name) | |
</th> | |
<th> | |
@Html.DisplayNameFor(model => model.DataList[0].City) | |
</th> | |
</tr> | |
</thead> | |
<tbody id="childtable"> | |
@for (int i = 0; i < Model.DataList.Count; i++) | |
{ | |
<tr> | |
<td> | |
<input type="hidden" asp-for="DataList[i].Id" /> | |
<input asp-for="DataList[i].Name" class="form-control" /> | |
<span asp-validation-for="DataList[i].Name" class="text-danger"></span> | |
</td> | |
<td> | |
<input asp-for="DataList[i].City" class="form-control" /> | |
<span asp-validation-for="DataList[i].City" class="text-danger"></span> | |
</td> | |
<td> | |
<input asp-for="DataList[i].Remove" type="checkbox" /> | |
<label class="control-label">Select</label> | |
</td> | |
</tr> | |
} | |
</tbody> | |
</table> | |
<div class="form-group"> | |
<input name="command" type="submit" value="Submit" class="btn btn-default" /> | |
</div> | |
</form> | |
</div> | |
</div> | |
<div> | |
<a asp-page="./Index">Back to List</a> | |
</div> | |
@section Scripts { | |
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Linq; | |
using System.Threading.Tasks; | |
using Microsoft.AspNetCore.Mvc; | |
using Microsoft.AspNetCore.Mvc.RazorPages; | |
namespace WebApplication3.Pages.MyList | |
{ | |
public class IndexModel : PageModel | |
{ | |
[BindProperty] | |
public MyList DataList { get; set; } | |
public async Task OnGetAsync() | |
{ | |
DataList = await Csla.DataPortal.FetchAsync<MyList>(); | |
} | |
public async Task<IActionResult> OnPostAsync() | |
{ | |
foreach (var item in DataList.Where(r => r.Remove).ToList()) | |
DataList.Remove(item); | |
DataList = await DataList.SaveAsync(); | |
return RedirectToPage("Index"); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel.DataAnnotations; | |
using System.Linq; | |
using System.Threading.Tasks; | |
using Csla; | |
namespace WebApplication3.Pages.MyList | |
{ | |
[Serializable] | |
public class MyItem : BusinessBase<MyItem> | |
{ | |
public static readonly PropertyInfo<int> IdProperty = RegisterProperty<int>(c => c.Id); | |
public int Id | |
{ | |
get { return GetProperty(IdProperty); } | |
private set { LoadProperty(IdProperty, value); } | |
} | |
public static readonly PropertyInfo<string> NameProperty = RegisterProperty<string>(c => c.Name); | |
[Required] | |
public string Name | |
{ | |
get { return GetProperty(NameProperty); } | |
set { SetProperty(NameProperty, value); } | |
} | |
public static readonly PropertyInfo<string> CityProperty = RegisterProperty<string>(c => c.City); | |
[Required] | |
public string City | |
{ | |
get { return GetProperty(CityProperty); } | |
set { SetProperty(CityProperty, value); } | |
} | |
public static readonly PropertyInfo<bool> RemoveProperty = RegisterProperty<bool>(c => c.Remove); | |
public bool Remove | |
{ | |
get { return GetProperty(RemoveProperty); } | |
set { SetProperty(RemoveProperty, value); } | |
} | |
private void Child_Fetch(MockDb.DbItem data) | |
{ | |
using (BypassPropertyChecks) | |
{ | |
Id = data.Id; | |
Name = data.Name; | |
City = data.City; | |
} | |
} | |
[RunLocal] | |
protected override void DataPortal_Create() | |
{ | |
base.DataPortal_Create(); | |
} | |
protected override void DataPortal_Insert() | |
{ | |
Child_Insert(); | |
} | |
private void Child_Insert() | |
{ | |
using (BypassPropertyChecks) | |
{ | |
Id = MockDb.Items.Max(r => r.Id) + 1; | |
MockDb.Items.Add(new MockDb.DbItem { Id = Id, Name = Name, City = City }); | |
} | |
} | |
private void Child_Update() | |
{ | |
using (BypassPropertyChecks) | |
{ | |
var existing = MockDb.Items.Where(i => i.Id == Id).FirstOrDefault(); | |
if (existing == null) | |
throw new InvalidOperationException("No existing item in database {Id}"); | |
existing.Id = Id; | |
existing.Name = Name; | |
existing.City = City; | |
} | |
} | |
private void Child_DeleteSelf() | |
{ | |
var existing = MockDb.Items.Where(i => i.Id == Id).FirstOrDefault(); | |
if (existing == null) | |
throw new InvalidOperationException("No existing item in database {Id}"); | |
MockDb.Items.Remove(existing); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading.Tasks; | |
using Csla; | |
namespace WebApplication3.Pages.MyList | |
{ | |
public static class MockDb | |
{ | |
public static List<DbItem> Items = new List<DbItem> | |
{ | |
new DbItem { Id = 1, Name = "Rocky", City = "Aitkin"}, | |
new DbItem { Id = 3, Name = "Teresa", City = "Bemidji"}, | |
new DbItem { Id = 2, Name = "Tim", City = "St. Paul"} | |
}; | |
public class DbItem | |
{ | |
public int Id { get; set; } | |
public string Name { get; set; } | |
public string City { get; set; } | |
} | |
} | |
[Serializable] | |
public class MyList : BusinessListBase<MyList, MyItem> | |
{ | |
private void DataPortal_Fetch() | |
{ | |
AddRange(MockDb.Items.Select(i => DataPortal.FetchChild<MyItem>(i))); | |
} | |
protected override void DataPortal_Update() | |
{ | |
Child_Update(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// in startup.cs the ConfigureServices method needs to use CslaModelBinderProvider | |
services.AddMvc(config => | |
config.ModelBinderProviders.Insert(0, new Csla.Web.Mvc.CslaModelBinderProvider(CreateInstanceAsync, CreateChild)) | |
).SetCompatibilityVersion(CompatibilityVersion.Version_2_1); | |
// somewhere we also need to provide the CreateInstanceAsync and CreateChild implementations | |
// one location is in startup.cs | |
/// <summary> | |
/// Create an instance of a root object when requested | |
/// by CslaModelBinder | |
/// </summary> | |
/// <param name="type">Type of root object to create</param> | |
private async Task<object> CreateInstanceAsync(Type type) | |
{ | |
object result; | |
if (type.Equals(typeof(Pages.MyList.MyList))) | |
result = await Csla.DataPortal.FetchAsync<Pages.MyList.MyList>(); | |
else | |
result = Csla.Reflection.MethodCaller.CreateInstance(type); | |
return result; | |
} | |
/// <summary> | |
/// Create an instance of a child object when requested | |
/// by CslaModelBinder | |
/// </summary> | |
/// <param name="parent">Reference to parent object</param> | |
/// <param name="type">Type of child object to create</param> | |
/// <param name="values">Values that CslaModelBinder will load into the new child object</param> | |
/// <returns></returns> | |
private object CreateChild(System.Collections.IList parent, Type type, Dictionary<string, string> values) | |
{ | |
object result = null; | |
if (type.Equals(typeof(Pages.MyList.MyItem))) | |
{ | |
var list = (Pages.MyList.MyList)parent; | |
var idText = values["Id"]; | |
int id = string.IsNullOrWhiteSpace(idText) ? -1 : int.Parse(values["Id"]); | |
result = list.Where(r => r.Id == id).FirstOrDefault(); | |
if (result == null) | |
result = Csla.Reflection.MethodCaller.CreateInstance(type); | |
} | |
else | |
{ | |
result = Csla.Reflection.MethodCaller.CreateInstance(type); | |
} | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment