Add support for advanced usage using the controller pattern
See original GitHub issueSplit from #116
POC branch: https://github.com/tusdotnet/tusdotnet/tree/POC/controller-pattern
This issue needs refinement. See earlier discussions in #116 . When implementing this issue we also need to add support for dependency injection, i.e. services.AddTus()
.
Issue Analytics
- State:
- Created 2 years ago
- Comments:20 (6 by maintainers)
Top Results From Across the Web
What is controller pattern
Controller is great pattern which could help you to make you application better, scalable and make logic cleaner, but are you sure you...
Read more >Front Controller - Core J2EE Patterns
Learn about the Front Controller J2EE pattern. ... Use a controller as the initial point of contact for handling a request. The controller...
Read more >MVC Design Pattern
The Model View Controller (MVC) design pattern specifies that an application consist of a data model, presentation information, and control ...
Read more >15.3 Implementing Controllers
Controllers interpret user input and transform it into a model that is represented ... Use the spring-context schema as shown in the following...
Read more >Model-View-Controller design pattern
The model-view-controller (MVC) design pattern specifies that an application consist of a data model, presentation information, and control information.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
First of all, thanks for your feedback 😃 I agreed with many of your suggestions and implemented them in my last commits to the POC
Addressing your comments
Agreed. I implemented this in my last commits
Agreed and removed 😃
Being able to announce extensions independently from TusStore was the reason why i intruduced this feature in the first place. For example, if you want to disable the termination extension but want to keep using TusDiskStore, how would you do it? Just failing all termination requests while still announcing termination extension doesnt really seem like a good idea to me.
The intended usage of
[TusController]
attribute is for assembly scanning to be able to tell base-classes and implementations apart and for users to disable a controller by removing the attribute. For example if a user creates his own abstract class fromTusControllerBase
, assembly scanning is able to detect and ignore it, because the[TusController]
attribute is missing. Btw i named itTusControllerBase
to match the naming convention of MVC’sControllerBase
, but i dont mind to change that, if you dont like it.I completely agree 😃 I’ve made the TusController methods virtual in my latest commits
Agreed
The idea is to seperate validation into two parts.
Here is an example: The Requirement
new UploadOffset()
checks if a request is malformed, therefore it should be executed inIntentHandler
. The Requirementnew FileExist()
checks if a storage operation is invalid, therefore it should be executed inStorageClient
.This has following advantages:
I think it could indeed be useful for some users who want to return some json when the upload is finshed for example. I think we can discuss it at a later time
I think it would be pretty difficult tu ensure it is compliant with tus spec. For example ho can we prevent an user from returning the wrong IActionResult or ensure all headers have been set correctly? Also, a regular controller has a 1:1 request to action mapping, which makes it difficult to implement CreationWithUpload or Concatenation.
I dont see minimal apis as an replacement for controllers, but rather as an addition to simplify the creation of small applications. Also this poc already kind of supports minimal apis:
Note: In one of the next sections i explain in depth why i think that the controller pattern is still a good idea.
Current design
Configuration
Storage
I decided to implement a kind of “named clients” pattern to access storage
To register your storage:
The
isDefault: true
means, that evey tus controller uses this storage by default, if nothing else is configured. Thats it, now you can use it in a controller:To access your storage in DI services, inject
ITusStorageClientProvider
and then do:Controllers
Registering a controller is still as simple as doing
You can configure more options by doing:
Alternatively you can configure the options using attributes:
Controller alternative
If users dont want to write a controller, they can use this simpler abstraction: (which uses
EventsBasedTusController
)Examples of tus controllers
Simplest Tus Controller
Using database in a tus controller
Why controller pattern?
In this section i want to explain why i advocate for a controller pattern and change the current design. This may sound overly negative about the current design which is not my intent 😃 I created the following diagram that will help me illustrate what i mean. (correct me if i’m wrong)
I see the following problems with this design:
Intent Handlers have both protocol logic and storage logic (for example file expiration)
This should be seperated to increase modularity.User Application Logic is not part of the Request Flow (left to right). Instead, it is a outside observer, only communicating through Events, Callbacks and special classes like IFileIdProvider.
This adds unneccessary complexity. Making User Application Logic a part of the Request Flow will fix this while giving the user code additional control.One big options class for everything, regardless of the scope, is subobtimal.
Every scope should have their own options. Options should be configured once and not depend on some callback.Everything uses ITusStore
In many classes there is a dependency on TusStore, that isnt really needed. Validation, Configuration and even the Intent Handlers and Protocol Handlers depend on TusStore.Here is how the new design solves this:
Here is the diagram of the tus controller architecture used in my commit:
User code is now part of the request flow (left to right)
Removes the unnesecary need for events. Allows the users to intercept requests and change default behaiviur easily, without having to rewrite TusStore code and open unneccesary issues. Gives user appplication code more powerOptions classes have been split up and moved to different scopes
Removes the unnesecary need for option callbacks and simplifies configurationIntentHandlers, Protocol Handler and Request Validation do not depend on TusStore anymore
Increases Modularity and users can now implement new features using TusController without needing changes to the TusDiskStoreSeperation of concerns
IntentHandlers+Validation have been seperated from storage logic:(Note: In my commit, IntentHandlers are named RequestHanlders and StorageService is named StorageClient)
What are your thoughts about this?
@smatsson Any update on this?