Inject a property (recursively) without passing it as a parameter - c#

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.

Related

C# Unity Container Constructor Injection transient lifetime manager same instance served

Problem: I have some XSD generated models that are complex and I wanted to let Unity construct them. There are many nestings and arrays of classes within classes and I'd rather not new them up.
That given if I do that and use constructor injection, it seems I'm not getting a new model every time I use the generation class. My populated list contains records where all records reference the same instance.
This example simplifies the issue:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using Unity;
namespace sandbox
{
public class Test
{
private GetTestRec _getTestRec;
public Test(GetTestRec getTestRec)
{
_getTestRec = getTestRec;
}
public void RunMe()
{
var mylist = new List<TestModel>();
var InList = new List<StructIn>();
InList.Add(new StructIn() { Name = "asd", Amount = 5.55F });
InList.Add(new StructIn() { Name = "lkj", Amount = 1.00F });
foreach (var item in InList)
{
mylist.Add(_getTestRec.Get(item));
}
foreach (var item in mylist)
{
Console.WriteLine($"{item.Name} {item.Amount}" );
}
}
}
public class GetTestRec
{
private TestModel _testModel;
public GetTestRec(TestModel testModel)
{
//_testModel = testModel;
}
public TestModel Get(StructIn structIn)
{
_testModel = UnityConfig.Container.Resolve<TestModel>();
_testModel.Name = structIn.Name;
_testModel.Amount = structIn.Amount;
return _testModel;
}
}
public class TestModel
{
public TestModel()
{ }
public string Name { get; set; }
public float Amount { get; set; }
}
public struct StructIn
{
public string Name;
public float Amount;
}
}
In the above code the TestModel is being resolved explicitly. If I resolve the GetTestRec and execute RunMe()...
var testThis = UnityConfig.Container.Resolve<Test>();
testThis.RunMe();
You can see that it correctly generates two instances of the TestModel and adds them to the list
asd 5.55
lkj 1
But if I comment out the explicit resolve and instead inject the TestModel through the constructor...
public class GetTestRec
{
private TestModel _testModel;
public GetTestRec(TestModel testModel)
{
_testModel = testModel;
}
public TestModel Get(StructIn structIn)
{
//_testModel = UnityConfig.Container.Resolve<TestModel>();
_testModel.Name = structIn.Name;
_testModel.Amount = structIn.Amount;
return _testModel;
}
}
You can see that it's only using one instance of the TestClass and all records in the list point to the same instance
lkj 1
lkj 1
How do I use the constructor injection and get a new instance every time? The default transient lifetime says it gets a new instance with every resolve and if I call resolve then I do get a new instance. But, using the constructor I don't believe resolve is called as it's already been previously resolved.
What is the best direction here? Is a Factory pattern with Unity where I should be looking?
Assuming you are looking to return new model on every call to TestModel Get (essentially replacing new TestModel with some sort of DI friendly code.
Take dependency on factory method (as in Func<TestModel>) to create them as needed. With Unity you don't need to add any special registrations to get it working - it always registers both T and Func<T> (which is simply container => container.Resolve<T>()). With other containers you may need to either manually register it or even create factory interface.
public class GetTestRec
{
private Func<TestModel> _testModelFactory;
public GetTestRec(Func<TestModel> testModelFactory)
{
_testModelFactory = testModelFactory;
}
public TestModel Get(StructIn structIn)
{
TestModel newModel = _testModelFactory();
newModel.Name = structIn.Name;
newModel.Amount = structIn.Amount;
return newModel;
}
}

C# Architecture/Pattern for Tenant-Specific Business Logic

Say you have a multi-tenant app. A Tenant has various properties:
public class Tenant{
public string TenantName {get; set;}
public string TenantUrl {get; set;}
}
This way when my service layer sends emails, for example, I can do the following:
SendEmail(Tenant.FromEmailAddress, recipientEmailAddress)
This works well for properties. In many places throughout my business logic, I'm encountering cases where tenant-specific behaviors must be accounted for. One example is retrieving photos for the homepage:
public List<string> GetPhotoUrls(){
if(currentTenant == TenantA){
// logic to go off to retrieve from one third party
} else if (currentTenant == TenantB){
// totally different logic
} else... // one for each tenant
// do some stuff
// return stuff
}
GetPhotoUrls is a simple example - but there are cases like this in many places in my business logic. I'm looking for a simple pattern where I can define and implement tenant-specific logic. The overall goal is to get all tenant-specific logic in one place so tenant creation and definition is easy.
I would like the developer experience to read along the lines of:
public List<string> GetPhotoUrls(){
currentTenant.GetPhotoUrls(); // define this logic on the tenant object somehow
// do some stuff
// return stuff
}
What patterns/constructs are available to achieve this?
Use the strategy pattern in your case. The pattern is best applied when you see switch statements or multiple if statements to simplify the client so that it delegates custom implementation to dependent interfaces. You may also use in combination of factory pattern. To illustrate this:
public interface ITenant{
List<string> GetPhotoUrls();
}
public class TenantA:ITenant{
public string TenantName {get; set;}
public string TenantUrl {get; set;}
public List<string> GetPhotoUrls(){
//A implementation
}
}
public class TenantB:ITenant{
public string TenantName {get; set;}
public string TenantUrl {get; set;}
public List<string> GetPhotoUrls(){
//B implementation
}
}
public class SomeTenantApp{
public SomeTenantApp(ITenant tenant){
_tenant = tenant;
}
public void DoSomething(){
var urls = _tenant.GetPhotoUrls();
//do something
}
}
public static class TenantFactory{
public static ITenant Create(string id)
{
//logic to get concrete tenant
return concreteTenant;
}
}
class Program
{
static void Main(string[] args)
{
var tenant = TenantFactory.Create("A");
var app = var SomeTenantApp(tenant);
app.DoSomething();
}
}
The client (SomeTenantApp) won't have to change. You delegated the implementation to the concrete class which owns the logic.
If you want to build SaaS, I'd strongly recommend using ASP.NET Core and dependency injection to overcome multi-tenancy issue.
You can defined your tenant class :
public class AppTenant
{
public string Name { get; set; }
public string[] Hostnames { get; set; }
}
Next you can resolve a tenant from the current request
public class AppTenantResolver : ITenantResolver<AppTenant>
{
IEnumerable<AppTenant> tenants = new List<AppTenant>(new[]
{
new AppTenant {
Name = "Tenant 1",
Hostnames = new[] { "localhost:6000", "localhost:6001" }
},
new AppTenant {
Name = "Tenant 2",
Hostnames = new[] { "localhost:6002" }
}
});
public async Task<TenantContext<AppTenant>> ResolveAsync(HttpContext context)
{
TenantContext<AppTenant> tenantContext = null;
// it's just a sample...
var tenant = tenants.FirstOrDefault(t =>
t.Hostnames.Any(h => h.Equals(context.Request.Host.Value.ToLower())));
if (tenant != null)
{
tenantContext = new TenantContext<AppTenant>(tenant);
}
return tenantContext;
}
}
Wiring it up :
public void ConfigureServices(IServiceCollection services)
{
services.AddMultitenancy<AppTenant, AppTenantResolver>();
}
Getting the current tenant (whenever you need it) :
public class HomeController : Controller
{
private AppTenant tenant;
public HomeController(AppTenant tenant)
{
this.tenant = tenant;
}
.
.
.
}
For more info take a look at SaasKit
Building multi-tenant applications with ASP.NET Core (ASP.NET 5)

How to define use the same model within the model

Within my SessionView model I'm trying to assign data from the database into a local variable and then assign this data to the relevant public properties (rather than doing it in the controller).
I'm trying to achieve this by using the following code, but it crashes out when the data is interrogated, presumably because I'm defining the same model within it...
public class SessionView : BaseViewModel
{
public int SessionId { get; set; }
private SessionView data
{
get
{
return (from s in db.Sessions
where s.SessionId == SessionId
select new SessionView
{
CourseId = s.CourseId
// ... lots of other properties
}).FirstOrDefault();
}
set { }
}
public int CourseId { get { return data.CourseId; } set { } }
// ... lots of other properties
}
Is there some clever way I can achieve this without erroring?
Thank you.
I think the best way is to put the data retrieval in the constructor:
In this way, everytime someone reference in this class you only retrieve data once which lessen the retrieval overhead and optimized your code.
In simpler terms, everytime I use the variable data i will query it always from the database.
public class SessionView : BaseViewModel
{
private SessionView _sessionView;
public int SessionId { get; set; }
public SessionView()
{
_sessionView = new SessionView();
_sessionView.data = from s in db.Sessions
where s.SessionId == SessionId
select new SessionView
{
CourseId = s.CourseId
// ... lots of other properties
}).FirstOrDefault();
}
private SessionView data
{
get
{
return _sessionView.data
}
set { }
}
public int CourseId { get { return data.CourseId; } set { } }
// ... lots of other properties
}
Where did you read that Controllers should be thin versus fat Models? Business logic isn't great in the controllers because it would be harder to reuse than if in a business logic tier, but don't confuse that with just database access; that definitely should stay away from the models if you can help it.
This kind of work, assigning a database value to your model - that is exactly what the controller in MVC is meant for. I would opt for something like this.
Model
public class SessionView : BaseViewModel
{
public int SessionId { get; set; }
public int CourseId { get; set; }
// ... lots of other properties
}
Controller
public class HomeController : Controller
{
public ActionResult Index(){
var context = new MyContext();
var firstSession = context.Sessions.First();
var viewModel = new SessionView
{
SessionId = firstSession.SessionId,
CourseId = firstSession.CourseId,
//keep populating here if you need
};
return View(viewModel);
}
}
I think your issue is that the data-loading on your model is actually happening in the view, which is a bad practice in MVC, instead you should do it on the controller, by using a service, something like:
public class SessionController : Controller
{
private readonly ISessionsService sessionService;
public SessionController(ISessionsService sessionsService)
{
this.sessionService = sessionService;
}
public ActionResult SessionData(int sessionId)
{
var sessionData = sessionService.GetById(sessionId);
/// do whatever validation you might require here
var model = new SessionView(sessionData); // you could even pass the sessionId if required here
return View(model);
}
}
you can get your service Dependency-Injected into your controller. I think this is the preferred way to do this on MVC

