WebApi.HAL Collection Representation Issues - asp.net-web-api
I created Web API project for a maze game service. It uses WebApi.Hal for returning hal+jsonand hal+xml media types. It works for the most part – except for the following issues.
Though page is 2 in the request, it returns all the cells for all pages. How to correct it?
In hal+json, there are “links” to all cells in the self itself, in addition to embedded cells. In hal+xml, there is only embedded cells. Why is the difference? Which is correct?
There is a link added as rel="page" href="~/api/cells/page/{page}" . Why is the rel coming as “page” though I have written following code
`public static Link GetCells { get { return new Link("cell","~/api/cells/page/{page}"); } }
There is a link added with searchTerm .How to utilize it in the client? I could not find any useful example.
All the cells are coming as embedded. Is it the right way for HAL collection? Or should it be links onl?
Request: http://localhost:51910/api/cells/page/2
application/hal+xml
<?xml version="1.0" encoding="utf-8"?>
<resource rel="" href="~/api/cells/page/2">
<link rel="prev" href="~/api/cells/page/1" />
<link rel="next" href="~/api/cells/page/3" />
<link rel="page" href="~/api/cells/page/{page}" />
<link rel="page" href="~/api/cells{?searchTerm,page}" />
<TotalResults>6</TotalResults>
<TotalPages>3</TotalPages>
<Page>2</Page>
<resource rel="self" href="~/api/cells/00">
<link rel="left" href="~/api/cells/10" />
<link rel="left" href="~/api/cells/01" />
<CellID>00</CellID>
<IsExit>False</IsExit>
</resource>
<resource rel="self" href="~/api/cells/10">
<link rel="down" href="~/api/cells/00" />
<link rel="down" href="~/api/cells/20" />
<CellID>10</CellID>
<IsExit>False</IsExit>
</resource>
<resource rel="self" href="~/api/cells/20">
<link rel="left" href="~/api/cells/10" />
<link rel="right" href="~/api/cells/21" />
<CellID>20</CellID>
<IsExit>False</IsExit>
</resource>
<resource rel="self" href="~/api/cells/01">
<link rel="down" href="~/api/cells/00" />
<link rel="left" href="~/api/cells/11" />
<CellID>01</CellID>
<IsExit>False</IsExit>
</resource>
<resource rel="self" href="~/api/cells/11">
<link rel="left" href="~/api/cells/01" />
<link rel="right" href="~/api/cells/21" />
<CellID>11</CellID>
<IsExit>False</IsExit>
</resource>
<resource rel="self" href="~/api/cells/21">
<link rel="down" href="~/api/cells/20" />
<link rel="left" href="~/api/cells/11" />
<CellID>21</CellID>
<IsExit>False</IsExit>
</resource>
</resource>
application/hal+json
Controller
public class CellsController : ApiController
{
//Get all cells in the maze
[HttpGet]
[Route("api/cells")]
public CellListRep Get()
{
Maze m = new Maze();
int page = 1;
int totalPages = 1;
List<CellRepresentation> cellRepresentations = GetAllCellRepresentation(m);
int totalCells = cellRepresentations.Count;
return new CellListRep(cellRepresentations, totalCells, totalPages, page, LinkTemplates.CellLinks.GetCells);
}
//Get paged list
[HttpGet]
[Route("api/cells/page/{page}")]
public CellListRep Get(int page)
{
Maze m = new Maze();
List<CellRepresentation> cellRepresentations = GetAllCellRepresentation(m);
int totalCells = cellRepresentations.Count;
int totalPages = cellRepresentations.Count / 2;
return new CellListRep(cellRepresentations, totalCells, totalPages, page, LinkTemplates.CellLinks.GetCells);
}
//Get specific cell
[HttpGet]
[Route("api/cells/{id}")]
public CellRepresentation Get(string id)
{
Maze m = new Maze();
Cell c = m.GetSpecificCell(id);
List<Cell> possibleLists = m.GetPossibleRelatedCells(c);
CellRepresentation beerRep = new CellRepresentation(c, possibleLists);
return beerRep;
}
private List<CellRepresentation> GetAllCellRepresentation(Maze m)
{
List<CellRepresentation> cellRepresentations = new List<CellRepresentation>();
List<Cell> cells = m.GetAllCells();
foreach (Cell c in cells)
{
List<Cell> possibleLists = m.GetPossibleRelatedCells(c);
CellRepresentation beerRep = new CellRepresentation(c, possibleLists);
cellRepresentations.Add(beerRep);
}
return cellRepresentations;
}
}
Representations and Links
public static class LinkTemplates
{
public static class CellLinks
{
public static Link CellEntry { get { return new Link("self", "~/api/cells/{id}"); } }
public static Link UpLink { get { return new Link("up", "~/api/cells/{id}"); } }
public static Link RightLink { get { return new Link("right", "~/api/cells/{id}"); } }
public static Link DownLink { get { return new Link("down", "~/api/cells/{id}"); } }
public static Link LeftLink { get { return new Link("left", "~/api/cells/{id}"); } }
public static Link GetCells { get { return new Link("cell", "~/api/cells/page/{page}"); } }
public static Link SearchCells { get { return new Link("page", "~/api/cells{?searchTerm,page}"); } }
}
}
public class CellRepresentation : WebApi.Hal.Representation
{
Cell theCell;
List<Cell> possibleMoveCells;
public String CellID
{
get
{
return theCell.CellID ;
}
}
public bool IsExit
{
get
{
return theCell.IsExtCell;
}
}
public CellRepresentation(Cell c, List<Cell> possibleMoveCells )
{
theCell = c;
//_cellIDVal = c.CellID;
this.possibleMoveCells = possibleMoveCells;
}
public override string Rel
{
get { return LinkTemplates.CellLinks.CellEntry.Rel; }
set { }
}
public override string Href
{
get { return LinkTemplates.CellLinks.CellEntry.CreateLink(new { id = theCell.CellID }).Href; }
set { }
}
protected override void CreateHypermedia()
{
foreach (Cell relatedCell in possibleMoveCells)
{
if (relatedCell.RelativeName == "Up")
{
Links.Add(LinkTemplates.CellLinks.UpLink.CreateLink(new { id = relatedCell.CellID }));
}
if (relatedCell.RelativeName == "Right")
{
Links.Add(LinkTemplates.CellLinks.RightLink.CreateLink(new { id = relatedCell.CellID }));
}
if (relatedCell.RelativeName == "Down")
{
Links.Add(LinkTemplates.CellLinks.DownLink.CreateLink(new { id = relatedCell.CellID }));
}
if (relatedCell.RelativeName == "Left")
{
Links.Add(LinkTemplates.CellLinks.LeftLink.CreateLink(new { id = relatedCell.CellID }));
}
}
}
}
public class CellListRep : PagedRepresentationList<CellRepresentation>
{
public CellListRep(IList<CellRepresentation> beers, int totalResults, int totalPages, int page, Link uriTemplate) :
base(beers, totalResults, totalPages, page, uriTemplate, null)
{ }
public CellListRep(IList<CellRepresentation> beers, int totalResults, int totalPages, int page, Link uriTemplate,
object uriTemplateSubstitutionParams) :
base(beers, totalResults, totalPages, page, uriTemplate, uriTemplateSubstitutionParams)
{ }
protected override void CreateHypermedia()
{
base.CreateHypermedia();
var search = LinkTemplates.CellLinks.SearchCells;
if (Links.Count(l => l.Rel == search.Rel && l.Href == search.Href) == 0)
{
Links.Add(LinkTemplates.CellLinks.SearchCells);
}
}
}
public abstract class PagedRepresentationList<TRepresentation> : SimpleListRepresentation<TRepresentation> where TRepresentation : Representation
{
readonly Link uriTemplate;
protected PagedRepresentationList(IList<TRepresentation> res, int totalResults, int totalPages, int page, Link uriTemplate, object uriTemplateSubstitutionParams)
: base(res)
{
this.uriTemplate = uriTemplate;
TotalResults = totalResults;
TotalPages = totalPages;
Page = page;
UriTemplateSubstitutionParams = uriTemplateSubstitutionParams;
}
public int TotalResults { get; set; }
public int TotalPages { get; set; }
public int Page { get; set; }
protected object UriTemplateSubstitutionParams;
protected override void CreateHypermedia()
{
var prms = new List<object> { new { page = Page } };
if (UriTemplateSubstitutionParams != null)
prms.Add(UriTemplateSubstitutionParams);
Href = Href ?? uriTemplate.CreateLink(prms.ToArray()).Href;
Links.Add(new Link { Href = Href, Rel = "self" });
if (Page > 1)
{
var item = UriTemplateSubstitutionParams == null
? uriTemplate.CreateLink("prev", new { page = Page - 1 })
: uriTemplate.CreateLink("prev", UriTemplateSubstitutionParams, new { page = Page - 1 }); // page overrides UriTemplateSubstitutionParams
Links.Add(item);
}
if (Page < TotalPages)
{
var link = UriTemplateSubstitutionParams == null // kbr
? uriTemplate.CreateLink("next", new { page = Page + 1 })
: uriTemplate.CreateLink("next", UriTemplateSubstitutionParams, new { page = Page + 1 }); // page overrides UriTemplateSubstitutionParams
Links.Add(link);
}
Links.Add(new Link("page", uriTemplate.Href));
}
}
Business Classes
public class Cell
{
public int XVal { get; set; }
public int YVal { get; set; }
public bool TopIsWall { get; set; }
public bool RightIsWall { get; set; }
public bool BottomIsWall { get; set; }
public bool LeftIsWall { get; set; }
public bool IsStartCell { get; set; }
public bool IsExtCell { get; set; }
public string RelativeName { get; set; } //Top, Right, Etc.
public string CellID
{
get
{
string characterID = XVal.ToString() + YVal.ToString();
return characterID; //Example 10
}
}
}
public class Maze
{
List<Cell> cells;
public Maze()
{
cells = CreateCells();
}
public Cell GetFirtCell()
{
Cell firstCell = null;
foreach (Cell c in cells)
{
if(c.IsStartCell )
{
firstCell = c;
break;
}
}
return firstCell;
}
public Cell GetSpecificCell(string cellID)
{
Cell theCell = null;
foreach (Cell c in cells)
{
if (c.CellID == cellID)
{
theCell = c;
break;
}
}
return theCell;
}
public List<Cell> GetAllCells()
{
return cells;
}
public List<Cell> GetPossibleRelatedCells(Cell inputCell)
{
List<Cell> possibleCells = new List<Cell>();
foreach (Cell c in cells)
{
if (c.YVal == 2 && c.XVal == 3)
{
int test = 0;
}
if (c.XVal == inputCell.XVal-1 && c.RightIsWall == false && c.YVal== inputCell.YVal )
{
//Go left from the input cell
c.RelativeName = "Left";
possibleCells.Add(c);
}
else if (c.XVal == inputCell.XVal + 1 && c.LeftIsWall == false && c.YVal == inputCell.YVal )
{
//Go right from the input cell
c.RelativeName = "Right";
possibleCells.Add(c);
}
else if (c.YVal == inputCell.YVal - 1 && c.TopIsWall == false && c.XVal == inputCell.XVal )
{
//Go down from the input cell
c.RelativeName = "Down";
possibleCells.Add(c);
}
else if (c.YVal == inputCell.YVal + 1 && c.BottomIsWall == false && c.XVal == inputCell.XVal)
{
//Go up from the input cell
c.RelativeName = "Up";
possibleCells.Add(c);
}
}
return possibleCells;
}
public List<Cell> CreateCells()
{
List<Cell> cells = new List<Cell>();
Cell cell1 = new Cell
{
XVal = 0,YVal = 0,TopIsWall = false,RightIsWall = false,BottomIsWall = true,LeftIsWall = true,
RelativeName="Self"
};
Cell cell2 = new Cell
{
XVal = 1,YVal = 0,TopIsWall = true,RightIsWall = false,BottomIsWall = false,LeftIsWall = false,
IsStartCell = true, //--Start
RelativeName="Self"
};
Cell cell3 = new Cell
{
XVal = 2,YVal = 0,TopIsWall = false,RightIsWall = false,BottomIsWall = true,LeftIsWall = false,
RelativeName="Self"
};
Cell cell5 = new Cell
{
XVal = 0,YVal = 1,TopIsWall = true,RightIsWall = false,BottomIsWall = false,LeftIsWall = true,
RelativeName = "Self"
};
Cell cell7 = new Cell
{
XVal = 1,YVal = 1,TopIsWall = true,RightIsWall = false,BottomIsWall = true,LeftIsWall = false,
RelativeName = "Self"
};
Cell cell8 = new Cell
{
XVal = 2,YVal = 1,TopIsWall = false,RightIsWall = true,BottomIsWall = false,LeftIsWall = false,
RelativeName = "Self"
};
cells.Add(cell1);
cells.Add(cell2);
cells.Add(cell3);
cells.Add(cell5);
cells.Add(cell7);
cells.Add(cell8);
return cells;
}
}
Related
how to show a alert if table is empty?
I want to show a alert if table is empty, problem is that i have to click twice before he is hitting the else statement to show my alert. I use a overlay to show the devices. I tried OnafterrenderAsync, OnInitializedAsync, OnParameterSetAsync If the api call gets devices than there is no problem, the table is loading but if there is no data in the table he doesn't go to the else statement to show my mudalert <PageTitle>#AccountResource.DevicesLinkLabel</PageTitle> #if (isLoading) { } else { #if (!isShowing) { <MudTable T="DeviceModel" ServerData="#(new Func<TableState, Task<TableData<DeviceModel>>>(LoadData))" Hover="true" Breakpoint="Breakpoint.Sm" Dense="true" #ref="table"> <HeaderContent> <MudTh>#AccountResource.DevicesLinkLabel</MudTh> <MudTh>#SharedResource.Type</MudTh> <MudTh>#SharedResource.Version</MudTh> <MudTh>#SharedResource.VersionAppNumber</MudTh> </HeaderContent> <RowTemplate> <MudTd DataLabel="DeviceName">#context.DisplayName</MudTd> <MudTd DataLabel="DeviceType">#context.Type</MudTd> <MudTd DataLabel="DeviceVersion">#context.Version</MudTd> <MudTd DataLabel="DeviceVersionAppNumber">#context.VersionAppNumber</MudTd> </RowTemplate> <PagerContent> <MudTablePager /> </PagerContent> </MudTable> } else { <MudAlert Severity="MudBlazor.Severity.Warning">#SharedResource.NothingToShow</MudAlert> } } #code { [Parameter] public long UserId { get; set; } [Parameter] public long OrganisationId { get; set; } [Parameter] public EventCallback<ModelBase> ShowResponseInToast { get; set; } private MudTable<DeviceModel>? table; private bool isLoading = true; private bool isShowing; protected override async Task OnParametersSetAsync() { try { if (table != null) { //table.CurrentPage = 0;s await table.ReloadServerData(); } } finally { isLoading = false; } } private async Task<TableData<DeviceModel>> LoadData(TableState state) { var request = new GetDeviceRequest { OrganisationId = OrganisationId, UserId = UserId, Page = state.Page, PageSize = state.PageSize, }; var response = await DeviceManagerClient.GetDeviceResponseAsync(request); if (table?.Items?.Any() == true) { isShowing = false; return new TableData<DeviceModel> { Items = response.Results, TotalItems = response.TotalCount }; } else { isShowing = true; return new TableData<DeviceModel> { Items = response.Results, }; } } }
Permission Contacts in Xamarin Forms iOS
I met an error display when I tried to access user contact to fetch all contacts: The splash screen hide the permission dialog. Did anyone meet this error before? Interface: public interface IUserContactsService { List<PhoneContactInfo> GetAllPhoneContacts(IEnumerable<int> filterIds = null); } UserContactService.cs: [assembly: Dependency(typeof(UserContactService))] namespace Test.iOS { public class PhoneContact { public string FirstName { get; set; } public string LastName { get; set; } public string PhoneNumber { get; set; } public string Name { get => $"{FirstName} {LastName}"; } } public class UserContactService : IUserContactsService { string phoneNumber(string number) { string callNumber = number; int i = 0; while (i < callNumber.Length) { if (callNumber[i] == ' ' || callNumber[i] == 160 || callNumber[i] == '-') callNumber = callNumber.Remove(i, 1); else i++; } return callNumber; } public List<PhoneContactInfo> GetAllPhoneContacts(IEnumerable<int> filterIds = null) {var keysTOFetch = new[] { CNContactKey.GivenName, CNContactKey.FamilyName, CNContactKey.EmailAddresses }; NSError error; CNContact[] contactList; var ContainerId = new CNContactStore().DefaultContainerIdentifier; using (var predicate = CNContact.GetPredicateForContactsInContainer(ContainerId)) using (var store = new CNContactStore()) { contactList = store.GetUnifiedContacts(predicate, keysTOFetch, out error); } var contacts = new List<PhoneContactInfo>(); foreach (var item in contactList) { if (null != item && null != item.EmailAddresses) { contacts.Add(new PhoneContactInfo { contactName = item.GivenName, contactNumber = item.PhoneNumbers.ToString() }); } } return contacts; } }
Here is my solution: public List<PhoneContactInfo> GetAllPhoneContacts (IEnumerable<int> filterIds = null) { // if the app was not authorized then we need to ask permission if (ABAddressBook.GetAuthorizationStatus() == ABAuthorizationStatus.Authorized) { GetContacts(); } else Console.WriteLine("Error"); }
AutomationPeer.GetChildrenCore () only reports first child to VisualStudio.TestTools
I'm not able to override GetChildrenCore correctly. I use this for a Canvas to get information about it's children (Line, Rectangle). The output correctly indicates the first child but misses the second. Even though the Canvas already contains both. Custom Canvas Custom Line Childs of Canvas parent: 2 Instead it should be like this: Custom Canvas Custom Line Childs of Canvas parent: 2 Custom Rectangle Childs of Canvas parent: 2 App side side: public class ElementAP : FrameworkElementAutomationPeer { private FrameworkElement Owner = null; private Int32 Count = 0; public ElementAP(FrameworkElement owner, Int32 count) : base (owner) { Owner = owner; Count = count; } protected override AutomationControlType GetAutomationControlTypeCore() { return AutomationControlType.Custom; } protected override string GetClassNameCore() { return $"{Owner.GetType().Name} Childs of Canvas parent: {Count}"; } } public class CanvasAP : FrameworkElementAutomationPeer { public CanvasAP(Windows.UI.Xaml.Controls.Canvas owner) : base(owner) { } protected override AutomationControlType GetAutomationControlTypeCore() { return AutomationControlType.Custom; } protected override string GetClassNameCore() { return "Canvas"; } protected override IList<AutomationPeer> GetChildrenCore() { var owner = (Windows.UI.Xaml.Controls.Canvas)Owner; var list = new List<AutomationPeer> (); foreach (var child in owner.Children) { var peer = new ElementAP(child as FrameworkElement, owner.Children.Count); list.Add(peer); } return list; } } UI Testing side: private static string WalkTree(UITestControl element, Int32 level = 0) { var children = element.GetChildren(); var str = ""; foreach (var c in children) { str += GetElementString(c, level); str += WalkTree(c, level + 1); } return str; } private static string GetElementString(UITestControl element, Int32 level = 0) { var xaml = element as XamlControl; var str = ""; for (var i = 0; i < level; i++) str += " "; str += $"{element.ControlType} {element.ClassName} {element.Name} {xaml?.AutomationId ?? ""}\n"; return str; }
I finally found an answer. When using a cache for the children`s AutomationPeers it works perfectly. public class ElementAP : FrameworkElementAutomationPeer { public UIElement Element { get { return Owner; } } public ElementAP(FrameworkElement owner) : base(owner) { } protected override AutomationControlType GetAutomationControlTypeCore() { return AutomationControlType.Custom; } protected override string GetClassNameCore() { return Owner.GetType().Name; } } public class CanvasAP : FrameworkElementAutomationPeer { private List<ElementAP> _cachedAutomationPeers = new List<ElementAP>(); public CanvasAP(Windows.UI.Xaml.Controls.Canvas owner) : base(owner) { } protected override AutomationControlType GetAutomationControlTypeCore() { return AutomationControlType.Custom; } protected override string GetClassNameCore() { return "Canvas"; } protected override IList<AutomationPeer> GetChildrenCore() { var owner = (Windows.UI.Xaml.Controls.Canvas)Owner; if (owner.Children.All(c => c is CanvasA)) return base.GetChildrenCore(); var list = new List<ElementAP>(); foreach (var child in owner.Children) { var peer = _cachedAutomationPeers.FirstOrDefault(p => p.Element == child) ?? new ElementAP(child as FrameworkElement); list.Add(peer); } _cachedAutomationPeers = list; return list.Cast<AutomationPeer>().ToList(); } }
Click an Item -hold- and swipe to an other site
If an object is clicked, the next page should not be called immediately. But the click should remain on the object until you scroll through a wipe to the next page. How can it hold the click command on an Item? How can it swipe from the clicked Item to an other Page? Update Click one item > OnHold> swipe from the holded item to the left and right. This is the actual behavior: private int index = -1; break; } return true; } }
To highlight the item when it is clicked, you can set background color to the item's view, to perform a swipe gesture for each item, I think you will need to implement IOnTouchListener for each item. Here I created an adapter to implement this feature: public class LVAdapter : BaseAdapter<ListItemModel>, View.IOnTouchListener { private List<ListItemModel> items = new List<ListItemModel>(); private Activity context; private int index = -1; public enum SwipeAction { LR, // Left to Right RL, // Right to Left TB, // Top to bottom BT, // Bottom to Top None // when no action was detected } private int MIN_DISTANCE = 100; private float downX, downY, upX, upY; private SwipeAction maction = SwipeAction.None; public LVAdapter(Activity context, List<ListItemModel> items) : base() { this.context = context; this.items = items; } public override ListItemModel this[int position] { get { return items[position]; } } public override int Count { get { return items.Count; } } public override long GetItemId(int position) { return position; } private void SetSelectedItem(int position) { index = position; NotifyDataSetChanged(); } private class MyViewHolder : Java.Lang.Object { public TextView Name { get; set; } public TextView Description { get; set; } public int index { get; set; } } public override View GetView(int position, View convertView, ViewGroup parent) { MyViewHolder holder = null; var view = convertView; if (view != null) holder = view.Tag as MyViewHolder; if (holder == null) { holder = new MyViewHolder(); view = context.LayoutInflater.Inflate(Resource.Layout.ItemCell, null); holder.Name = view.FindViewById<TextView>(Resource.Id.nametxt); holder.Description = view.FindViewById<TextView>(Resource.Id.detailtxt); holder.index = position; view.Tag = holder; } holder.Name.Text = items[position].Name; holder.Description.Text = items[position].Description; if (index != -1 && position == index) { holder.Name.SetBackgroundColor(Android.Graphics.Color.Red); holder.Description.SetBackgroundColor(Android.Graphics.Color.Pink); } else { holder.Name.SetBackgroundColor(Android.Graphics.Color.RoyalBlue); holder.Description.SetBackgroundColor(Android.Graphics.Color.SeaGreen); } view.SetOnTouchListener(this); return view; } public bool OnTouch(View v, MotionEvent e) { switch (e.Action) { case MotionEventActions.Down: downX = e.GetX(); downY = e.GetY(); maction = SwipeAction.None; break; case MotionEventActions.Move: upX = e.GetX(); upY = e.GetY(); var deltaX = downX - upX; var deltaY = downY - upY; if (Math.Abs(deltaX) > MIN_DISTANCE) { if (deltaX < 0) { maction = SwipeAction.LR; } else if (deltaX > 0) { maction = SwipeAction.RL; } return true; } else if (Math.Abs(deltaY) > MIN_DISTANCE) { if (deltaY < 0) { maction = SwipeAction.TB; } else if (deltaY > 0) { maction = SwipeAction.BT; } return false; } break; case MotionEventActions.Up: var holder = v.Tag as MyViewHolder; if (maction == SwipeAction.None) { SetSelectedItem(holder.index); } else if (maction == SwipeAction.LR | maction == SwipeAction.RL) { if (holder.index == index) context.StartActivity(typeof(Activity1)); } break; } return true; } } The ListItemModel is quite simple by my side: public class ListItemModel { public string Name { get; set; } public string Description { get; set; } } You can try to modify the model and holder as you need.
Generate list from treeitem using c#
we have a list of the class public class DummyClass { public string Text { get; set; } public int LevelNo { get; set; } public List<DummyClass> Children { get; set; } } we want to add this list to another list with class. public class FragmentLevel { public int currentLevelNo { get; set; } public int ParentLevelNo { get; set; } public string Text { get; set; } } we need the result like var list = new List<FragmentLevel> { new FragmentLevel{ id = 1, text = "Root" }, new FragmentLevel{ id = 2, parent= 1, text = "Node-1.1" }, new FragmentLevel{ id = 3, parent= 2, text = "Node-1.1.1" } }; For getting result we are doing like for (int i = 0; i < DummyClassList.Count; i++) { list.Add(new FragmentLevel { currentLevelNo = DummyClassList[i].LevelNo, Text = DummyClassList[i].Text, }); do { for (int j = 0; j < DummyClassList[i].Children.Count; j++) { list1.Add(new FragmentLevel { LevelNo = DummyClassList[i].Children[j].LevelNo, Text = DummyClassList[i].Children[j].Text, }); } } while (DummyClassList[i].Children[i].Children != null); } But this will give wrong result. How we can get the result?
Try this way of filling the fragments recursively, private static void FillFragments(List<DummyClass> DummyClassList, List<FragmentLevel> list) { for (int i = 0; i < DummyClassList.Count; i++) { list.Add(new FragmentLevel { currentLevelNo = DummyClassList[i].LevelNo, Text = DummyClassList[i].Text, }); if (DummyClassList[i].Children != null && DummyClassList[i].Children.Count > 0) { FillFragments(DummyClassList[i].Children, list); } } } and the main method would look like this static void Main(string[] args) { var DummyClassList = new List<DummyClass> { new DummyClass { Children = new List<DummyClass> { new DummyClass{ Children = null, LevelNo=2, Text = "two" } }, LevelNo = 1, Text = "one" } }; var list = new List<FragmentLevel>(); FillFragments(DummyClassList, list); }