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 :)

asked Mar 21, 2021 at 17:27
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Do I understand correctly that the refactored version is not complete? \$\endgroup\$ Commented Mar 22, 2021 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\$ Commented Mar 25, 2021 at 11:24

1 Answer 1

1
\$\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.

answered Mar 22, 2021 at 7:43
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.