0
\$\begingroup\$

I have been trying to refactor my code since I found I've been doing a lot of copying and pasting to implement the logic of the web API controllers. Here's how the controllers looked like before refactoring

Controller for EducationalGroups table:

public class EducationalGroupsController : ApiController
    {
        public HttpResponseMessage Get()
        {
            try
            {
                using (SchoolDbContext entities = new SchoolDbContext())
                    return Request.CreateResponse(HttpStatusCode.OK,
                        entities.EducationGroups.Where(g => !g.Is_Delete).ToList());
            }
            catch (Exception e)
            {
                return Request.CreateErrorResponse(HttpStatusCode.NoContent, e);
            }
        }

        public HttpResponseMessage Post([FromBody] EducationGroup group)
        {
            try
            {
                using (SchoolDbContext entities = new SchoolDbContext())
                {
                    group.Create_User = WebApiConfig.CurrUserIdx;
                    group.Create_Date = DateTime.Now;

                    entities.EducationGroups.Add(group);
                    entities.SaveChanges();

                    var msg = Request.CreateResponse(HttpStatusCode.Created, group);
                    msg.Headers.Location = new Uri(Request.RequestUri, group.Id.ToString());
                    return msg;
                }
            }
            catch (Exception e)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, e);
            }
        }
    }

Controller for EducationalStages table:

public class EducationalStagesController : ApiController
    {
        public HttpResponseMessage Get()
        {
            try
            {
                //Notice the only difference here is the *Educational_Stages* object of type DbSet
                using (SchoolDbContext entities = new SchoolDbContext())
                    return Request.CreateResponse(HttpStatusCode.OK, 
                        entities.Education_Stages.Where(s => !s.Is_Delete).ToList());
            }
            catch (Exception e)
            {
                return Request.CreateErrorResponse(HttpStatusCode.NoContent, e);
            }
        }

        //Same implementation for this method as previous controller 
        //Only with the difference of the type of the parameter
        public HttpResponseMessage Post([FromBody] Education_Stages stage)
        {
            try
            {
                using (SchoolDbContext entities = new SchoolDbContext())
                {
                    stage.Create_User = WebApiConfig.CurrUserIdx;
                    stage.Create_Date = DateTime.Now;

                    entities.Education_Stages.Add(stage);
                    entities.SaveChanges();

                    var msg = Request.CreateResponse(HttpStatusCode.Created, stage);
                    msg.Headers.Location = new Uri(Request.RequestUri, stage.Id.ToString());
                    return msg;
                }
            }
            catch (Exception e)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, e);
            }
        }
    }

There are like 8 more controllers required for 8 more tables, so you get the idea of how redundant it looks like...

What I've been trying to do is create a base class for the entities that share the same fields as follows:

public abstract class BaseEntity
    {
        public int Id { get; set; }

        [StringLength(50)]
        public string Ar_Name { get; set; }

        [StringLength(10)]
        public string En_Name { get; set; }

        public bool Is_Delete { get; set; }

        public int? Create_User { get; set; }

        public DateTime? Create_Date { get; set; }

        public int? Last_Update_User { get; set; }

        public DateTime? Last_Update_Date { get; set; }
    }

And inherit it in all of the entities sharing the same fields:

public partial class Education_Stages : BaseEntity
    {
    }

And then create a base class for the API controllers to inherit from as follows, and here's where I can't find any more solutions for what I want:

public abstract class BaseApiVerbs<T> : ApiController where T : BaseEntity
    {
        private DbSet<T> dbSet;

        public BaseApiVerbs(DbSet<T> _dbSet)
        {
            dbSet = _dbSet;
        }

        public HttpResponseMessage Get()
        {
            try
            {
                return Request.CreateResponse(HttpStatusCode.OK, 
                    dbSet.Where(t => t.Is_Delete == false));
            }
            catch (Exception e)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, e);
            }
        }
        public HttpResponseMessage Post([FromBody] T entity)
        {
            // No Idea how to implement the same logic here without using DbContext... 
        }

Furthermore, I don't know how to initialize the controllers' classes and pass the DbSet object accordingly:

public class CityController : BaseApiVerbs<City>
    {
        SchoolDbContext context = new SchoolDbContext();
        public CityController() 
            : base( /* How would I pass the DbSet object here? */ )
        {
            
        }
    }

Is the idea of copying and pasting the code acceptable in this case? If not, how can I accomplish what I've been trying to do for the past two days?

I am a beginner so please don't be harsh in your replies if you found anything smelly in my code, kindly note it for me :)

\$\endgroup\$
2
  • \$\begingroup\$ Do I understand correctly that the refactored version is not complete? \$\endgroup\$ – Peter Csala Mar 22 at 8:10
  • \$\begingroup\$ A good start would be to go use dependency injection. If this is .net core, a DI framework is readily available. \$\endgroup\$ – Gert Arnold Mar 25 at 11:24
0
\$\begingroup\$

Honestly, don't try to invent new ways of doing things and instead learn well-documented ways of doing things, like MediatR and CQRS.

Please follow the Microsoft guidelines when naming things: only alphanumeric characters are allowed in property names, class names etc. (exception is the underscore at the start of a private member variable).

Use readable names. Ar_Name and En_Name are meaningless. Create_User and the likes are names of methods, not properties.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.