Before everyone throws stones at me, I have searched Google / MSDN / StackOver flow for related questions and answers but none of them suited my needs.
I'm working on a rather large application in C# - Windows Forms that is currently divided into the following:
Data-Layer
Domain-Layer
UI-Layer
Basically in my current situation the roles of this layers are the following
The Data-Layer's responsability is to communicate with the data-store, basically CRUD operations.
The Domain-Layer's responsability is to hold the model of our objects, create the objects, apply business-rules etc.
The UI-Layer, well, basically this is what the user sees and interacts with.
My problem is the following:
From the UI Layer the user has access to fields like: Name, Project Name, Project Number which basically are TextBoxes, Calendars etc - all of them are UI Components.
After the input of the user I call a method named: AddExplorerNode(string name, string projectName, int projectNumber) which resides in the Domain-Layer. This method is responsible based on the passed parameters to create an ExplorerNode Object ( a "special" TreeNode ) which requires the passed parameters to actually be valid.
After the object has been created, sanitized, validated etc - the same method mentioned above passes the created object to the Data-Layer which pushes it to a Cache-Repository and then to persists it to the data-store if everything went OK in the Cache.
So until now, basically everything is separated UI -> Domain -> DataLayer.
My question is, could I replace the signature of the Domain method from
AddExplorerNode(string name, string projectName, int projectNumber) to AddExplorerNode(TreeNode node) and based on the TreeNode object and its properties, construct the actual object I need ? I'm asking this because, if the Domain-Layers knows about the UI ( in this case the TreeNode UI Component ) basically we break the separation.
For example, if next year we swap WindowsForms to a Console Application, then the project is broken due to the fact that a Console Application will not have a TreeNode UI Component.
In this case, is it better to have a domain method which takes for example 5-10 parameters ( int's, strings, etc ) and based on those parameters to create my object or to replaces the parameters with a TreeNode UI Component which ?
Thank you in advance.
#EDIT:
I am asking this question, because a colleague of mine reviewed my code and started to refactor it. By refactoring he was exposing the actual TreeNode UI Component to the Domain-Layer. My approach was AddExplorerNode(string name, string projectName, int projectNumber) etc.
You can make your own class that acts in a similar way to TreeNode without actually being a TreeNode.
class TreeNodeModel
{
public string Name { get; set; }
public string ProjectName { get; set; }
public int ProjectNumber { get; set; }
}
Then you can write a method in the UI to map (copy) TreeNodeModel to an actual TreeNode.
Related
In brief
I'm after suggestions for how best to write a .NET application that provides a design canvas that will allow a user to create an object graph.
In more detail
Imagine the following .NET POCO class
public class BuildingBlock
{
public string Name { get; set; }
public BuildingBlock? Child { get; set; }
}
You can see that someone ccould create an object graph in the following manner:
BuildingBlock start = new()
{
Name = "One",
Child = new()
{
Name = "Two",
Child = new()
{
Name = "Three"
}
}
};
But, my user is not a programmer. They need to create this, but want a nice UI where they can drag 'n' drop objects, or right-click on the screen and pick "new block" etc. For those familiar with it, it would be similar to the design canvass in the Power Virtual Agents (PVA), or the designer in SQL Server Management Studio (SSMS).
I'd of course need to validate the model - so the Name property may have rules around it, such as it must be no longer than 5 characters, and can't contain numbers (simple for a Regex test). I may have a rule that the object graph can only be 12 objects "deep".
This program could save a serialized version of the object graph (xml, json etc). So also, it could read in this serialized file and paint a representation on the canvas for further editing.
Obviously my actual class would be far more complex than the one shown, but you hopefully get the gist.
What would be the best way to approach this, from a .NET perspective? I'm not sure which libraries etc I should look at. This could be a desktop app, or web/blazor.
Look up a tutorial on WinForms TreeView control which supports drag and drop, and context menus. What you will learn will be translatable to other UIs. As Henk mentioned, you need a collection of child nodes List<BuildingBlock> Children, not just a single BuildingBlock? Child.
If you want to record this in a relational database, each node will need to record a reference to its parent, e.g. Guid? ParentId.
So, i decided to learn DDD as it seems to solve some architectural problems i have been facing. While there are lots of videos and sample blogs, i have not encountered one that guides me to solve the following scenario:
Suppose i have the entity
public class EventOrganizer : IEntity
{
public Guid Id { get; }
public string Name { get; }
public PhoneNumber PrimaryPhone { get; }
public PhoneNumber AlternatePhone { get; private set; }
public Email Email { get; private set; }
public EventOrganizer(string name, PhoneNumber primaryPhoneNr)
{
#region validations
if (primaryPhoneNr == null) throw new ArgumentNullException(nameof(primaryPhoneNr));
//validates minimum length, nullity and special characters
Validator.AsPersonName(name);
#endregion
Id = new Guid();
Name = name;
PrimaryPhone = primaryPhoneNr;
}
}
My problem is: suppose this will be converted and fed to a MVC view and the user wants to update the AlternatePhone, the Email and a lot of other properties that make sense to exist within this entity for the given bounded context (not shown for brevity)
I understand that the correct guidance is to have a method for each operation, but (AND I KNOW ITS KINDA OF ANTI-PATTERN) i cant help but wonder if this wont end up triggering multiple update calls on the database.
How is this handled ? somewhere down the line, will there be something that maps my EventOrganizer to something - say DbEventOrganizer and gathers all changes made to the domain entity and apply those in a single go?
DDD is better suited for task-based UIs. What you describe is very CRUD-oriented. In your case, individual properties are treated as independent data fields where one or many of these can be updated by a single generic business operation (update).
You will have to perform a deeper analysis of your domain than this if you want to be successfull with DDD.
Why would someone update all those fields together? What implicit business operation is the user trying to achieve by doing that? Is there a more concrete business process that is expressed by changing PrimaryPhone, AlternatePhone and Email together?
Perhaps that is changing the ContactInformation of an EventOrganizer? If that's the case then you could model a single ChangeContactInformation operation on EventOrganizer. Your UI would then send a ChangeContactInformation command rather than an update command.
As for the persistence of your aggregate roots (AR), this is usually handled by an ORM like NHibernate if you are using a RDBMS. However, there are other ways to persist your ARs like Event Sourcing, NoSQL DBs and even storing JSON or any other data inter-change formats in a RDBMS.
You question is quite broad!
EventOrganizer itself should not be updating anything. You should keep your update code quite separate from the entity. A different class would take an EventOrganizer object and update the DB. This is called 'persistence ignorance' and makes the code a lot more modular and cohesive.
It would be common to create a View Model - a class whose purpose is to provide the View with the exact data it needs in the exact form it needs. You would need to create the View Model from your EventOrganizer, after which the View can update it - programmatically or with binding. When you're ready to save the changes, you'll need to update your EventOrganizer from the View Model and pass it onto the updater. This seems like a layer you don't need when the project is small and simple, but it is becomes invaluable as the complexity builds.
I am creating a generic Windows Form that accepts T and uses reflection with custom attributes to create labels and input controls at run-time.
Example:
class GenericForm<T>: Form where T : ICloneable<T>
{
}
Here's a link to a previous question for the form code: SO Question.
This form could accept the following entity class as an example:
class Vehicle: ICloneable<Vehicle>
{
public int Id { get; set; }
public int Name { get; set; }
public int Description { get; set; }
}
As you could imagine, the magic behind the form would use reflection to determine data types, validation criteria, preferred control types to use, etc.
Rather than re-inventing the wheel, I thought it would be worth asking on SO if anyone knows of such frameworks. Needless to say, I'm looking for something simple rather than a bulky framework.
eXpressApp Framework (XAF) can generate UI on the fly. In a simple case, a programmer will create business entities only, and will not care of UI at all.
As far as I know, there are no frameworks that generate the UI code at runtime. There are plenty of tools (code-generators) that do this before. But you wouldn't have the advantage of "only" changing the code - you'd had an extra step where you would need to start the code generator.
If you really want to create the UI information at runtime - I'd generate Attributes for your properties, that would tell your UI generator how to deal with this property (if no Attribute is given - have a default for your datatypes). It's a lot of coding but could save you time for small to medium projects in the future.
Another thing you could do is to externalize your UI information into an XML file and have a generator for that one. There's actually a framework that does that - have a look at the re-motion framework. I don't know if the part of the UI is free but it has some functionality (i.e. mixins) that could help you fulfilling your task.
If I have an aggregate root which consists of say:
class Parent
{
IEnumerable<Child> Children{ get; set; }
}
Children could contain any number of possible Child objects which are stored in the database.
What would be the best way of getting a total list of all Child objects to the application, so they can be presented in a UI allowing a user to attach/remove them from the Parent object?
Having a method in Parent such as
class Parent
{
IEnumerable<Children> GetAllChildObjects { get; set; }
}
would surely corrupt the model with implementation details?
Would it be ok to have a domain service which calls the Parent repository and retrieves a full list. The facade to the application could then call the service directly, ensuring the Parent model stays "pure".
Update:
To give a bit more detail, i'm tidying up a system and trying to give it some structure.
A User can hold a number of WorkLocations. WorkLocations are pretty simple. The current system contains a webpage which displays user details including a full list of valid WorkLocations. Selecting locations from the list updates the User model with the new locations.
Currently, the UI pretty much hits the DB and pulls out the full list of WorkLocations. I need to pull this back into a more structured form.
Or, does this suggest that WorkLocation should not be in the User root as it currently is?
Am I correct in thinking that you want all the WorkLocations from the database, regardless of what User they are attached to (if any)?
If so I would definitely go for the service approach, something like:
public interface IWorkLocationsService
{
IEnumerable<WorkLocation> GetAllWorkLocations();
}
You might want WorkLocation to be immutable so that all changes to them go through User, though I suspect this isn't necessary here.
Update:
You could then add the following methods to User
// This gets filled from the db somehow.
private IList<WorkLocation> workLocations;
// IEnumerable so that all external additions and
// removals must go through dedicated methods.
public IEnumerable<WorkLocation> WorkLocations
{
get { return workLocations; }
}
public void AddWorkLocation(WorkLocation locationToAdd)
{
workLocations.Add(locationToAdd);
// Do whatever else you need to, i.e. mark the item for saving.
}
public void RemoveWorkLocation(WorkLocation locationToRemove)
{
workLocations.Remove(locationToRemove);
// Do whatever else you need to, i.e. mark the item for saving.
}
If you really must get the list of SonOfFoo for some reason, by using simple high level interfaces such as IEnumerable, you're not corrupting the model with implementation details.
Depending on what you need done, it would be better to avoid getting a list of SonOfFoo though, having Foo manage the work would be better.
Also depending on the amount of details SonOfFoo has, it would be a good idea to encapsulate it on an interface with the methods that the UI/Facade would need to use.
Edit:
From your description, the UI needs a list of the WorkLocations a user can work at (a IEnumarable would be a good choice), and then after the user selects the location and confirms it, the UI notifies the control the switch of the user with the selected location.
I have a two part application. One part is a web application (C# 4.0) which runs on a hosted machine with a hosted MSSQL database. That's nice and standard. The other part is a Windows Application that runs locally on our network and accesses both our main database (Advantage) and the web database. The website has no way to access the Advantage database.
Currently this setup works just fine (provided the network is working), but we're now in the process of rebuilding the website and upgrading it from a Web Forms /.NET 2.0 / VB site to a MVC3 / .NET 4.0 / C# site. As part of the rebuild, we're adding a number of new tables where the internal database has all the data, and the web database has a subset thereof.
In the internal application, tables in the database are represented by classes which use reflection and attribute flags to populate themselves. For example:
[AdvantageTable("warranty")]
public class Warranty : AdvantageTable
{
[Advantage("id", IsKey = true)]
public int programID;
[Advantage("w_cost")]
public decimal cost;
[Advantage("w_price")]
public decimal price;
public Warranty(int id)
{
this.programID = id;
Initialize();
}
}
The AdvantageTable class's Initialize() method uses reflection to build a query based on all the keys and their values, and then populates each field based on the database column specified. Updates work similarly - We call AdvantageTable.Update() on whichever object, and it handles all the database writes. It works quite well, hides all the standard CRUD, and lets us rapidly create new classes when we add a new table. We'd rather not change it, but I'm not going to entirely rule it out if there's a solution that would require it.
The web database needs to have this table, but doesn't have a need for the cost data. I could create a separate class that's backed by the web database (via stored procedures, reflection, LINQ-TO-SQL, ADO data objects, etc), but there may be other functionality in the Warranty object which I want to behave the same way regardless of whether it's called from the website or the internal app, without the need to maintain two sets of code. For example, we might change the logic of how we decide which warranty applies to a product - I want to need to create and test that in only one place, not two.
So my question is: Can anyone think of a good way to allow this class to sometimes be populated from the Advantage database and sometimes the web database? It's not just a matter of connection strings, because they have two very different methods of access (even aside from the reflection). I considered adding [Web("id")] type tags to the Advantage tags, and only putting them on the fields which exist in the web database to designate its columns, then having a switch of some kind to control which set of logic is used for reading/writing, but I have the feeling that that would get painful (Is this method web-safe? How do I set the flag before instantiating it?). So I have no ideas I like and suspect there's a solution I'm not even aware exists. Any input?
I think the fundamental issue is that you want to put business logic in the Warranty object, which is a data layer object. What you really want to do is have a common data contract (could be an interface in this case) that both data sources support, with logic encapsulated in a separate class/layer that can operate with either data source. This side-steps the issue of having a single data class attempt to operate with two different data sources by establishing a common data contract that your business layer can use, regardless of how the data is pulled.
So, with your example, you might have an AdvantageWarranty and WebWarranty, both of which implement IWarranty. You have a separate WarrantyValidator class that can operate on any IWarranty to tell you whether the warranty is still valid for given conditions. Incidentally, this gives you a nice way to stub out your data if you want to unit test your business logic in the WarrantyValidator class.
The solution I eventually came up with was two-fold. First, I used Linq-to-sql to generate objects for each web table. Then, I derived a new class from AdvantageTable called AdvantageWebTable<TABLEOBJECT>, which contains the web specific code, and added web specific attributes. So now the class looks like this:
[AdvantageTable("warranty")]
public class Warranty : AdvantageWebTable<WebObjs.Warranty>
{
[Advantage("id", IsKey = true)][Web("ID", IsKey = true)]
public int programID;
[Advantage("w_cost")][Web("Cost")]
public decimal cost;
[Advantage("w_price")][Web("Price")]
public decimal price;
public Warranty(int id)
{
this.programID = id;
Initialize();
}
}
There's also hooks for populating web-only fields right before saving to the web database, and there will be (but isn't yet since I haven't needed it) a LoadFromWeb() function which uses reflection to populate the fields.