.NET controllers compact en overzichtelijk houden

Toen ik zelf begon met programmeren pakte ik alles heel pragmatisch aan; als het werkt en de code enigszins leesbaar is, is het voldoende. Toentertijd waren .NET controllers van 150+ regels niets geks voor mij. Door de jaren heen heb ik mij verdiept in code practices en het onderdeel ‘seperation of concerns’ komt daar heel duidelijk in naar voren. Tegenwoordig lukt het om controllers te schrijven die ergens tussen 10 tot 30 regels bevatten. Dit komt natuurlijk niet doordat ik code magisch magisch laat verdwijnen, maar door de applicatie gestructureerd op te bouwen en door code niet écht in de controller thuis hoort te verplaatsen naar een aparte classe. In deze blog laat ik zien hoe ik dat voor twee verschillende situaties aanpak; het ophalen van de gegevens en het mappen van de gegevens.

Ik begin met een voorbeeld van hoe het niet moet. Onderstaand stuk code bevat alle code die een gemiddelde edit actie pagina ook bevat. Deze code is voor deze blog bewust heel simpel gehouden, het draait hier hoofdzakelijk om het ophalen van een AppleTree object en deze te mappen van/naar een viewmodel.

[code language=”csharp”]
public IActionResult Edit()
{
AppleTree tree = _context.Trees
.Include(t => t.Roots)
.Include(t => t.Branches.Select(b => b.Leaves))
.Include(t => t.Branches.Select(b => b.Apples))
.OrderBy(t => t.Age)
.FirstOrDefault(t => t.Color == “Brown”);

if (tree == null)
{
return NotFound();
}

AppleTreeEditViewModel model = new AppleTreeEditViewModel
{
Name = tree.Name,
Location = tree.Location,
Age = tree.Age
// etc
};

return View(model);
}

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(AppleTreeEditViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}

AppleTree tree = _context.Trees
.Include(t => t.Roots)
.Include(t => t.Branches.Select(b => b.Leaves))
.Include(t => t.Branches.Select(b => b.Apples))
.OrderBy(t => t.Age)
.FirstOrDefault(t => t.Color == “Brown”);

tree.Name = model.Name;
tree.Location = model.Location;
tree.Age = model.Age;
// etc

_context.Entry(tree).State = EntityState.Modified;
_context.SaveChanges();

return RedirectToAction(“Details”);
}
[/dm_code_snippet]

Ophalen van de Tree

Zelf maak ik gebruik van een servicelaag met daarachter eventueel een repository laag. Voor dit voorbeeld zou ik in mijn TreeService een functie ‘GetYoungestBrownTree’ maken, deze functie ziet er dan als volgt uit:

[code language=”csharp”]
public Tree GetYoungestBrownTree()
{
return _context.Trees
.Include(t => t.Roots)
.Include(t => t.Branches.Select(b => b.Leaves))
.Include(t => t.Branches.Select(b => b.Apples))
.OrderBy(t => t.Age)
.FirstOrDefault(t => t.Color == “Brown”);
}
[/dm_code_snippet]

Wanneer je vervolgens een instantie van je service aanmaakt in de controller kan de functie als volgt worden aangeroepen:

[code language=”csharp”]
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(AppleTreeEditViewModel model)
{
AppleTree tree = _treeService.GetYoungestBrownTree();

tree.Name = model.Name;
tree.Location = model.Location;
tree.Age = model.Age;
// etc

_context.Entry(tree).State = EntityState.Modified;
_context.SaveChanges();

return RedirectToAction(“Details”);
}
[/dm_code_snippet]

Deze aanpak biedt drie voordelen:

  • De code wordt afgezonderd naar een centrale plaats
  • Dit houdt de controller compact en overzichtelijk
  • Deze code kan nu worden hergebruikt

De mapping

