To implement the Template Method Pattern in an ASP.NET Core Web API with a 3-tier architecture, I need to create layers for presentation, business logic, and data access. Additionally, I need to create a model for CSharpCornerArticle. This design pattern allows for a structured, modular, and easily maintainable architecture by separating concerns into distinct layers and leveraging the Template Method Pattern to provide a common structure for CRUD operations while allowing flexibility for additional logic in concrete implementations.
Create the ASP.NET Core Web API Project
Start by creating a new ASP.NET Core Web API project in Visual Studio or your preferred development environment.
Create Layers
Implement the 3-tier architecture by creating separate projects or folders for each layer.
Presentation Layer: Controllers and DTOs.
Business Logic Layer: Services.
Data Access Layer: Repositories and the data model.
Model (CSharpArticle):
Create a model class representing the CSharpArticle.
// Sardar Mudassar Ali Khan
// CSharpArticle.cs
public class CSharpArticle
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
Data Access Layer (Repository)
Create a repository interface and implementation for data access.
//Sardar Mudassar Ali Khan
using System;
using System.Collections.Generic;
using System.Linq;
public interface IRepository<T>
{
T GetById(int id);
IEnumerable<T> GetAll();
void Add(T entity);
void Update(T entity);
void Delete(int id);
}
public class CSharpArticleRepository : IRepository<CSharpArticle>
{
private readonly List<CSharpArticle> _data; // Simulated in-memory storage, replace this with your actual data source
public CSharpArticleRepository()
{
_data = new List<CSharpArticle>();
// Example initial data for simulation
_data.Add(new CSharpArticle { Id = 1, Title = "Sample Title 1", Content = "Sample Content 1" });
_data.Add(new CSharpArticle { Id = 2, Title = "Sample Title 2", Content = "Sample Content 2" });
}
public CSharpArticle GetById(int id)
{
return _data.FirstOrDefault(article => article.Id == id);
}
public IEnumerable<CSharpArticle> GetAll()
{
return _data;
}
public void Add(CSharpArticle entity)
{
if (entity == null)
{
throw new ArgumentNullException(nameof(entity));
}
entity.Id = _data.Any() ? _data.Max(a => a.Id) + 1 : 1;
_data.Add(entity);
}
public void Update(CSharpArticle entity)
{
if (entity == null)
{
throw new ArgumentNullException(nameof(entity));
}
var existing = _data.FirstOrDefault(a => a.Id == entity.Id);
if (existing != null)
{
existing.Title = entity.Title;
existing.Content = entity.Content;
}
}
public void Delete(int id)
{
var entity = _data.FirstOrDefault(a => a.Id == id);
if (entity != null)
{
_data.Remove(entity);
}
}
}
public class CSharpArticle
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
Business Logic Layer (Service)
Create a service that will use the Template Method Pattern.
// Sardar Mudassar Ali Khan
public abstract class CSharpArticleService
{
protected readonly IRepository<CSharpArticle> repository;
public CSharpArticleService(IRepository<CSharpArticle> repository)
{
this.repository = repository ?? throw new ArgumentNullException(nameof(repository));
}
public CSharpArticle GetArticle(int id)
{
if (id <= 0)
{
throw new ArgumentException("Invalid ID");
}
return repository.GetById(id);
}
public IEnumerable<CSharpArticle> GetAllArticles()
{
return repository.GetAll();
}
public void CreateArticle(CSharpArticle article)
{
if (article == null)
{
throw new ArgumentNullException(nameof(article));
}
repository.Add(article);
}
public void UpdateArticle(CSharpArticle article)
{
if (article == null)
{
throw new ArgumentNullException(nameof(article));
}
if (repository.GetById(article.Id) == null)
{
throw new InvalidOperationException("Article does not exist");
}
repository.Update(article);
}
public void DeleteArticle(int id)
{
if (id <= 0)
{
throw new ArgumentException("Invalid ID");
}
repository.Delete(id);
}
}
public class ConcreteCSharpArticleService : CSharpArticleService
{
public ConcreteCSharpArticleService(IRepository<CSharpArticle> repository) : base(repository)
{
this.repository = repository ?? throw new ArgumentNullException(nameof(repository));
}
public IEnumerable<CSharpArticle> GetArticlesWithContentLengthGreaterThan(int length)
{
return repository.GetAll().Where(article => article.Content.Length > length);
}
public void PublishArticle(int id)
{
var article = repository.GetById(id);
if (article == null)
{
throw new ArgumentException("Article not found");
}
}
public void ArchiveArticle(int id)
{
var article = repository.GetById(id);
if (article == null)
{
throw new ArgumentException("Article not found");
}
}
}
Presentation Layer (Controller)
Create a controller for handling HTTP requests.
// Sardar Mudassar Ali Khan
// CSharpArticleController.cs
[Route("api/articles")]
[ApiController]
public class CSharpArticleController : ControllerBase
{
private readonly CSharpArticleService articleService;
public CSharpArticleController(CSharpArticleService articleService)
{
this.articleService = articleService;
}
[HttpGet]
public IActionResult Get()
{
var articles = articleService.GetAllArticles();
return Ok(articles);
}
[HttpGet("{id}")]
public IActionResult Get(int id)
{
var article = articleService.GetArticle(id);
if (article == null)
return NotFound();
return Ok(article);
}
[HttpPost]
public IActionResult Post([FromBody] CSharpArticle article)
{
articleService.CreateArticle(article);
return Created($"/api/articles/{article.Id}", article);
}
[HttpPut("{id}")]
public IActionResult Put(int id, [FromBody] CSharpArticle article)
{
var existingArticle = articleService.GetArticle(id);
if (existingArticle == null)
return NotFound();
article.Id = id;
articleService.UpdateArticle(article);
return NoContent();
}
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
var existingArticle = articleService.GetArticle(id);
if (existingArticle == null)
return NotFound();
articleService.DeleteArticle(id);
return NoContent();
}
}
Dependency Injection Configuration
Register your services and repositories in the Startup.cs.
// Sardar Mudassar Ali Khan
// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IRepository<CSharpArticle>, CSharpArticleRepository>();
services.AddScoped<CSharpArticleService, ConcreteCSharpArticleService>();
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Conclusion
The implementation of the Template Method Pattern within an ASP.NET Core Web API with a 3-tier architecture offers a structured and flexible approach for handling CRUD operations on the `CSharpArticle` model. Here's a summary of the key points:
1. Design Pattern Implementation: The Template Method Pattern is used to define a skeletal structure for performing CRUD operations, offering flexibility to extend or modify specific parts of the process while keeping the overall structure intact.
2. Layered Architecture:
- Presentation Layer: Controllers handle HTTP requests and responses.
- Business Logic Layer: Services manage the business logic, leveraging the Template Method Pattern for CRUD operations.
- Data Access Layer: Repositories interact with the data storage, handling actual database operations.
3. Cohesive Functionality:
- The abstract CSharpArticleService class provides a standard interface for CRUD operations on CSharpArticle.
- The concrete implementation, `ConcreteCSharpArticleService`, extends the abstract class, allowing for additional methods tailored to specific business needs.
4. Error Handling and Validation:
- Proper checks and validations ensure data integrity and security, preventing potential issues such as null references and invalid operations.
5. Scalability and Extensibility:
- The modular structure facilitates scalability and maintenance, enabling the addition of new features or alterations without affecting the core structure.
By adhering to this architecture, developers can maintain a clear separation of concerns, streamline development, and easily adapt the system to changing requirements, making it a robust foundation for ASP.NET Core Web API development.