Pass parameters in constructor instead of setting propeties

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>();
}

Saving an Item in EF with existing childrens

Im having some problems saving an object (FeatureType) that have a 1-M relationship with Section.
public class FeatureType
{
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("SectionId")]
public Section Section { get; set; }
public virtual List<ItemType> ItemTypes { set; get; }
}
public class Section
{
public int Id { get; set; }
public string Name { get; set; }
public int Order { get; set; }
public virtual List<FeatureType> Features { get; set; }
}
If The ItemTypes are new i have no problem and the insert is done correctly.
But if i want to add some existing ItemTypes im getting this Error:
An entity object cannot be referenced by multiple instances of
IEntityChangeTracker.
I have been reading about this problem but i havent found a way to solve it, and it might be because of how its designed my application.
Whem im mappinig from my viewModel to my Model, im getting the section ID and getting the section Object from my SectionRepository as this:
private Section GetSection()
{
var section = _sectionRepository.GetSection(SectionId);
return section;
}
And this is what is giving me the problem, as the section is now been tracked by the SectionRepository that have its own context.
How can i solve this? I have tried just creating a new section with the existing ID but it just create me an empty object.
private Section GetSection()
{
var section = new Section{Id=SectionId};
return section;
}
UPDATE
To save my entity i just use :
_repository.Create(featureType.ToModel());
public FeatureType ToModel()
{
var ft = new FeatureType
{
Name = Name,
ControlType = (ControlType)ControlType,
Order = Order,
Required = Required,
RequiredText = RequiredText,
ItemTypes = GetItemTypes().ToList(),
Section = GetSection(),
};
return ft;
}
UPDATE 2: This is how i have my repositories, i wouldn't like to manage any EF in my controller but with some kind of repository or service.
public class EFBaseRepository
{
protected MyContext Db = new MyContext();
public void Dispose(bool disposing)
{
Db.Dispose();
}
}
public class EFFeatureTypeRepository : EFBaseRepository, IFeatureTypeRepository
{
public IQueryable<FeatureType> GetFeatureTypes
{
get { return Db.FeatureTypes.Include("Section").Include("ItemTypes"); }
}
public Message Create(FeatureType feature)
{
try
{
Db.FeatureTypes.Add(feature);
Db.SaveChanges();
return new Message();
}
catch (Exception e)
{
throw;
// return new Message(e, string.Format("Error Creating {0}", feature.GetType()));
}
}
//..Other Methods
}
You say that the SectionRepository has its own context. That is going to cause you problems. The repositories should share a context. The context is a combination of the unit of work and repository patterns. You need to separate the two patterns:
How to migrate towards unit-of-work and repository pattern
EDIT
You can avoid having the DbContext in the Controller by implementing your own Unit Of Work pattern.
public interface IUnitOfWork : IDisposable
{
ISectionRepository SectionRepository {get;}
//etc
int Save();
}
then in your controller:
public ActionResult Create(FeatureTypeCreate featureType)
{
_Uow.SectionRepository.Create(featureType.ToModel());
_Uow.Save(); //Saving is the responsibility of the Unit Of Work
//not the Repository
}
More references:
Implementing the Repository and Unit of Work
Repository and Unit of Work in Entity Framework
John Papa's original source code
Simply, the error you're getting means that the entities were returned from a different instance of your DbContext than from which they are now trying to be saved. Make sure that you're not doing something like using two different usings around your repository and that your repository always makes use of the same DbContext per instantiation.

Categories