Follow these instructions to build a Backend For Frontend API C# ASP.NET Core.

ScriptBot.io
Alternatively, use an advanced code generator like ScriptBot ;-) to generate the solution.
  1. Create an ASP.NET Web Solution. Suffix the solution name with -BackendForFrontend-API. This will be your start-up project.
  2. Create a class library called *-BackendForFrontend-Data.
    1. Create an interface called IEntity.
      public interface IEntity
      {
          string Id { get; set; }
      }
    2. Create a folder called Generic.
    3. Create a folder called BaseAddress within Generic.
      Create the following files within this folder:
      1. Create an interface called IBaseAddress.
        public interface IBaseAddress
        {
            Uri BaseAddress { get; set; }
        }
                                
      2. Create a class called BaseAddressConfig.
        public class BaseAddressConfig : IBaseAddress
        {
            public Uri BaseAddress { get; set;  }
        }
      3. For the monolith create an address manager:
        1. Interface:
          public interface IMonolithManagerBaseAddress: IBaseAddress
          {
          }
                                         
        2. Class:
          public class MonolithManagerBaseAddress: ICustomerManagerBaseAddress
          {
              public Uri BaseAddress { get; set; }
              public MonolithManagerBaseAddress(string baseAddress)
              {
                  BaseAddress = new Uri(baseAddress);
              }
          }
      4. For each microservice create an interface base address manager:
        1. Interface:
          public interface IMicroserviceAManagerBaseAddress: IBaseAddress
          {
          }
        2. Class:
          public class MicroserviceAManagerBaseAddress: ICustomerManagerBaseAddress
          {
              public Uri BaseAddress { get; set; }
              public MicroserviceAManagerBaseAddress(string baseAddress)
              {
                  BaseAddress = new Uri(baseAddress);
              }
          }
    4. Create a folder called Repository within Generic.
      Create the following files within this folder:
      1. create a generic repository:
        1. Interface:
        2.     public interface IGenericRepository where T : IEntity
              {
                  string ResourcePath { get; set; }
                  Task> GetAllAsync();
                  Task GetByIdAsync(int id);
                  Task StoreNewAsync(T entity);
                  Task UpdateAsync(T entity);
                  Task DeleteAsync(T entity);
              }
        3. Class:
        4. public abstract class GenericRepository : IGenericRepository where T: IEntity
          {
              private static readonly HttpClient _client = new HttpClient();
          
              public string ResourcePath { get; set; }
              public GenericRepository(IConfiguration configuration, IBaseAddress baseAddress)
              {
                  _client.BaseAddress = baseAddress.BaseAddress;
                  _client.Timeout = new TimeSpan(0, 0, 30);
                  _client.DefaultRequestHeaders.Accept.Clear(); 
              }
          
              public async Task> GetAllAsync()
              {
                  // Setup HttyRequestMessage
                  var request = new HttpRequestMessage(HttpMethod.Get, $"{ResourcePath}");
                  request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
          
                  // Get HttyResponseMessage
                  var response = await _client.SendAsync(request);
                  response.EnsureSuccessStatusCode(); 
                  var content = await response.Content.ReadAsStringAsync();
                  var entities = JsonConvert.DeserializeObject>(content);
          
                  return entities;
              }
          
              public async Task DeleteAsync(T entity)
              {
                  // Setup HttyRequestMessage
                  var request = new HttpRequestMessage(HttpMethod.Delete, $"{ResourcePath}/{entity.Id}");
                  request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
          
                  // Get HttyResponseMessage
                  var response = await _client.SendAsync(request);
                  response.EnsureSuccessStatusCode(); 
                  var content = await response.Content.ReadAsStringAsync();
          
                  return (content.Length==0);
              }
          
              public async Task GetByIdAsync(int id)
              {
                  // Setup HttyRequestMessage
                  var request = new HttpRequestMessage(HttpMethod.Get, $"{ResourcePath}/{id}");
                  request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
          
                  // Get HttyResponseMessage
                  var response = await _client.SendAsync(request);
                  // response.EnsureSuccessStatusCode(); 
                  var content = await response.Content.ReadAsStringAsync();
                  var entities = JsonConvert.DeserializeObject(content);
          
                  return entities;
              }
          
              public async Task StoreNewAsync(T entity)
              {
                  // Setup HttyRequestMessage
                  var entityToCreate = JsonConvert.SerializeObject(entity);
                  var request = new HttpRequestMessage(HttpMethod.Post, $"{ResourcePath}");
                  request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                  request.Content = new StringContent(entityToCreate);
                  request.Content.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/json");
          
                  // Get HttyResponseMessage
                  var response = await _client.SendAsync(request);
                  response.EnsureSuccessStatusCode(); 
                  var content = await response.Content.ReadAsStringAsync();
                  var newEntity = JsonConvert.DeserializeObject(content);
          
                  return (newEntity.Id>0);
              }
          
              public async Task UpdateAsync(T entity)
              {
                  // Setup HttyRequestMessage
                  var entityToUpdate = JsonConvert.SerializeObject(entity);
          
                  var request = new HttpRequestMessage(HttpMethod.Put, $"{ResourcePath}/{entity.Id}");
                  request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                  request.Content = new StringContent(entityToUpdate);
                  request.Content.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/json");
          
                  // Get HttyResponseMessage
                  var response = await _client.SendAsync(request);
                  response.EnsureSuccessStatusCode(); 
                  var content = await response.Content.ReadAsStringAsync();
                  var newEntity = JsonConvert.DeserializeObject(content);
          
                  return (newEntity.Id > 0);
              }
          }
      2. For the monolith create a repository:
        1. Interface:
        2. public interface IMonolithRepository: IGenericRepository where T : IEntity
          {
          }
        3. Class:
        4. public class MonolithRepository : GenericRepository,
                                            IMonolithRepository where T : IEntity
          {
              public MonolithRepository(IConfiguration configuration,
                                        IMonolithBaseAddress baseAddress) : base(configuration, baseAddress)
              {}
          }
      3. For each microservice create a repository:
        1. Interface:
        2. public interface IMicroserviceAManagerRepository: IGenericRepository where T : IEntity
          {
          }
        3. Class:
        4. public class MicroserviceAManagerRepository : GenericRepository, 
                                                        IMicroserviceAManagerRepository where T : IEntity
          {
              public MicroserviceAManagerRepository(IConfiguration configuration,
                                                    IMicroserviceAManagerBaseAddress baseAddress) : base(configuration, baseAddress)
              {}
          }
  3. Create a class library called *-BackendForFrontend-Core. This will hold a model of your monolith and any enumerators for the model.
    1. Reference *-BackendForFrontend-Data.
    2. Create a folder called Domain.
    3. Populate the Domain folder with POCO classes representing the model. Each class should inherit from *_BackendForFrontend_Data.Generic.IEntity.
      A source code generator can do this automatically and with perfect accuracy.
      Example of an Invoice POCO:
      using System;
      using System.Collections.Generic;
      using *_BackendForFrontend_Data.Generic;
      
      namespace *_BackendForFrontend_Core.Domain
      {
          public class Invoice : IEntity
          {
              public string Id { get; set; }
              public string CustomerId { get; set; }
              public Domain.Customer Customer { get; set; }
              public DateTime InvoiceDate { get; set; }
              public DateTime DueDate { get; set; }
              public string Message { get; set; }
              public List InvoiceLines { get; set; }
          }
      }
      
  4. Reference *-BackendForFrontend-Core and *-BackendForFrontend-Data in -BackendForFrontend-API.
  5. Add the following NuGet packages to -BackendForFrontend-API:
    • AutoMapper.Extensions.Microsoft.DependencyInjection
    • Microsoft.Extensions.Configuration.Binder
    • Swashbuckle.AspNetCore
  6. Edit appsettings.json to add the following:
    "MonolithBaseAddress": "https://localhost:5000",
    "MicroserviceABaseAddress": "https://localhost:5003"
            

    The base addresses will be different for each project.

  7. Create a Models folder. For each model within the monolith create a POCO class
    Example of a Invoice POCO:
    using System;
    
    namespace *_BackendForFrontend_API.Models
    {
        public class Invoice
        {
            public string Id { get; set; }
            public string CustomerId { get; set; }
            public DateTime InvoiceDate { get; set; }
            public DateTime DueDate { get; set; }
            public string Message { get; set; }
        }
    }
  8. Create a folder called AutoMapper.
    1. Within this folder create a class called MapperProfiles. It should inherit from AutoMapper.Profile.
      using AutoMapper;
      using Core = AM_BackendForFrontend_Core;
      
      namespace AM_BackendForFrontend_API.AutoMapper
      {
          public class MapperProfiles : Profile
          {
              public MapperProfiles()
              {
                  // Repeat the following code for each POCO in the monolith class:
      
                  CreateMap<Models.POCO, Core.Domain.POCO>()
                  .ForMember(c => c.Id, opt => opt.Ignore())
                  .ReverseMap();
      
                  For Example:
                  CreateMap<Models.Invoice, Core.Domain.Invoice>()
                  .ForMember(c => c.Id, opt => opt.Ignore())
                  .ReverseMap();
              }
          }
      }
  9. Create a controller for each POCO in the monolith.
    Example of a Invoice POCO:
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Routing;
    using Microsoft.Extensions.Logging;
    using System;
    using System.Threading.Tasks;
    
    using *_BackendForFrontend_API.Models;
    using *_BackendForFrontend_Data.Generic;
    using AutoMapper;
    
    using Core = *_BackendForFrontend_Core;
    
    namespace *_BackendForFrontend_API.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class InvoiceController : ControllerBase
        {
            private readonly IAccountManagerRepository _repository;
            private readonly IMapper _mapper;
            private readonly LinkGenerator _linkGenerator;
            private readonly ILogger _logger;
    
            public InvoiceController(
                IAccountManagerRepository repository, 
                IMapper mapper, LinkGenerator linkGenerator,
                ILogger logger)
            {
                _repository = repository;
                _repository.ResourcePath = "api/Invoice";
    
                _mapper = mapper;
                _linkGenerator = linkGenerator;
                _logger = logger;
            }
    
            [HttpGet]
            public async Task> Get()
            {
                try
                {
                    var results = await _repository.GetAllAsync();
    
                    return _mapper.Map(results);
                }
                catch (Exception e)
                {
                    _logger.LogError(e, e.Message);
                    return StatusCode(
                        StatusCodes.Status500InternalServerError,
                        "Failed Request");
                }
            }
    
            [HttpGet("{id}")]
            public async Task> Get(string id)
            {
                try
                {
                    var result = await _repository.GetByIdAsync(id);
    
                    if (result == null) 
                        return NotFound();
    
                    return _mapper.Map(result);
    
                }
                catch (Exception e)
                {
                    _logger.LogError(e, e.Message);
                    return StatusCode(
                        StatusCodes.Status500InternalServerError,
                        "Failed Request");
                }
            }
    
            [HttpPost]
            public async Task> Post(Invoice model)
            {
                try
                {
                    // Make sure InvoiceId is not already taken
                    var existing = await _repository.GetByIdAsync(model.Id);
                    if (existing != null)
                        return BadRequest("Invoice Id in Use");
    
                    // map
                    var Invoice = _mapper.Map(model);
    
                    //save and return
                    if (!await _repository.StoreNewAsync(Invoice))
                        return BadRequest("Bad request, could not create record!");
    
                    var location = _linkGenerator.GetPathByAction(
                        "Get", 
                        "Invoice",
                        new { Id = Invoice.Id });
    
                    return Created(location, _mapper.Map(Invoice));
    
                }
                catch (Exception e)
                {
                    _logger.LogError(e, e.Message);
                    return StatusCode(
                        StatusCodes.Status500InternalServerError, 
                        "Failed Request");
                }
            }
    
            [HttpPut("{id}")]
            public async Task> Put(
                string id,
                Invoice updatedModel)
            {
                try
                {
                    var currentInvoice = await _repository.GetByIdAsync(id);
                    if (currentInvoice == null)
                        return NotFound($"Could not find Invoice with Id of {id}");
    
                    _mapper.Map(updatedModel, currentInvoice);
    
                    if (await _repository.UpdateAsync(currentInvoice))
                        return _mapper.Map(currentInvoice);
                }
                catch (Exception e)
                {
                    _logger.LogError(e, e.Message);
                    return StatusCode(
                        StatusCodes.Status500InternalServerError, 
                        "Failed Request");
                }
    
                return BadRequest();
            }
    
            [HttpDelete("{id}")]
            public async Task Delete(string id)
            {
                try
                {
                    var Invoice = await _repository.GetByIdAsync(id);
                    if (Invoice == null)
                        return NotFound();
    
                    if (await _repository.DeleteAsync(Invoice))
                        return Ok();
    
                }
                catch (Exception e)
                {
                    _logger.LogError(e, e.Message);
                    return StatusCode(
                        StatusCodes.Status500InternalServerError, 
                        "Failed Request");
                }
    
                return BadRequest("Failed to delete the Invoice");
            }
        }
    }
  10. Edit Startup.cs by adding the following to Configure:
    services.AddControllers();
    services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
    
    services.AddScoped<IBaseAddress, BaseAddressConfig>();
    
    // For each micro service
    services.AddSingleton<IMicroServiceABaseAddress>(a => new CustomerManagerBaseAddress(Configuration.GetValue<string>("MicroServiceABaseAddress")));
    services.AddSingleton(typeof(IMicroServiceARepository<>), typeof(MicroServiceARepository<>));
    
    services.AddSingleton<IMonolithBaseAddress>(a => new MonolithBaseAddress(Configuration.GetValue("MonolithBaseAddress")));
    services.AddSingleton(typeof(IMonolithRepository<>), typeof(MonolithRepository<>));
    
    services.RegisterSwagger();
  11. Edit Startup.cs by adding the following to Configure:
    if (env.IsDevelopment())
        app.UseDeveloperExceptionPage();
    
    app.UseSwagger();
    
    app.UseHttpsRedirection();
    
    app.UseRouting();
    
    app.UseAuthorization();
    
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
Copyright © 2025 delaney. All rights reserved.