I’ve done a number of LOB ASP.NET MVC projects (MVC5) and would like to re-structure how I handle some things for a new project. Specifically, I have a component that I want to re-use throughout multiple places in the application.
Current Method
Let’s say I have an app that handles patient case management. Part of this would be keeping running list of loose notes/tasks on the patient. Traditionally I’d work these up as part of whatever primary area would be handling the entry of the notes: let’s say they’d go in the CaseManager
portion of the UI, and as such would fall into context within the CaseController
(and subsequently, the model and views would also be naturally “adjacent” (for lack of better word) to that controller.
Elsewhere, I might want to display a list/summary of notes as well as maybe a quickedit popup or whatever. This would generally be handled separately from the aforementioned CaseController implementation.
What I’d Like To Do
Now, I’d like to take this Notes editor/display and treat it as an embedded resource into any other view that I want. So, I’ll create a Notes controller with specific Notes models and Notes views (to keep all that stuff nicely encapsulated), then when I want to display the notes “component” in the app somewhere, I’d just send a request to the NotesController accordingly.
As such, my CaseManager is now “bound” to my CaseController, but when the user clicks the Notes tab, I want to fire up an instance of the NotesController, pass it a relevant parameter or two, then let the NotesController do the heavy lifting and return the response.
Elsewhere – not in the CaseManager – I may want to similarly embed this Notes component, and would handle it the same way: delegate the processing to a new instance of the NotesController and let it do it’s thing.
What I’ve Done
Previously, I’ve handled “lightweight” scenarios like this using httpContext.Server.TransferRequest
, which works very nicely in silently moving the request and its context to a new controller action.
I’ve followed the same path for what I’d like to do now – so my CaseController’s tab method now says return MyTransferResultWrapper("/Notes/?id=1234");
It works, but…
What I Don’t Like
… it feels wrong. It doesn’t feel right anyway. It works, but it smells to me, for reasons I can’t quite put my fingers on. It seems that if I were to evolve this approach as a “fundemental tactic” for dealing with this across this new application (which has a lot of these re-use cases), I’d be really mangling with and working against the current in terms of tossing around controller contexts and in general just doing things that maybe the framework was never really designed to handle.
Might someone be able to offer some advice on a sound approach for this type of thing?
5
This can be accomplished with Partial Views.
The partial view accepts a reference Id that is used to get the notes for a particular parent(like Case in your example) and then the Partial view always goes back to the NotesController to fetch the data.
You can now place the Partial View on any page, wire up the reference Id, and it should work.
See this for a start.
You can call your Notes controller from within other views to insert a partial view
@Html.Action("action", "controller", parameters)
However, as you say, if you have buttons in the partial view which call further actions this is going to become problematic and I don’t recommend it
Better to move the control to the client side and have an Api Controller with the relevant queries and actions.
The client side code can then populate and take actions on the control without complicating the page lifecycle and you can reuse the same partial view with the controls basic html and javascript anywhere in your application.
You might be interested in my project, FormFactory, which allows you to build your UI as a set of components https://github.com/mcintyre321/FormFactory
I do wonder if really what you are asking is a domain modelling question though. It seems you have modelled a Note as a separate aggregate from the Case, and this is giving you pause for thought.
Perhaps you should be modelling the Notes as a component and corresponding value object Type (i.e. data), and embed the note data on the case entity itself.