Creating a standalone project which read JSON and simply response back. Trying to make the best use of dependency injection. However, I've few questions to clarify.
So firstly HomeController
is called which has a dependendency on ClassA
, so after refactoring ClassA
implements IClassA
and Updating Startup.cs
, HomeController
can now successfully use the instance created by the Startup.cs to invoke the method _IClassA.GetOP(data)
.
Now I see similar behavior where ClassA
has a dependency on ClassB
, UtiClass
& Document
class. So do I need to create Interfaces for all to remove the new
keyword used for creating instances.
Again, my primary focus is to retrieve the value of KeysAndValues
-> path
. So in ClassA
constructor I instantiated ClassB
and pass the IOptions<KeyAndValue>
. Unfortunately, I am unable to get the value of options.path
. Please help to clarify my doubts and kindly solve this puzzle. Thank you.
//HomeController
public class HomeController : ControllerBase
{
private readonly IClassA _IClassA;
public HomeController(IClassA iClassA)
_IClassA = iClassA;
public string Get(DTO_A data)
var result = _IClassA.GetOP(data);
}
//INTERFACE
public interface IClassA
public string GetOP(DTO_A data);
//Class
public sealed class ClassA : IClassA
//private readonly IClassB _IClassB; //Cannot Instantiated
private readonly ClassB _ClassB;
public ClassA(IOptions<KeysAndValues> options)
_ClassB = new ClassB(options);
Document request = new Document();
UtiClass objUtiClass = new UtiClass();
public string GetOP(DTO_A data)
{
request.Name = data.Name;
objUtiClass .Document = request;
_ClassB.UpdateMethod(objUtiClass );
}
public class Document : IDocument
{}
public class ClassC
{}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IClassA, ClassA>();
services.AddControllers();
services.AddScoped<IClassB, ClassB>();
services.Configure<KeysAndValues>(Configuration.GetSection("KeysAndValues"));
}
public class ClassB : IClassB
private IOptions<KeysAndValues> options;
public ClassB(IOptions<KeysAndValues> options)
this.options = options;
public void UpdateMethod(UtiClass req)
string fille = Path.Combine(options.path);
}
public class KeysAndValues
public string path { get; set; }
CodePudding user response:
Just like how class HomeController
requires interface IClassA
, class ClassA
needs to require interface IClassB
. Class ClassB
is the one that requires IOptions<KeysAndValues>
, because it's ClassB
that actually needs the path
value.
Now, you don't need to use interfaces at all here. However, I'd recommend using interfaces because it makes your life much easier should you add unit testing.
Here's what it would look like with interfaces.
public class HomeController : ControllerBase
{
private readonly IClassA _IClassA;
public HomeController(IClassA iClassA)
{
_IClassA = iClassA;
}
}
public interface IClassA { }
public interface IClassB { }
public class ClassA : IClassA
{
private readonly IClassB _IClassB;
public ClassA(IClassB iClassB)
{
_IClassB = iClassB;
}
}
public class ClassB : IClassB
{
private readonly KeysAndValues options;
public ClassB(IOptions<KeysAndValues> options)
{
this.options = options.Value;
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddTransient<IClassA, ClassA>();
services.AddTransient<IClassB, ClassB>();
services.Configure<KeysAndValues>(Configuration.GetSection("KeysAndValues"));
}
If you don't want to use interface, just remove all the interfaces and replace all constructor parameters with the concrete class, and modify ConfigureServices
with
services.AddTransient<ClassA>();
services.AddTransient<ClassB>();
I'd recommend AddTransient
over AddScoped
. Use Scoped only if you need information from the HTTP request/response explicitly in that service. I'd also recommend not having any properties in a service (Document request
and UtiClass objUtiClass
) that are not readonly
and set by DI, or you'll need to use AddSingleton
and ensure you don't get race conditions (which your current code looks like it will).