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.
Related
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.
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)
Given the following types
public class User
{
public long Id { get; set; }
public string Name { get; set; }
}
public class Context : DbContext
{
public DbSet<User> Users { get; set; }
}
public interface IMyService
{
bool IsNameCool(string name);
}
I need to implement something like that
public class CoolUsersFinder
{
IMyService _myService;
private Context _context;
public CoolUsersFinder(IMyService myService, Context context)
{
_myService = myService;
_context = context;
}
public List<long> GetIdsOfCoolUsers()
{
return ???
}
}
while IMyService is implemented in a webservice, and i don't know how its implementations looks like, and i want to implement GetIdsOfCoolUsers method to return something looks like that
return context.Users.Where(U => myService.IsNameCool(U.Name) ).Select(U.ID).ToList()
While my database is really huge and i cannot get all records at once and filter them later, i need the translated code to SQL to be able to filter the data.
Is there any way to do that?
if the way you decide if a name is cool or not does not change, you can add it as column to the users table and update it when users are added or updated.
the it will be very easy to get all the cool users.
even if the way you decide if a name is cool or not changes you only need to re-calculate it once for all the users.
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.
I want to have an IDataService that I can then swap out with a different service for mocking or use for Design time data. Is this a good approach or am I just creating problems for myself.
public interface INorthwindContext
{
public IDomainContext Context;
}
I've tried using a partial class in my Silverlight project to implement an interface like so:
public partial class NorthwindContext : INorthwindContext
{
}
Now I can create a DataService or TestDataService etc, like so:
public class DataService : IDataService
{
public INorthwindContext Context { get; set; }
}
My INorthwindContext:
EDIT: unless I add all the methods from the DomaincContext to this interface I'm going to lose need functionality to lad the data. I'm also going to have to manually update the interface each time I add new entites to the service.
public interface INorthwindContext
{
EntitySet<Category> Categories { get; }
EntityQuery<Category> GetCategoriesQuery();
EntityQuery<Product> GetProductsQuery();
EntityQuery<Region> GetRegionsQuery();
EntityQuery<Shipper> GetShippersQuery();
EntityQuery<Supplier> GetSuppliersQuery();
EntityQuery<Territory> GetTerritoriesQuery();
EntitySet<Product> Products { get; }
EntitySet<Region> Regions { get; }
EntitySet<Shipper> Shippers { get; }
EntitySet<Supplier> Suppliers { get; }
EntitySet<Territory> Territories { get; }
}
This was very helpful and http://www.nikhilk.net/NET-RIA-Services-ViewModel-Pattern-2.aspx
Here's the pattern I recommend for using RIA Services with MVVM (which is a good pattern to use for mocking and design-time data). It's a take on John Papa's MVVM sample.