简体   繁体   中英

Best Practice to Get 1 object from Database using WebApi C# Layered Architecture

So I know my question seems basic but I want to know something that's been bugging me for a while, My backend is done following the Layered Architecture(repo-services-controllers)

I have an api call that should return a json of an employee after providing his id, so the url is something like api.mywebsite.com/api/employees/1

and my controller will look like this:

public async Task<EmployeeDto> GetEmployee([FromUri] int eId)
{
    return GetService<IEmployeeService>().GetEmployeeById(eId);
}

my question is, what are the checks I'm supposed to do when I get this object? Should I do a check if the employee is deleted (soft deleted that is)? I obviously should do a check if it returns a null (didnt find an employee with such an id)

But if I want to do a check if the entity is deleted, should I do it in the repository layer or the service layer? repo layer:

public Task<Employee> GetSingle(int id)
{
    return GetDatabase().Employees.Where(x => x.EmployeeId== id && !x.Deleted).SingleOrDefaultAsync();
}

or on the service layer:

var emp= await GetTenantRepository<IEmployeeRepository>().GetSingle(eId);
if (emp==null)
{
    throw ...
}
if (emp.Deleted)
{
    throw ...
}

Am I too overthinking it and it doesnt matter if I put it here or there?

It's all about code style, architecture philosophy and chosen design :) Answering on your question about "where to put checking": It depends on responsibilities of your layers. All code samples are just for reference and shouldn't be considered as straightforward solution

1) DAL (repository) - is the bridge from application to storage. It should encapsulate all the stuff related to DB interaction and DB implementation details. So, in case of missing entity it's fine to return null from repository interface.

2) BL (service) - is combining raw data fetched from repository(s) and applying some business rules/actions to them. In case of simple CRUD service it becomes very similar to repository and may handle some DB exceptions, make data transformations (map DAL object to BL) etc. Again, null returned from BL layer indicates missing entity. Eg based on your code you can encapsulate some DB inconsistency here and consider multiple entries as missing value. BL service example:

public async Task<EmployeeDto> GetEmployee(int eId)
{
    try
    {
        return GetService<IEmployeeService>().GetEmployeeById(eId);
    }
    catch (InvalidOperationException) //If it's suitable
    {
        return null;
    }
}

3) API layer (controllers) - is the RESTFUL interface. It combines results from service(s) and represents it as resources and returns status codes and resources represenation. In case of missing entity the best way is to return 404 status (HttStatusResult) from your RESTFUL API.

public async Task<IHttpActionResult> GetEmployee([FromUri] int eId)
{
    var res = GetService<IEmployeeService>().GetEmployeeById(eId);

    return res == null ? (IHttpActionResult)NotFound() : Ok(res);
}

So, you are free to check the missing result on ANY layer, but do it in the right way. Your repository should never drive the API behavior(I mean no code should be developed for resources on DAL. Eg resource object should not have exactly the same props as DAL object) , BL never should affect DAL and vice versa.

PS it goes beyond the scope of question, but take a look at IoC and DI. You current DI implementation is not the best in my opinion.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM