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 :)
-
1\$\begingroup\$ Do I understand correctly that the refactored version is not complete? \$\endgroup\$Peter Csala– Peter Csala2021年03月22日 08:10:39 +00:00Commented 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\$Gert Arnold– Gert Arnold2021年03月25日 11:24:33 +00:00Commented Mar 25, 2021 at 11:24
1 Answer 1
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.
Explore related questions
See similar questions with these tags.