I am practicing using the Service / Repository pattern in a C# / .NET 8 app and have some questions about best practices.
Below is an example interface for one of the services:
namespace NCAAMB.Services.Interfaces;
public interface IEspnBasketballService
{
Task<EspnBasketballTeam?> GetBasketballTeam();
string GetTeamName(EspnBasketballTeam? team);
string GetNextEventId(EspnBasketballTeam? team);
}
And the corresponding service class:
namespace NCAAMB.Services;
public class EspnBasketballService : IEspnBasketballService
{
private readonly ILogger<EspnBasketballService> _logger;
private readonly IEspnBasketballRepository _espnRepo;
public EspnBasketballService(GetBasketballTeam() espnRepo, ILogger<EspnBasketballService> logger)
{
_espnRepo = espnRepo;
_logger = logger;
}
public Task<EspnBasketballTeam?> GetBasketballTeam() => _espnRepo.GetBasketballTeam();
public string GetTeamName(EspnBasketballTeam? team)
{
try
{
if (team == null)
{
throw new Exception("Team obj was null.");
}
return team?.team?.name ?? string.Empty;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
return string.Empty;
}
public string GetNextEventId(EspnBasketballTeam? team)
{
try
{
if (team == null)
{
throw new Exception("Team obj was null.");
}
return team?.team?.nextEvent?.First()?.id ?? string.Empty;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
return string.Empty;
}
}
What I think I got right:
- I believe
GetBasketballTeam()is being used in the service correctly which is callingIEspnBasketballRepositoryto fetch data from an API endpoint
What I think I currently got wrong:
- I am thinking
GetTeamName()andGetNextEventId()should not be included in the service. If not, what do you think is best practice for housing these methods? Utility class, extension methods, etc? I would also like the ability to have these methods testable and include logging.
Any suggestions and examples? Thanks in advance!
GetTeamNamemethod needs serious re-thinking...try/catchandthrowincorrectly... In C#/.NET, Exceptions are exceptional - they are not for control-flow - andtry + throw + catchis just wrong.teamhave ateamproperty that has anameproperty? If a Team has-a Team, why is it a Team? That's beyond confusing. If yourEspnBasketballTeamjust had aName, you wouldn't need a method to get it in the first place.