.NET controllers compact en overzichtelijk houden

Toen ik begon met programmeren, hanteerde ik een pragmatische aanpak: als het werkt en de code enigszins leesbaar is, is het goed genoeg. Destijds waren .NET controllers van 150+ regels niet ongebruikelijk voor mij. Met de tijd heb ik me verdiept in codepraktijken, waarbij ‘separation of concerns’ een prominente rol speelt. Tegenwoordig schrijf ik controllers die doorgaans tussen 10 en 30 regels bevatten. Dit bereik ik niet door magie, maar door de applicatie gestructureerd op te bouwen en code die niet echt thuis hoort in de controller te verplaatsen naar aparte klassen. In deze blog demonstreer ik dit aan de hand van twee verschillende situaties: het ophalen van gegevens en het mappen van deze gegevens.

Laten we beginnen met een voorbeeld van hoe het niet moet. Hieronder staat een stuk code dat alle benodigde logica voor een gemiddelde bewerkingspagina bevat. Voor deze blog houd ik de code bewust eenvoudig, waarbij het vooral draait om het ophalen van een AppleTree-object en het mappen ervan 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 aspect dat doorgaans veel ruimte in beslag neemt, is het mappen tussen entiteiten en viewmodels. Door deze code ook naar aparte klassen te verplaatsen, kun je dezelfde voordelen behalen als bij de servicelaag. In dit geval gebruik ik een statische klasse om de mappers onder te brengen. De mapfunctie zelf wordt ook statisch gemaakt. Door de klassen statisch te maken, hoef je ze niet te instantiëren en kun je ze 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 methoden toe te passen, kun je de code in je controllers aanzienlijk verminderen en zo je controllers overzichtelijk houden. Natuurlijk zijn controllers in veel gevallen complexer dan in dit voorbeeld, maar deze methoden zijn vrijwel altijd toepasbaar. Als afsluiting van deze blog volgt de aangepaste code uit het begin.

[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

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

Fill out this field
Fill out this field
Geef alstublieft een geldig e-mailadres op.

Categorieën

Categorieën

Vragen?

Onze specialisten geven graag antwoord op uw vragen!