I tried to follow the example from https://chaitanyasuvarna.wordpress.com/2021/03/21/factory-pattern-di-in-net-core/ but i didn't use a classic console application, I created a .Net core service project in VS.
Please find below the files with their source code:
IShape.cs
public interface IShape
{
public void GetInputValues();
public void DisplaySurfaceArea();
public void DisplayVolume();
}
Sphere.cs
public class Sphere : IShape
{
public decimal Radius { get; set; }
public void GetInputValues()
{
Console.WriteLine("Radius : ");
Radius = decimal.Parse(Console.ReadLine());
}
public void DisplaySurfaceArea()
{
Console.WriteLine("Surface Area of the sphere is :" + (4 * 3.14m * Radius * Radius));
}
public void DisplayVolume()
{
Console.WriteLine("Volume of the sphere is :" + (4 / 3 * 3.14m * Radius * Radius * Radius));
}
}
Cube.cs
public class Cube : IShape
{
public decimal Side { get; set; }
public void GetInputValues()
{
Console.WriteLine("Side : ");
Side = decimal.Parse(Console.ReadLine());
}
public void DisplaySurfaceArea()
{
Console.WriteLine("Surface Area of the Cube is :" + (6 * Side * Side));
}
public void DisplayVolume()
{
Console.WriteLine("Volume of the Cube is :" + (Side * Side * Side));
}
}
ShapeFactory.cs
public class ShapeFactory : IShapeFactory
{
private readonly IServiceProvider serviceProvider;
public ShapeFactory(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public IShape GetShape(ShapeEnum shapeEnum)
{
switch (shapeEnum)
{
case ShapeEnum.Cube:
return (IShape)this.serviceProvider.GetService(typeof(Cube));
case ShapeEnum.Sphere:
return (IShape)this.serviceProvider.GetService(typeof(Sphere));
default:
throw new ArgumentOutOfRangeException(nameof(shapeEnum), shapeEnum, $"Shape of {shapeEnum} is not supported.");
}
}
}
public interface IShapeFactory
{
public IShape GetShape(ShapeEnum shapeEnum);
}
ShapeCalculationService.cs
public class ShapeCalculationService : IShapeCalculationService
{
private readonly IShapeFactory _shapeFactory;
private IShape _shape;
public ShapeCalculationService(IShapeFactory shapeFactory)
{
this._shapeFactory = shapeFactory;
}
public void CalculateShapeMeasurements()
{
this._shape = GetShapeFromUser();
this._shape.GetInputValues();
this._shape.DisplaySurfaceArea();
this._shape.DisplayVolume();
}
private IShape GetShapeFromUser()
{
Console.WriteLine("Enter the serial no. for the shape you want to choose :");
Console.WriteLine("1. Cube");
Console.WriteLine("2. Sphere");
var serialNumber = int.Parse(Console.ReadLine());
switch (serialNumber)
{
case 1:
return _shapeFactory.GetShape(ShapeEnum.Cube);
case 2:
return _shapeFactory.GetShape(ShapeEnum.Sphere);
default:
throw new ArgumentOutOfRangeException("Invalid input.");
}
}
}
public interface IShapeCalculationService
{
public void CalculateShapeMeasurements();
}
worker.cs
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly IShapeCalculationService shapeCalculationService;
public Worker(ILogger<Worker> logger, IShapeCalculationService shapeCalculationService)
{
_logger = logger;
this.shapeCalculationService = shapeCalculationService;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
shapeCalculationService.CalculateShapeMeasurements();
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Delay(1000, stoppingToken);
}
}
}
Program.cs
using TestFactory;
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext,services) =>
{
services.AddTransient<IShapeFactory, ShapeFactory>();
services.AddTransient<IShapeCalculationService, ShapeCalculationService>();
services.AddScoped<Sphere>().AddScoped<IShape, Sphere>(s=>s.GetService<Sphere>());
services.AddScoped<Cube>().AddScoped<IShape, Cube>(s => s.GetService<Cube>()); ;
services.AddHostedService<Worker>();
})
.Build();
await host.RunAsync();
While going through with the debugger, I found that
public IShape GetShape(ShapeEnum shapeEnum)
always returns null.
Please can you advice what I am doing wrong, and how I can correct it and make the example work.
You can simplify your solution by using delegate in DI, like this:
{
public delegate IShape ShapeResolver(int serialNumber);
}
then in program.cs:
services.AddScoped<Sphere>();
services.AddScoped<Cube>();
services.AddTransient<ShapeResolver>(serviceProvider => key =>
{
switch (key)
{
case 1:
return this.serviceProvider.GetRequiredService<Cube>();
case 2:
return this.serviceProvider.GetRequiredService<Sphere>();
default:
throw new KeyNotFoundException();
}
ShapeCalculationService will look something like this:
public class ShapeCalculationService : IShapeCalculationService
{
private readonly ShapeResolver _ShapeResolver;
private IShape _shape;
public ShapeCalculationService(ShapeResolver shapeResolver)
{
this._ShapeResolver= shapeResolver;
}
public void CalculateShapeMeasurements()
{
this._shape = GetShapeFromUser();
this._shape.GetInputValues();
this._shape.DisplaySurfaceArea();
this._shape.DisplayVolume();
}
private IShape GetShapeFromUser()
{
Console.WriteLine("Enter the serial no. for the shape you want to choose :");
Console.WriteLine("1. Cube");
Console.WriteLine("2. Sphere");
var serialNumber = int.Parse(Console.ReadLine());
return _ShapeResolver(serialNumber);
}
}