Mvc: Model binder with constructor

Created on 18 May 2015  路  11Comments  路  Source: aspnet/Mvc

I think it would be awesome if modelbinder do binder with constructor, too. I am use an custom model binder and this small library https://github.com/juliano/Ioget for do it!

0 - Backlog duplicate enhancement feature feature-Model-Binding

Most helpful comment

Let's not turn this (or anything else) into appeals to authority; arguments should speak for themselves (although often they build on other arguments, recursively).

IIRC, the first time I touched on the subject of Dependency Injection into 'model' classes was back in early 2010. Later, I expanded my thoughts into an article that argues that at the boundaries, applications aren't object-oriented.

If boundary code like 'models' can't be object-oriented, but should rather be viewed as 'dumb' data, then attempting to enable Dependency Injection for Data Transfer Objects (DTOs) would go counter to that.

That said, support for immutable DTOs would make me happy, but that's a slightly different discussion.

All 11 comments

@juliano, @mfpalladino can you guys shed some insights, how one can pursue this one in Mvc repo? Would you like to send a PR for this? :smile:

1786

@jasonwilliams200OK I've created Ioget seeking a way to instantiate objects by constructor, it is almost functional, I just don't have much free time to implement a ModelBinder that uses it. Take a look on this file, you'll have a good idea how the magic happens! :smile:

How about these changes to the implementation of MutableObjectModelBinder:

  • Attempt to use whichever public constructor has the most bind-able arguments, similar to how controller actions are resolved
  • If a suitable constructor cannot be found, the result is equivalent to default(T) (though I don't believe Mvc does struct binding, so it would just be null)
  • Resolve the values of the constructor arguments the same way the values of the controller action arguments are resolved (respecting any existing binding attributes, falling back to 'wherever we can get the value from')
  • Carry on with business per usual, binding to public-settable properties, etc.

This would allow for the use of immutable model objects and for the [FromServices] attribute to be used in the constructor so that models can take advantage of 'proper' dependency injection. If these changes were made, the class should probably be named something besides Mutable.

If the team would agree to this idea, of course with any adjustments, I would be happy to work on it.

Proper dependency injection would never be used to inject into models. That's widely seen as an antipattern.

By who? How many people? And by what authority? @ploeh is posting on here saying the DI infrastructure as a whole is an antipattern, many blog posts and Stack Overflow posts out there feature opinions that 'fat controllers and skinny models are an antipattern', and yet more people will harp on ORMs, saying that using them without another abstraction layer is an antipattern, or that using them _with_ another abstraction layer is an antipattern.

Do you have any alternatives to offer, or maybe just some reasoning behind your statements?

Let's not turn this (or anything else) into appeals to authority; arguments should speak for themselves (although often they build on other arguments, recursively).

IIRC, the first time I touched on the subject of Dependency Injection into 'model' classes was back in early 2010. Later, I expanded my thoughts into an article that argues that at the boundaries, applications aren't object-oriented.

If boundary code like 'models' can't be object-oriented, but should rather be viewed as 'dumb' data, then attempting to enable Dependency Injection for Data Transfer Objects (DTOs) would go counter to that.

That said, support for immutable DTOs would make me happy, but that's a slightly different discussion.

Yes! This puts it better than I can. The second link I'm fairly certain is a clear expression of realizations I've been coming to over the past few years. And sure enough, I've never hoped to inject into "models", or even have "models" injected into other classes. They are just a snapshot of data, relevant only to the contexts that decide to use them.

@tuespetre, reasoning? Well, I'll take my best shot, although I have a sinking suspicion that despite my effort it'll be easy for you to dismiss out of hand:

How does all this result in the practice of models touching injection being bad? When I'm thinking about it, the key thing to note from my first paragraph is _context_.
It's characterized as misuse because it's easy to conflate creating objects with an assumption that in OO, objects, therefore methods. But what happens when that behaviour doesn't apply to every context in which that object might find itself? Injecting into models implies an anything-goes mentality, and _if you want it, just take it_. All the while the context becomes blurred as the model's purpose is spread thinner and thinner.
What I've seen in those situations is that the models start having to become aware of every situation, riddled with exceptions to their own behaviour. Rather than being an expressive and easily digested API, you're now stuck sorting through dense nests of branching logic to determine just what is going to happen _given a scenario_ -- read: _context_.

Now, nobody is going to deny that fat models still exist with examples today (ActiveRecord, Eloquent, etc). But it's not without deferring what I view as some responsibility towards the almighty context and resisting the urge to create god-like objects.
Rather than fat models vs. skinny models, I try to advocate balance. I won't deny the ability to put some behaviour on models, but it must be possible with state that is guaranteed to be present no matter what situation the model finds itself in.

Now here's where it all comes together: If what you give a "model" at creation is a bunch of infrastructure and it's also responsible for housing a bunch of state you've deigned as serializable data...Is it not then reasonable to assume that you've accidentally fused the idea of services and models together?

tldr;
The best question to ask at that point is "Are you sure what you want isn't a serializable service?" with the followup being "Why would you want that?"

@ploeh - Thanks for these links, they were great reads, you've indirectly gained another follower through this discussion thread. :)

@ploeh:

Let's not turn this (or anything else) into appeals to authority; arguments should speak for themselves (although often they build on other arguments, recursively).

Agreed; I was merely expressing my frustration with the situation. It's too easy to call something an antipattern without offering an explanation.

@atrauzzi:

I have a sinking suspicion that despite my effort it'll be easy for you to dismiss out of hand

Although it is easy for anyone to dismiss any argument 'out of hand', I would not ask for your reasoning unless I genuinely cared to discuss it with you.

It's characterized as misuse because it's easy to conflate creating objects with an assumption that in OO, objects, therefore methods.

In MVC, model objects can implement the IValidatableObject interface, therefore, methods (well, one method.) Now, I don't know if there are many (if any) other such use cases for other methods on models, but I do appreciate your explanation.

I agree that models shouldn't do too much, but there is such a blurry line between 'this is outright bad' and 'I just don't like it'. Some folks insist on having a separate class just for 'that one method', and to them, it is sacrilege to just leave it on some other class. Some folks insist on having a dedicated class for everything: "everything is a command or a query so the objects HAVE to be explicitly designed and named as such."

If support for models with parameterized constructors is added, developers _will_ be able to inject dependencies into their models unless the entire [FromServices] binding construct is removed. I'm just not convinced by the "well, it _could_ be abused" viewpoint, because _anything_ can be abused.

Now, supposing the [FromServices] attribute was to be removed entirely, I could envision another potential solution to the 'validation logic making use of services' problem. I will just begin a new issue about that.

@Eilon I think this is a duplicate of #1786

@danroth27 yep looks like the same thing.

Was this page helpful?
0 / 5 - 0 ratings