Een ander deel dat vrijwel altijd een grote hoeveelheid ruimte in beslag neemt is het mappen tussen de entiteit(en) en het viewmodel. Door ook deze stukken code naar aparte classes te verplaatsen kun je dezelfde drie pluspunten behalen zoals bij de servicelaag. Voor dit scenario maak ik een statische classe aan om de mappers in te plaatsen. De mapping functie zelf maak ik ook statisch. Door de classes statisch te maken hoef je deze niet te instantiëren en kun je dus direct gebruiken.

[code language=”csharp”]
public static class TreeMapper
{
public static AppleTreeEditViewModel MapAppleTreeEdit(AppleTree tree)
{
return new AppleTreeEditViewModel
{
Name = tree.Name,
Location = tree.Location,
Age = tree.Age
// etc
};
}

public static AppleTree MapAppleTreeEdit(AppleTree tree, AppleTreeEditViewModel model)
{
tree.Name = model.Name;
tree.Location = model.Location;
tree.Age = model.Age;
// etc

return tree;
}
}
[/dm_code_snippet]

Conclusie

Door beide methodes toe te passen kun je de code in je controllers aanzienlijk verminderen om zo je controllers overzichtelijk te houden. Natuurlijk zijn controllers in veel gevallen een stuk complexer dan in dit voorbeeld, maar hoe dan ook zijn deze methodes bijna altijd toe te passen. Als afsluiting van deze blog volgt de aangepaste code uit het begin van deze blog.

[code language=”csharp”]
public IActionResult Edit()
{
AppleTree tree = _treeService.GetYoungestBrownTree();

if (tree == null)
{
return NotFound();
}

AppleTreeEditViewModel model = TreeMapper.MapAppleTreeEdit(tree);

return View(model);
}

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(AppleTreeEditViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}

AppleTree tree = _treeService.GetYoungestBrownTree();

tree = TreeMapper.MapAppleTreeEdit(tree, model);

_treeService.Update(tree);

return RedirectToAction(“Details”);
}
[/dm_code_snippet]

Meer weten over onze oplossingen?

Onze consultants hebben veel ervaring binnen een grote verscheidenheid aan branches.
Eens verder brainstormen over de mogelijkheden voor jouw organisatie?

Maak kennis met onze specialist Arnoud van der Heiden.

Wellicht herkent u een van deze vraagstukken.

Inmiddels hebben wij ruime ervaring opgedaan met maatwerkapplicaties. Wij staan ook u graag te woord bij vragen of opmerkingen.

Maatwerk applicaties zijn softwareoplossingen die specifiek zijn ontworpen voor de unieke behoeften en vereisten van een bedrijf. Ze bieden meer flexibiliteit, schaalbaarheid en aanpasbaarheid dan kant-en-klare software.

Het hangt af van de complexiteit van de applicatie en de specifieke behoeften van uw bedrijf.

Enkele weken tot enkele maanden, afhankelijk van de omvang van het project.

Low-code applicaties zijn ontworpen om sneller ontwikkeld te worden met minder code. High-code applicaties zijn robuuster, maar kosten meer tijd en middelen om te ontwikkelen. Welke geschikt is voor uw bedrijf hangt af van de specifieke vereisten van uw project.

.NET, React, Angular, Blazor, Python, Node.js en meer, afhankelijk van de specifieke behoeften van de klant.

Onze maatwerk applicaties bieden een uitstekende prijs-kwaliteitverhouding omdat ze precies aan uw behoeften voldoen en we werken met de nieuwste technologieën.

We werken nauw samen met onze klanten om hun unieke vereisten te begrijpen en een op maat gemaakte oplossing te bieden. We ontwikkelen in sprints, waarbij aan het einde van de sprint een nieuw stuk software opgeleverd wordt.

Ja, we bieden uitgebreide onderhouds- en ondersteuningsdiensten om ervoor te zorgen dat uw applicatie optimaal blijft werken en eventuele problemen snel worden opgelost.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Dit is een verplicht veld
Dit is een verplicht veld
Geef een geldig e-mailadres op.

Categorieën

Categorieën

Vragen?

Onze specialisten geven graag antwoord op uw vragen!