I have used constructor only for Dependency Injection in MVC and created all my application or entity objects with out a construction like below
public class MyEntity
{
public string FirstName{get;set;}
public Type PropName{get;set;}
}
However I see many are using constructor for some purpose. I know we can use constructor to initialize something. But what are the scenarios should I consider to create a constructor like below? with readonly fields and setting them
public class Licence
{
private readonly Instant expiry;
private readonly IClock clock;
public Licence(Instant expiry, IClock clock)
{
this.expiry=expiry;
this.clock=clock;
}
//some methods & prop goes here
}
I have mostly seen this kind of code in Frameworks like MVC and some high level Application Frameworks designed by Architects.
Generally you'd pass in parameters in a constructor when you don't want those values to be changed after the object is instantiated; this can apply to a variety of situations, including Dependency Injection. A common case for this is custom Exception classes, where you want to pass on additional information that can't be modified:
public class MyException : Exception
{
public string MyField { get; private set; }
public MyException(string myField)
{
this.MyField = myField;
}
}
For Dependency Injection, consider providing a log provider implementation to your class:
public class MyClass
{
public ILogger Logger { get; private set; }
public MyClass(ILogger logger)
{
this.Logger = logger;
}
}
In both of these cases, you don't want the properties to change once you create them because they would change the fundamental meaning or behavior of the instance.
I only use constructors in classes where I use dependency injection or when I want to set data which I don't want to change anymore. For example, a MVC controller:
private readonly IProductService _productService;
private readonly IShoppingCartService _shoppingCartService;
public ProductController(IProductService productService,
IShoppingCartService shoppingCartService)
{
_productService = productService;
_shoppingCartService = shoppingCartService;
}
For my domain models, I don't create constructors to fill my public properties. That would result in a constructor like this:
public Order(string orderReference,
string userEmail,
string paymentIssuer,
bool? isProcessed,
ICollection<OrderDetail> orderDetails)
{
OrderReference = orderReference;
UserEmail = userEmail;
PaymentIssuer = paymentIssuer;
IsProcessed = isProcessed;
OrderDetails = orderDetails;
}
We can call this constructor this way:
new Order("test", "john#doe.com", "test", true, null);
Which makes it completely unclear that the arguments mean, I prefer the object initializer. Which looks like this:
new Order
{
OrderReference = "test",
UserEmail = "john#doe.com",
PaymentIssuer = "test",
IsProcessed = true
};
However, I do sometimes create a parameterless constructor for my domain models where I set some default data:
public Order()
{
UserId = Guid.NewGuid();
OrderDetails = new List<OrderDetail>();
}
Related
My .NET 6 ASPNET MVC application has the usual controller, model and view scenario, with a separate service layer/interface for getting and saving data. The service is injected into the controller via it's constructor, which gets the data and via the service. The service is also injected into the model's constructor, but because the model also requires a constructor with no parameters (for model binding when the form in the view is posted), so the service reference within the model is null, which causes problems when a "computed" property of the model is accessed which relies on a call to the service.
I'm aware that I can access the service instance when validating the model (via IServiceProvider being implemented by the ValidationContext argument to my model's implementation of IValidatableObject.Validate) but how can I access an IServiceProvider elsewhere in a model that's been constructed using the default constructor?
I've thought about encapsulating an IServiceProvider within a global/singleton class but suspect that would cause issues and doesn't seem at all elegant.
I presume you are trying to do something like this:
class MyModel
{
readonly MyService _myService;
public MyModel(MyService myService)
{
_myService = myService;
}
public string Prop1 { get; set; }
public string ComputedProp => _myService.Compute(Prop1);
}
A model for posting to a controller should really be a pure DTO (Data Transfer Object) and not include any behaviour such as this.
I would echo WiseGuy's suggestion and implement as follows:
class MyModel
{
public string Prop1 { get; set; }
// Initialize to avoid model binding validation error
// when null
public string Prop2 { get; set; } = string.Empty;
}
class MyController
{
readonly MyService _myService;
public MyController(MyService myService)
{
_myService = myService;
}
public async Task PostAsync(MyModel myModel)
{
myModel.Prop2 = _myService.Compute(myModel.Prop1);
// Rest of method
}
}
I would go further to say that a computed value does not belong on the DTO at all. Ideally the model used to post to your controller is not the same class as is used deeper in your application and the model should be transformed in the controller:
class MyModel
{
public string Prop1 { get; set; }
}
class MyEntity
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
class MyController
{
readonly MyService _myService;
public MyController(MyService myService)
{
_myService = myService;
}
public async Task PostAsync(MyModel myModel)
{
MyEntity myEntity = new MyEntity()
{
Prop1 = myModel.Prop1,
Prop2 = _myService.Compute(myModel.Prop1);
}
// Rest of method - using myEntity, not myModel
}
}
So I have been stuck with this issue for quite some time. We are implementing a DDD architecture and I don't want our models or entities to be anemic.
We are also using EF6 and Autofac. I don't want to implement a repository pattern as EF already acts as this pattern.
So say for instance we have a context called TestContext
public class TestContext : DbContext
{
public TestContext() : base("TestContext")
{
}
public DbSet<AEntity> AEntities { get; set; }
}
The one DBset it has is AEntity
public class AEntity
{
public ITest testService;
public Guid Id { get; set; }
public string Name { get; private set; }
public AEntity()
{
}
public AEntity(string name)
{
this.Name = name;
}
public virtual void Test()
{
// Logic.
// Global testLogic for names
testService.Test(this.Name);
}
}
So I have autoface configured to autowire property injection
builder.RegisterType<AEntity>().PropertiesAutowired();
and this works a charm if autofac is responsible for instantiating the instance like the following method shows:
public ValuesController(AEntity aEntity)
{
aEntity.Test();
}
Great it works and everything but here comes the catch when I do something like this
public ValuesController(TestContext context)
{
var a = context.AEntities.FirstOrDefault();
a.Do();
}
The ITest is not getting autowired, and I know its due to that autofac is not the instantiater or resolver, but this is something that I want to accomplish.
Any pointers and let me know if my question does not make sense.
I am using standard configuration pattern for ASP.NET Core applications and I can not bind configuration to my class as it has construtor with parameters.
In appsettings.json I included desired config:
"MyServiceConfig": {
"Identity": {
"Version": "1.0",
"ComplicatedUri": {
"Scheme": "http",
"Authority": "localhost",
"Path": "SuperService"
}
}
},
My config class and it's dependencies look like that:
public class MyServiceConfig
{
public MyIdentity Identity { get; set; }
}
public class MyIdentity
{
public string IdentityName { get; set; }
public string Version { get; set; }
public MyComplicatedUri ComplicatedProperty { get; set; }
public MyIdentity(string version, MyComplicatedUri complicatedProperty)
{
Version = version;
ComplicatedProperty = complicatedProperty;
IdentityName = complicatedProperty.Path;
}
}
public class MyComplicatedUri
{
public string Scheme { get; set; }
public string Authority { get; set; }
public string Path { get; set; }
}
I have already tried code like that:
private MyServiceConfig GetMyConfig(IConfiguration configuration)
{
var config = new MyServiceConfig();
configuration.GetSection("MyServiceConfig").Bind(config);
return config;
}
It throws exception:
'Cannot create instance of type 'MyIdentity' because it is missing
a public parameterless constructor.'
That behaviour can make sense in some cases but in that particular one not so much. Mappings could be straightforward - by property names which have public setters or by constructor parameter names.
Another idea would be adding converter in AddJsonOptions in Startup class for my types - IConfiguration.Bind could infer how to construct it but I also tried that with no success.
Have you encoutered similar problems and found some reasonable solution to that?
Edit: Adding parameterless constructor will work of course, but sometimes I need to deal with some classes from external packages I'd like to use as parts of my config class so let's assume we can not modify them. I'd like to avoid adding new types for mapping only as well. Ideally I'd like to force ASP.NET Core engine to use existing constructor with parameters and by parameter name map with json properties - which currently is not working.
You should just add a default constructor in MyIdentity class.
.bind() binds the configuration into the object using the default constructor.
So, add the required default constructor in your MyIdentity class and it will be fine.
public MyIdentity(){}
Also, you can use Options.
In ConfigureServices, add the following:
services.AddOptions();
services.ConfigureOptions<MyServiceConfig>();
and then use dependency injection to initialize it.
In addition, use your own JsonConverter
I'm trying to achieve maybe something that might be impossible.
We have a big MVC 5 application. I created a small MVC project to simulate and explain what I want to apply into that big MVC project.
I have a controller that has unique Id. In this sample project the unique Id is regenerated for each request. In the MVC project, it is a bit more complex and different. However it's not relevant in the scope of this example.
public class FooController : Controller
{
public string UniqueId = Guid.NewGuid().ToString("N");
public ActionResult Index()
{
var worker = new WorkerA();
worker.DoWork();
return View();
}
}
The FooController creates WorkerA which creates WorkerB which creates WorkerC and so on. The workers are not the same. They don't have the same interface/implementation. To make the example simple I made them look similar.
Here's the Workers:
public class WorkerA
{
public string UniqueId = string.Empty;
public void DoWork()
{
var worker = new WorkerB();
worker.DoWork();
//...
//...
}
}
public class WorkerB
{
public string UniqueId = string.Empty;
public void DoWork()
{
var worker = new WorkerC();
worker.DoWork();
}
}
I want to have inject the property UniqueId into the worker without having to passing it as a parameter.
I want to avoid having to do this:
public WorkerA(string uniqueId)
{
UniqueId = uniqueId;
}
But I need to do the same for all the other workers.
EDIT
Is there a way to acheive that with ninject?
You can achieve what you want using Microsoft.Practices.Unity in the following manner:
public class WorkerA
{
[Dependency]
public string UniqueId { get; set; }
}
public class WorkerB
{
[Dependency]
public string UniqueId { get; set; }
}
And after that :
var container = new UnityContainer();
container.RegisterType<WorkerA>(new InjectionProperty(nameof(WorkerA.UniqueId),"WorkerAValue"));
container.RegisterType<WorkerA>(new InjectionProperty(nameof(WorkerB.UniqueId), "WorkerBValue"));
Later, you can request the instances from the container with the desired properties configured:
var workerA = container.Resolve<WorkerA>();
var workerB = container.Resolve<WorkerB>();
You can do something like:
worker.GetType().GetField("prop")?.SetValue(worker, "guid");
You could create a singleton class to manage the GUID and deliver it to the child classes that way. This way you can still do it in a constructor but not have to pass it as a parameter
public class GUIDManager
{
private static GUIDManager _instance;
private Guid _activeGuid;
public Guid ActiveGuid {
get { return _activeGuid; }
set { _activeGuid = value; }
}
private GUIDManager()
{
if (_activeGuid == null)
_activeGuid = new Guid();
}
public static GUIDManager GetInstance()
{
if(_instance == null)
{
_instance = new GUIDManager();
}
return _instance;
}
}
public class WorkerB
{
public string UniqueId = string.Empty;
public WorkerB()
{
var manager = GUIDManager.GetInstance();
UniqueId = manager.ActiveGuid.ToString();
}
public void DoWork()
{
var worker = new WorkerC();
worker.DoWork();
}
}
From your question i'm not entirely clear about all the workers in the same request getting the same ID or not. If they all should get the same ID then it's simple:
Wrap the ID in a class and use InRequestScope():
public class BrowserTabId
{
public string browserTabId;
public BrowserTabId(string tabId)
{
if(string.IsNullOrEmpty(tabId))
{
throw new NullArgumentException();
}
this.browserTabId = tabId;
}
public string Id { get { return this.browserTabId; } }
}
Bind<BrowserTabId>()
.ToMethod(ctx =>
new BrowserTabId(HttpContext.Items["BrowserTabId"] as string)))
.InRequestScope();
For testability reasons you can also slap on an interface IUniqueRequestId and create the binding for that.
This will result in all workers / objects created during the same request receiveing the same BrowserTabId. If you don't want to use c-tor injection you can use property injection instead. If you don't want to inject the value all the type, then use a When(..) condition to specify when to inject and when not to. Combine this with the null-object pattern to keep ninject from complaining that it can't inject a requested type.
Property Injection
Adapt a worker as follows:
public class WorkerA
{
[Inject]
public BrowserTabId BrowserTabId { get; set; }
....
}
Note, however, for this to work, like normal constructor injection, it is necessary that either the WorkerA is instanciated by ninject or that Ninject is informed about its existence by Ninject.Inject(workerAInstance)
Scoping
Since you mention that the lifetime of the ID in your actual application is somewhat more complicated, I guess you will have to use something different than InRequestScope - maybe roll your own scope (by using InScope(...)). Or Maybe, InCallScope() is as viable alternative. However, without knowing what exactly it is what you need, it's a bit difficult to advise you properly.
We are working on a Mvc application, where we want to use dependency injection using nInject. Currently we are maintaining entities in different class library "ShopEntities" and in our mvc application we are using this entities.
Let's consider a class in ShopEntities.
namespace ShopEntities
{
public class Customers
{
public int custId {get;set;}
public string custName {get;set;}
public string Address {get;set;}
public string ShippingAddress {get;set;}
}
}
Now when we want to use it in our mvc application, we create an instance and set the properties like below,
public ActionResult Index()
{
ShopEntities.Customers cust = new ShopEntities.Customers();
cust.CustName = "Sam";
cust.IAddress = "xyz";
cust.ShippingAddress = "xyz xyx xyz";
}
How to use nInject here to avoid dependency? Further we don't want to create interfaces as this is limited in scope. Thanks in advance.
The way to abstract away the use of the Customer entity from the presentation layer is not to hide the entity itself behind an ICustomer of some sort, nor to let a DI container build it up. Hiding data objects behind an interfaces is typically not useful; interfaces are meant to abstract behavior, not data.
As NightOwl already stated, your Customer entity is runtime data and you should not use a container to build up object graphs containing runtime data.
Instead, you should hide specific business operations behind an abstraction. Such abstraction can be consumed by the presentation layer and implemented by the business layer. For instance:
public interface ICustomerServices
{
void CreateCustomer(string customerName, string homeAddress,
string shippingAddress);
void ChangeShippingAddress(Guid customerId, string shippingAddress);
}
Your controller can depend on this abstraction:
private readonly ICustomerServices customerServices;
public CustomerController(ICustomerServices customerServices) {
this.customerServices = customerServices;
}
public ActionResult Index()
{
this.customerServices.CreateCustomer("Sam", "xyz", "xyz xyz xyz");
}
Now your business layer can create an implementation for this abstraction that uses the entities internally:
public class CustomerServices : ICustomerServices
{
private readonly EntitiesContext context;
public CustomerServices(EntitiesContext context) {
this.context = context;
}
public void CreateCustomer(string customerName, string homeAddress,
string shippingAddress)
{
// NOTE that I renamed 'Customers' to 'Customer', since it holds information
// to only one customer. 'Customers' implies a collection.
Customer cust = new ShopEntities.Customer();
cust.CustName = "Sam";
cust.IAddress = "xyz";
cust.ShippingAddress = "xyz xyx xyz";
this.context.Customers.Add(cust);
this.context.SubmitChanges();
}
public void ChangeShippingAddress(...) { ... }
}
Doing this has the advantage that you can keep your presentation layer thin, but there are still quite some down sides to the shown approach, compared to alternatives. One of such alternatives is using a message based approach with SOLID design, as explained here.
If i understand you question, you should create middle business layer to convert ShopEntities to your own Entities:
namespace MyShopEntities
{
public class MyCustomers
{
public int custId {get;set;}
public string custName {get;set;}
public string Address {get;set;}
public string ShippingAddress {get;set;}
}
}
public ActionResult Index()
{
ShopEntities.Customers cust = new MyShopEntities.MyCustomers();
cust.CustName = "Sam";
cust.IAddress = "xyz";
cust.ShippingAddress = "xyz xyx xyz";
}
class BussinesModel
{
void Insert(ShopEntities.Customer customer)
{
// use ShopEntities.Customer only in wrapper
// if you later switch to another Customer dependency,
// you just change this wrapper
MyShopEntities.MyCustomers cust = new MyShopEntities.MyCustomers();
cust.CustName = customer.CustName;
cust.IAddress = customerIAddress;
cust.ShippingAddress = customer.ShippingAddress;
InsertInternal(cust);
}
void InsertInternal(MyShopEntities.MyCustomer customer)
{
// use MyCustomer for all your bussines logic
}
}