-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Model bind to Interface via DI #6014
Comments
We don't look in DI by default (similar to how formatting doesn't kick in until you say |
@pranavkm Perfect thank you! |
|
@benaadams - here's a sample that someone else wrote https://github.com/Serjster/IOCModelBinderExample/tree/ASPNETRTMVersion |
You give with one hand then take away with the other 😢 |
I gave you a sample? And yeah |
|
What I really mean is that it would have been dope to be able to create a model using deserialization (like |
Wouldn't need an object mapper for simple cases though if could just use the language feature of interfaces to do it |
I wrote a post about how to model bind interfaces in the way you need: There you will find a custom binder for interfaces, and how to make validation works properly when using interfaces. |
@benaadams , anyway, I dont know if interfaces are enough to avoid object mapping at all:
I dont know if the validation behavior is correct or a kinda bug, but for sure there are classes where you need the actual runtime type be validated instead of the declared type (model binding subclasses for instance). |
Scenario: I have one microservice posting to another microservice; they both have their own data models - however they share an interface/contract for data exchange; but don't share models. So easy approach is to serialise and post the through interface; then deserialize the posted interface (and populate the rest of the local model as needed) |
@benaadams , if you dont use IQueryables forget my first point. Probably, also the validation problem is not an issue for you. Anyway, I explain better the issue of validation. Suppose, You have two interfaces, say IShort and IComplete that inherits from IShort. Suppose, also some transaction uses IShort, since you need to communicate just a few properties of IComplete. The issue is that you can't use a single class to resolve both interfaces with DI, because of the way validation works.
Obviously, since "CompleteClass" implements also IShort you might use it also for resolving IShort. However, if some of the properties of IComplete that are not contained in IShort contain [Required], then Anyway, Since one of my customer is very interested in this approach, I hope to be able to solve this problem, ie the need to use ModelMetadataType by adding some smart validation logics in the custom model binder. If I'll come up with a solution I will post it here. |
Update! The problem with server side validation takes place ONLY WHEN the interface is the root model where model binding starts. The problem being caused by the way the interface method IObjectModelValidator.Validate is defined. It doesn't accept a parameter containing the declared type of the model, so its default implementation computes this type with model.GetType(), which returns the type behind the interface instead of the interface (or the runtime subclass of a class). I can write a custom implementation of IObjectModelValidator that might solve the problem by comparing the model type, and name against the list of action parameters one may get from the ActionContext. However, this is not optimal. The optimal solution would be adding a new param to IObjectModelValidator.Validate (or defining a new interface or interface method) and then updating both the default implementation and the ParameterBinder code. |
Our system is a model validation system, not an input validation system. This means that we ensure that the model object is in a valid state, which may include properties that were not set from the model binding system. http://bradwilson.typepad.com/blog/2010/01/input-validation-vs-model-validation-in-aspnet-mvc.html It sounds like what you're asking for is fundamentally an input validation system, which we unfortunately don't have today. |
@rynowak , it is not about model versus input validation. It is more subtle, it is about what to do when an action method parameter or ViewModel property that as been declared as "Animal" is bound with a subclass, say "Dog". Should it be validated as "Animal" or as "Dog"? However, in the current implementation it happens that if "Animal" is the root model it is validated as a "Dog" , while if it is nested in the property of another class it is validated as an "Animal". So the behavior of the validation system is incoherent, and I consider it a bug. Probably, it was implicitly assumed that the run time type is always equal to the declared type, which is true if only the built-in binders are used, but may be false in case custom binders are used. So different ways to get type metadata have been mixed. Validation system should be moved toward a coherent behavior (any of the two possibilties is acceptable for me), but it is not acceptable that the way an objecy is validated depends on the way it is nested in the whole object tree. |
If this is true then yes this is a bug. It just doesn't surface through any default path, but we should address this. |
@rynowak , if this can help I have two projects with a custom model binder for interfaces. One where the interface is the root model and the other where it is nested. They show the different behaviors. If you need them I may upload them either to some cloud drive or to Github. Anyway,the simplest fix is the one outlined in my previous post about IObjectModelValidator.Validate. It follows the "Animal" path. This fix should be quite easy. Taking the other path should be more difficult instead, because it would involve a substantial rewrite of the validation visitors, and of the metadata structures they rely on. About the optimal solution, instead,, thinking more about the subject, I concluded that it should do the following ("pro arguments" are attached to each point):
The above behavior would allow both usage of interfaces in Views and custom model binders able to recognize subclasses (from the validation point of view...binder code is another stuff). However, I understand that it is quite difficult to move toward this very dfferent behavior, so probably the best compromise is an overall "animal" path. |
@benaadams , |
Reading through this thread again, I think there's value in the design idea of considering DI/Formatters/ |
I'm closing this issue because I think we've answered the concerns here, and we have no immediate plans to invest in this area. |
Requirement
I'd like to bind to a model interface via DI but it doesn't seem to work? Am I doing something wrong?
Steps to reproduce
Models
ConfigureServices
Controller Method
Expected behavior
Transient object obtained from DI; then its properties set as per non DI type
Actual behavior
/cc @DamianEdwards @rynowak
The text was updated successfully, but these errors were encountered: