HiveBrain v1.2.0
Get Started
← Back to all entries
snippetcsharpModerate

Simple example of N-Tier, entity framework, unit of work, repository, business logic layer

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
layersimplebusinessexampletierlogicworkunitrepositoryframework

Problem

I've been studying C# for about 6 months and am trying to make a simple example for an n-tier application. I want to learn to do things in the most proper and professional way. This example uses a table in the database called "Settings" where various application settings can be persisted to the database. I figure once I can make a simple example, then I can have the knowledge to do something more advanced with the other tables in the database. I'm most concerned if this is a good simple example of a business logic layer.

There are 4 projects:

-
AnimalDB.Models - POCO objects

-
AnimalDB.DataAccess - Entity Framework DBContext, Repository, Unit of Work

-
AnimalDB.Logic - Business Logic Layer

-
AnimalDB.API - Web API

Here is my code for the project:

AnimalDB.Models

namespace AnimalDB.Models
{
    [Table("Settings")]
    public class Setting
    {
        [Key]
        public int SettingID { get; set; }

        [Required]
        [MaxLength(255)]
        public string Name { get; set; }

        [Required]
        [MaxLength(255)]
        public string Value { get; set; }
    }
}


AnimalDB.DataAccess

```
namespace AnimalDB.DataAccess
{
public class AnimalDBContext: DbContext
{
public DbSet Settings { get; set; }

public AnimalDBContext():base("AnimalDB"){ }
}
}

namespace AnimalDB.DataAccess
{
public class GenericRepository where TEntity : class
{
internal AnimalDBContext context;
internal DbSet dbSet;

public GenericRepository(AnimalDBContext context)
{
this.context = context;
this.dbSet = context.Set();
}

public virtual IEnumerable Get(
Expression> filter = null,
Func, IOrderedQueryable> orderBy = null,
string includeProperties = "")
{
IQueryable query = dbSet;

if (filter != null)
{
query = query.Where(filter);
}

foreac

Solution

Of your questions, 1, 4, 5 all seem to hit on a common theme I think you might be missing the point of. The Single Responsibility Principle says that every object should have exactly one reason to change. The nuances of this become apparent if you were to try to write unit tests around your controller.

Without making any changes, it seems impossible to write tests for your SettingsController without hitting a real database. Go ahead and try it.

So how would you write tests for SettingsController without hitting a database? First thing you need to do is to remove the concern of persistence from the controller by inverting the control of it to something else. You are 90% of the way there already in that you have a class that handles this called the SettingsManager. What you need is an easy way of swapping out implementations of the SettingsManager without modifying the code of SettingsController. This is generally done by injecting an instance into the constructor of the SettingsController. But we aren't done yet. SettingsManager is a concrete class that cannot have its methods overridden. I would extract out an interface, maybe an ISettingsManager, and then instead of injecting an instance of SettingsManager to the SettingsController, you would instead inject an instance of ISettingsController.

So you are probably wondering how this helps. Now you could theoretically write a new implementation of ISettingsManager that stores settings in memory, or to DynamoDB, or MongoDB, or writes to a CSV on the filesystem, it doesn't matter. In testing you might even make a MockSettingsManager using something like Moq. Now what you have is a way of testing only the logic in the SettingsController separate from everything else.

As for validation, I sometimes struggle with that myself. I find it helpful to ask myself "Who should be responsible for validation?" or "Where would I put validation so that validation is that objects only responsibility?" or my personal favorite "Where would I put validation if I only was going to write tests for validation and nothing else?"

I strongly encourage you to do two things going forward that will make a lot of these concepts clearer.

  • Watch this talk from Uncle Bob called Architecture The Lost Years. Bob Martin gives some great background on where the SOLID principles come from and how they benefit your applications architecture as a whole.



  • Get in the habit of practicing Test Driven Development. It may feel painful and slow at first, but once you get in the habit of it you will find it does far more than reduce the bug count. It goes a long way to producing more maintainable code, code that follows better object-oriented patterns, and in the long run makes you a more productive programmer.

Context

StackExchange Code Review Q#43463, answer score: 11

Revisions (0)

No revisions yet.