The BAL should contain the Business Logic.
The Controller will use the BAL's API and high-level functions in a bridge pattern and orchestrate data exchanges with the DAL underneath, loading and persisting data, like this:
MyEntity e;
Repository<MyEntity> r;
r = DAL.GetRepository<MyEntity>;
e = r.Retrieve(x => x.Age > 20);
v = BAL.GetValidator<MyEntity>();
e.Broken = !v.Validate(e).HasErrors;
e.LastChecked = DateTime.Now;
DAL.GetRepository("MyEntity").Update(e);
This is not working code, it is just to give the idea of a thin controller. If this repeats too often (like 3 times or more) it's time to consider promoting the code into the BAL, because it might be a commonly accepted procedure of the business.
You can add Unit of Work patterns and using () {}
clauses as needed. The problem will always be: what is business logic and was is application logic? What goes into the controller and what into the library?
Generally, try to keep the controllers thin and keep the BAL free of persistence logic and application logic.
Principles like DRY (Don't Repeat Yourself) and KISS (Keep It Simple, Stupid) will guide you along the way. The rest is analysis (practices for requirement gathering) and years of experience in this field. Both can't be taught but require that you keep practicing.