Start with plain ASP.NET MVC and a couple of free add-ins, and you'll finish with a complete non-WF workflow application with fleshed-out Identity 2 security, hierarchical data structured as a tree-based UI, parent-child views with multiple child entities, child editing in Bootstrap modals, AutoComplete dropdown lists, workflow rules built into entities, an audit trail, snapshotting, cloaking, and concurrency handling.
This course teaches a lot of asked-for solutions, like fleshing-out Identity 2 into a complete security application with all the features and functionality hinted-to but not fleshed-out in the scaffolded code; building tree structures from hierarchical data and embedding business rules for its behavior; adding server-side searching, sorting, and pagination to Index views; creating parent-child views with multiple child entity collections; adding, editing, and deleting child entities using Bootstrap modal dialogs; creating Google-like AutoComplete dropdown suggestion lists; snapshotting temporarily-related data; adding workflow rules to entities and incorporating them into a unified work list user interface; creating an embedding an audit trail of user activities; cloaking data rather than deleting it; and handling multi-user concurrency.
Adam Churvis is a software developer and quality assurance specialist with over twenty-five years of software industry experience. He is the President of Productivity Enhancement, a consulting, development, and testing firm. He works throughout the Microsoft stack but follows cool tech wherever it shows up, especially in robotics. Adam has co-authored three books on computer technology and has spoken at user groups throughout the United States.
Building Out the Identity 2 Security Framework Identity 2 was built to keep pace with the demands of stakeholders who wanted features like two-factor authentication, third-party authentication, and account validation. For the most part, Identity 2 is a great out-of-the-box solution for small- to medium-sized web applications. I say, for the most part not because it isn't robust, it is, I say this because of the way Identity 2 is woven through a website rather than isolated as a pluggable security solution. Identity 2's design makes the site it protects dependent on its structure, which becomes a bit of an obstacle when you want to integrate your application's concept of a user with Identity 2's concept of a user, and then relate that User class with your app's other classes. These Identity 2 issues, combined with certain shortcomings in Entity Framework, make structuring an app for true Domain-Driven Design nearly, if not completely impossible, when using these two technologies. There are folks who have successfully isolated the Identity 2 Security Framework from the rest of the application it was designed to serve, but this is outside the scope of this course. We're concentrating on the real-world select-the-checkbox-for-individual-accounts-and-start-coding scenario we all find ourselves in on a regular basis, and we'll build it out from there.
Creating and Using a Recursive Category Tree with Related Classes Implementing hierarchal data using an optional recursive relationship between database tables is one thing, creating a user interface for that data is another thing, and getting the rules you need to impose upon the hierarchy to work with both the model and the user interface is yet another. And all of these things never seem to naturally coalesce into a unified mechanism you can easily relate to other classes in your model. Well, we're going to make it all work using Entity Framework to handle the recursive relationship just like any other, using Bootstrap to handle the UI just like any other, and I'll show you where to put your recursion business rule code depending upon the scope of its tests.
Parent-child Views with Modals Modal dialogs have become a popular way to edit records that are contextual to the current view. Rather than going away from one view to engage a different view, modals enable developers to popup a dialog box over the current view, populate the modal with a related view, collect user input, and then return to the original view upon submitting or canceling the modal dialog. It's a much less jarring user experience, and it works better than any other technique I've come across yet. We're going to use this to great effect by placing the lists of child entities on the Parents Edit view, and then popping up model dialogs to display the child entities for adding, editing, and confirming deletion.
Using AutoComplete to Snapshot a Related Record So far we've manually entered some bogus data into Parts and Labors. It's pretty obvious that we'd rather choose these Parts and Labors from their respective catalogs, and that's exactly what we're going to do in this course module. But first, a word about the lifecycle of a relationship between two entities. Take, for example, the relationship between a work order and the customer for whom the work order is created. When you display a customer, you display the current state of that customer's properties. If the customer's address changes, displaying that customer's data as part of the work order will display the new version of the data, which is exactly what you'd expect. For perpetual data that works great, but when such perpetual data becomes involved in a transaction, the relationship becomes more complicated. That's because a transaction is an event that takes place uniquely at a specific moment in time, and must always reflect the facts at that specific moment in time forever. A great example of this is the relationship between the work order and its parts and labors. Unlike the customer's address, which for this system we're allowing to be perpetual with respect to work orders, parts and labors cannot be perpetual because if their prices change, that would corrupt all transactions made up to that moment the price changed. So for transactional data, we have to take a snapshot of what that related data looks like, and then copy it to a separate entity, effectively disconnecting the relationship between that copied data and its source, which is now free to change as necessary without affecting the transaction in which it was used, and that's exactly what we're going to do, look up from the InventoryItems table a copy of the part we want to add to a work order, make a copy of it along with additional transactional data, like the quantity being purchased, and then store that copy in the Parts table where there is no relationship defined between it and the InventoryItems table.
Implementing the Work List And now we get to the real payoff, the Work List. Everything we've done so far regarding Workflow has been to prepare us for this. As a teaser, I demoed a little of the finished application in the beginning of the course so you've already had a glimpse of what you're about to build. But what you didn't see is that the Work List handles more than just Work Orders, it handles any entity you want it to. In fact, once we get the Work List working with Work Orders, I'll create a Widget class and add that to the Work List to show you how straight forward it is.
Handling Inactive Data What do you do with data when it becomes too old to actively use anymore? You can archive it by moving it off-database. You can cloak it or you can cull it from the database. Archiving is outside the scope of this course, so I'll teach you cloaking and culling. Cloaking is hiding data, such that users think it has been deleted, but it is actually still there. To cloak data, you modify the delete action method to set the cloaked property and then save it, rather than delete the record, and then you filter out cloaked instances from parts of the user interface where you don't want cloaked data to appear. Sometimes there are good reasons to not actually delete data when you click the delete button, whether it's to comply with government regulations or to preserve legacy data. Sometimes you have to just pretend to delete data when all you're really doing is hiding it. For example, let's say that an old customer of yours has gone out of business. You're using that customer record for all manner of administrative purposes, like analytics, so you can't just delete it. You want to preserve it everywhere you need it and then just filter it out of the places you don't, like the customer's drop-down list from which you choose a customer on the work order create view. This is the essence of cloaking data. You need three things to cloak inactive data, a Boolean property named Cloaked, filters where you display cloakable entities, and an admin feature that enables physically deleting cloakable entities, such as a database script. We're going to enable customers to be cloaked, so that no further work can be started with them, but existing work that uses them can continue as normal.