I am using a Typed Factory supplied by Windsor Castle DI container. I am quite new to DI containers, so am after a bit of guidance with my solution.
Here is my implementation:
*updated registration & DB call
public interface IAgent { }
public class Agent : IAgent { }
public interface IAgentFactory
{
IAgent Create();
IAgent Create(int agentId);
IAgent Create(AgentDTO agentDTO);
}
class AgentFactory : IAgentFactory
{
public IAgent Create()
{
return InitNewEntity(new Agent());
}
public IAgent Create(int agentId, IDBContext dbContext) //Not happy with this, as it's a dependency that isn't factored out :(
{
return dbContext.GetAgent(agentId);
}
public IAgent Create(AgentDTO agentDTO)
{
Agent agent = InitNewEntity(new Agent());
agent.ParseDTO(agentDTO);
return agent;
}
private IAgent InitNewEntity(IAgent agent)
{
agent.Username = ""; /// + other fields to initialise
agent.DOB = DateTime.Now; /// etc.
return agent;
}
...
Container.AddFacility<TypedFactoryFacility>()
.Register( Component.For<IAgentFactory>()
.ImplementedBy<AgentFactory>());
which I'm using the following call to get some entities
IAgentFactory agentFactory = ViewModel.Container.Resolve<IAgentFactory>();
IAgent agent = agentFactory.Create(); //Creates new Agent entity
agent = agentFactory.Create(66, dbContext); //Looks up entity in database, don't like passing in a db context, another dependency
agent = agentFactory.Create(agentDTO); //Creates Agent entity from DTO object
I have several concerns about this.
There are 3 possible scenarios regarding creating a new Agent,
1: Create a new agent from scratch
2: Create an agent using an existing DTO (Data Transfer Object)
3: Create an agent with a call to the database.
I decided to put all this functionality into a factory, as it seems to fit the bill, however, I am not entirely sure if this is the correct or best way to accomplish this.
The question is, is it possible to leverage all 3 Create scenarios into the DI container Register statement and omit the concrete factory implementation altogether, so that I no longer have an AgentFactory class, but only the IAgentFactory interface.
Another question I have regarding this implementation, is it possible to do a call, such that if I request an Agent entity, Windsor will first make a call to the factory and return the entity created from the factory, rather than create the entity without referencing the factory.
ie.
IAgent agent = Container.Resolve<IAgent>(66);
With a Callstack:
Container -> AgentFactory -> Create(66) -> returns agent from factory.
Which Windsor will intercept and automatically use the factory to create the instance. However, I tried this and it didn't use the factory to create it, it just went ahead and created the Agent without referencing the factory.
I did have this, but it doesn't call the factory methods that I have defined.
Container.AddFacility<TypedFactoryFacility>()
.Register(Component.For<IAgentFactory>().AsFactory(),
Component.For<IAgent>().ImplementedBy<Agent>());
Advice is appreciated, thank you.
Typed Factory is designed to create "behaviour" instance, not "data" instance.
You do not register into the container a "model" component, but compenent to work w/ the model.
In other words you register into the container everything but the model.
You AgentFactory has to be registerted into the container, but that's not a "Typed Factory".
You may use TF for "late dependency" purpose.
I prefer be more decoupled w/ my design and also more "single responsability" oriented.
AgentFactory won't hide a repository (as per your Create from db) within the factory: I will pass a datareader as Create parameter instead.
Related
The project I'm working on deals with quite complex business rules, so I'm trying to apply DDD. Unfortunately, I have to work with a legacy database I cannot get rid of, and I'm having trouble keeping a clean Domain Design.
Lets say some Entity, has some ValueType as primary key, which is required. This could be designed in DDD like the following:
public class Entity
{
public Entity(ValueType key)
{
Key = key;
}
public ValueType Key { get; }
}
Now, lets say this key is actually stored as a string representation, which can be parsed to construct the ValueType. I could do something like this, to make it work with Entity Framework:
public class Entity
{
private Entity()
{
//Private empty ctor for EF
}
public Entity(ValueType key)
{
StoredKey = key.ToString();
}
public ValueType Key => ValueType.Parse(StoredKey);
//DB representation of the key, setter for EF
private string StoredKey { get; set; }
}
This way, I feel I'm kind of polluting my Domain Design with storage concerns. For what the Domain cares, the Entity could be persisted just in memory, so this string internal representation feels weird.
This is a very simple scenario to show an example, but things can actually get really worse. I would like to know if there is any way to achieve persistance ignorance in the model with this simple example, so I can start thinking later about how to design more complex scenarios.
The domain model doesn't need to follow the entity framework structure. What you can do is to create 2 types of models. One pure domain models and when passing it to the repository to persist it transform it into entity framework model. And when fetching the model you can do the inverse transformation.
You can achieve persistance ignorance in this instance. Your instincts are right, get rid of all persistance concerns from your domain model, move them entirely within your dal where they belong.
DB.sql:
create table entity {
id nvarchar(50) not null primary key,
fields nvarchar(max) /*Look mum, NoSql inside sql! (please dont do this) */
}
Domain.dll:
class Entity {
/*optional - you are going to need some way of 'restoring' a persisted domain entity - how you do this is up to your own conventions */
public Entity(ValueType key, ValueObjects.EntityAttributes attributes) {Key=key;Attributes=attributes;}
public ValueType Key { get; }
public ValueObjects.EntityAttributes Attributes { get; }
/* domain functions below */
}
IEntityRepository {
public Update(Domain.Entity enity);
public Fetch(ValueType Key);
}
now ALL persistance work can go in your DAL, includeing the translation. I havent done EF in a while so treat the below
as sudo code only.
DAL (EF):
/* this class lives in your DAL, and can be private, no other project needs to know about this class */
class Entity :{
public string EntityId {get;set;}
public string Fields {get;set;}
}
class EntityRepository : BaseRepository, Domain.IEntityRepository {
public EntityRepository(DBContext context) {
base.Context = context;
}
public Domain.Entity Fetch(ValueType key) {
string id = key.ToString();
var efEntity = base.Context.Entitys.SingleOrDefault(e => e.Id == id);
return MapToDomain(efEntity);
}
/*Note: Handle mapping as you want, this is for example only*/
private Domain.Entity MapToDomain(EF.Entity efEntity) {
if (efEntity==null) return null;
return new Domain.Entity(
ValueType.Parse(efEntity.Id),
SomeSerializer.Deserialize<ValueObjects.EntityAttributes>(efEntity.Fields) /*every time you do this, a puppy hurts its paw*/
);
}
public Domain.Entity Update(Domain.Entity domainEntity) {
string id = key.ToString();
var efEntity = MapToEf(domainEntity);
base.Context.Entities.Attach(efEntity);
base.Context.Entity(efEntity).State=EntityState.Modified;
base.Context.SaveChanges();
}
private Domain.Entity MapToEf(Domain.Entity domainEntity) {
return new EF.Entity(
Id = domainEntity.Key.ToString(),
Fields = SomeSerializer.Serialize(domainEntity.Attributes) /*stahp!*/
);
}
}
The takeaway thing here is that you are going to need to do Mapping of some sort. This all but unavoidable unless your domain is realy simple and your ORM is super fancy, but even then I would recommend keeping your ORM models seperate to your Domain models because they solving 2 different problems (ORMS are providing a code version of your database model, DDD are providing a code version of you Business Models). If you are compromising your Domain Model (ie, making properties public set ) to cater for your DAL then step back and re evaluate. Obviously compromise where appropriate but realise this means you are introducing (implied) dependancies across your application layers.
You next quetion in realtion to performance (but mapping is so slow) was answered by Constantin Galbenu, have seperate 'read' models and reposistories for lists, searches. Do you really need to pull back 1000's of business models just to populate a search result list (and then have the tempation to add properties of no concern to the business model because 'the search page needs this one bit of data for the finaince people'). You should only be pulling out our domain model when you are doing some sort of business action, otherwise some nice anemica read only views are your friend.
As many suggested in the comments, CQRS is a good choice for complex business rules. It has the great advantage that you can have different models for each side (write/command and read/query). In this way you separate the concerns. This is also very good because the business logic for the write side differs from the read side's but enough with the advantages of CQRS.
...Unfortunately, I have to work with a legacy database I cannot get rid of...
Your new Write model, the Aggregate, will be responsible for handling commands. This means that the legacy model will be relieved of this responsibility; it will be used only for queries. And to keep it up-to-date you can create a LegacyReadModelUpdater that is subscribed to all Domain events generated by the new Aggregate and it will project them to the old model in an eventually consistent manner.
Suppose I have an interface IStorage and multiple implementations of it, e.g.:
class FileStorage : IStorage
{
public FileStorage(string filePath)
{
}
}
class HttpStorage : Storage
{
public HttpStorage(IHttpClient httpClient)
{
}
}
Now I have multiple classes that I want to register in my application and each of them needs a different IStorage instance.
All instances of ClassA (implementing and registered via IClassA) need a singleton FileStorage with "C:\Temp\foo.txt" as filePath.
All instances of ClassB (implementing and registered via IClassB) need a singleton FileStorage with "C:\Temp\bar.txt" as filePath.
All instances of ClassC (implementing and registered via IClassC) need a singleton HttpStorage with the registered singleton of IHttpClient.
How can I achieve the above without falling back to creating most of the dependency graph manually?
The primary question to ask every time you think you need this is: Do I violate the Liskov Substitution Principle. You are breaking the LSP in case the implementations aren't interchangeable for one another. If ClassA breaks when you inject an HttpStorage into it, you are breaking the LSP. In that case, you should give each implementation each own abstraction, such as IFileStorage and IHttpStorage.
My first impression is that you are not violating LSP. Simple Injector v3 contains a RegisterConditional method that allows you to do conditional registrations. With Simple Injector v3.1 you can make the registration as follows:
Lifestyle transient = Lifestyle.Transient;
container.RegisterConditional(typeof(IStorage),
transient.CreateRegistration(() => new FileStorage(#"C:\Temp\foo.txt"), container),
c => c.Consumer.ImplementationType == typeof(ClassA));
container.RegisterConditional(typeof(IStorage),
transient.CreateRegistration(() => new FileStorage(#"C:\Temp\bar.txt"), container),
c => c.Consumer.ImplementationType == typeof(ClassB));
container.RegisterConditional(typeof(IStorage),
transient.CreateRegistration(() => new HttpStorage(new HttpClient()), container),
c => c.Consumer.ImplementationType == typeof(ClassC));
The RegisterConditional overload that accepts an Registration instance is new in v3.1.
I am specifically using breezejs and the server code for breeze js converts the dbcontext into a form which is useable on the clientside using EdmxWriter.WriteEdmx. There are many properties which I have added JsonIgnore attributes to so that they don't get passed to the client side. However, the metadata that is generated (and passed to the clientside) from EdmxWriter.WriteEdmx still has those properties. Is there any additional attribute that I can add to those properties that I want ignored so that they are ignored by EdmxWriter.WriteEdmx? Or, would I need to make a separate method so as not to have any other unintended side effects.
You can sub-class your DbContext with a more restrictive variant that you use solely for metadata generation. You can continue to use your base context for persistence purposes.
The DocCode sample illustrates this technique with its NorthwindMetadataContext which hides the UserSessionId property from the metadata.
It's just a few extra lines of code that do the trick.
public class NorthwindMetadataContext : NorthwindContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Hide from clients
modelBuilder.Entity<Customer>().Ignore(t => t.CustomerID_OLD);
// Ignore UserSessionId in metadata (but keep it in base DbContext)
modelBuilder.Entity<Customer>().Ignore(t => t.UserSessionId);
modelBuilder.Entity<Employee>().Ignore(t => t.UserSessionId);
modelBuilder.Entity<Order>().Ignore(t => t.UserSessionId);
// ... more of the same ...
}
}
The Web API controller delegates to the NorthwindRepository where you'll see that the Metadata property gets metadata from the NorthwindMetadataContext while the other repository members reference an EFContextProvider for the full NorthwindContext.
public class NorthwindRepository
{
public NorthwindRepository()
{
_contextProvider = new EFContextProvider<NorthwindContext>();
}
public string Metadata
{
get
{
// Returns metadata from a dedicated DbContext that is different from
// the DbContext used for other operations
// See NorthwindMetadataContext for more about the scenario behind this.
var metaContextProvider = new EFContextProvider<NorthwindMetadataContext>();
return metaContextProvider.Metadata();
}
}
public SaveResult SaveChanges(JObject saveBundle)
{
PrepareSaveGuard();
return _contextProvider.SaveChanges(saveBundle);
}
public IQueryable<Category> Categories {
get { return Context.Categories; }
}
// ... more members ...
}
Pretty clever, eh?
Just remember that the UserSessionId is still on the server-side class model and could be set by a rogue client's saveChanges requests. DocCode guards against that risk in its SaveChanges validation processing.
You can sub-class your DbContext with a more restrictive variant that you use solely for metadata generation. You can continue to use your base context for persistence purposes.
The DocCode sample illustrates this technique with its NorthwindMetadataContext which hides the UserSessionId property from the metadata.
It's just a few extra lines of code that do the trick.
The Web API controller delegates to the NorthwindRepository where you'll see that the Metadata property gets metadata from the NorthwindMetadataContext while the other repository members reference an EFContextProvider for the full NorthwindContext.
Pretty clever, eh?
If you use the [NotMapped] attribute on a property, then it should be ignored by the EDMX process.
My PLUGIN is firing on Entity A and in my code I am invoking a web service that returns an XML file with some attributes (attr1,attr2,attr3 etc ...) for Entity B including GUID.
I need to update Entity B using the attributes I received from the web service.
Can I use Service Context Class (SaveChanges) or what is the best way to accomplish my task please?
I would appreciate it if you provide an example.
There is no reason you need to use a service context in this instance. Here is basic example of how I would solve this requirement. You'll obviously need to update this code to use the appropriate entities, implement your external web service call, and handle the field updates. In addition, this does not have any error checking or handling as should be included for production code.
I made an assumption you were using the early-bound entity classes, if not you'll need to update the code to use the generic Entity().
class UpdateAnotherEntity : IPlugin
{
private const string TARGET = "Target";
public void Execute(IServiceProvider serviceProvider)
{
//PluginSetup is an abstraction from: http://nicknow.net/dynamics-crm-2011-abstracting-plugin-setup/
var p = new PluginSetup(serviceProvider);
var target = ((Entity) p.Context.InputParameters[TARGET]).ToEntity<Account>();
var updateEntityAndXml = GetRelatedRecordAndXml(target);
var relatedContactEntity =
p.Service.Retrieve(Contact.EntityLogicalName, updateEntityAndXml.Item1, new ColumnSet(true)).ToEntity<Contact>();
UpdateContactEntityWithXml(relatedContactEntity, updateEntityAndXml.Item2);
p.Service.Update(relatedContactEntity);
}
private static void UpdateContactEntityWithXml(Contact relatedEntity, XmlDocument xmlDocument)
{
throw new NotImplementedException("UpdateContactEntityWithXml");
}
private static Tuple<Guid, XmlDocument> GetRelatedRecordAndXml(Account target)
{
throw new NotImplementedException("GetRelatedRecordAndXml");
}
}
I have the need to extend Service/IService to allow me to register additional resources like other DB connections and custom classes that each individual service may need to get a handle to.
Is the proper way to do this to subclass Service? Also, it is not clear to me if I have another (say) IDbConnection how Funq figures out which Property to inject the value into.
If you have multiple services with the same type you need to register them in funq with a name. Unfortunatly I don't think funq can autowire the properties correctly so you need to manually resolve them.
container.Register<DataContext>("Security", x => new SecurityDataContext());
container.Register<DataContext>("Customers", x => new CustomersDataContext());
container.Register<DataContext>("Reporting", x => new ReportingDataContext());
container.Register<IReportRepository>(x => new ReportRepositoryImpl(x.ResolveNamed<DataContext>("Reporting")));
An alternative approach would be to create a unique interface (even if it has no members) for each type and then use that in funq. This would allow autowiring
container.Register<ISecurityDataContext>(x => new SecurityDataContext());
container.Register<ICustomersDataContext>(x => new CustomersDataContext());
container.Register<IReportingDataContext>(x => new ReportingDataContext());
// this could just be autowired
container.Register<IReportRepository>(x => new ReportRepositoryImpl(x.Resolve<IReportingDataContext>()));
If you still really need to extend Service you can just use standard inheritance in c#
public abstract class BaseService : Service
{
// custom things go here
public string Example() {
return "Hello World";
}
}
public class ReportsService : BaseService
{
public string Get(ListReports request) {
return Example();
}
}
You can configure other DB connections easily without extending the Service , but by just wiring them in the configure method in the AppHost.cs file.