We regularly advise customers to separate their input and output models (or view-models) when using MVC. This provides a typed protection from issues like mass assignment and keeps it very clear within a code-base which properties are intended for display, input, or no action at all. The existing facilities in MVC for specifying which properties to bind are somewhat clumsy or ugly (e.g. specifying property names via strings, decorating properties with [Bind], etc.).
We'd like to provide a very basic object mapper in the box to assist in dealing with accepting input models and copying their values to domain or data models, and vice-versa for producing output/view-models. It is not intended to be a fully featured object mapping system, but rather a a simple way to handle the most basic of requirements that people are exposed to when implementing these model binding patterns. To that end, it will only support recursive property assignment based on name matching. It will not include features such as flattening (CustomerName -> Customer.Name), construction, immutable object creation (via constructor params), configurable conventions, etc. Customers looking for features like this and more will be advised to use a fully-featured library such as AutoMapper. This included library thus likely act as an introduction to the concept of object mapping which customers will very often graduate from to libraries like AutoMapper.
The API will be static only with methods to perform a mapping operation, as well as create a mapping delegate that can be stored and invoked later. The implementation will use reflection to build and compile an Expression tree into a delegate. The static mapping function will cache these delegates by the type parameters so as to avoid excessive reflection and object traversal after first use.
@SteveSandersonMS hello.
OK, where do you think this best fits? Should it be its own separate repo and NuGet package (albeit a very tiny one), or can we make a case for fitting it into an existing repo/package?
I vote for a separate repo.
I at least think it definitely doesn't belong in the MVC repo. Perhaps something like Common, or its own repo.
Why not leverage automapper for this?
@bjorncoltof The thinking is that we could provide something really simple, at the expense of flexibility and power. We think we can do something simpler because our scenario is so constrained.
I understand that your scenario is relatively constrained, but it is also so easy to implement using e.g. Automapper. If you then 'hide' it behind an interface people can change it to whatever they like. It would not surpride me if the constrained svenario will grow bigger over time and you'll end reproducing more behaviour that is already covered by readily available packages
@bjorncoltof I was thinking the exact same thing. At the very least if it's behind a (supporting) interface, one could simply replace this intended implementation with AutoMapper instead.
@Eilon Design discussion aside, if this is going in a separate repo, can you create one I can push code to? I guess it should be called ObjectMapping. The APIs will go into the Microsoft.Extensions.ObjectMapping namespace.
I completely agree with @bjorncoltof here - why not just encourage people to use AutoMapper instead of creating your own 'MS sactioned' version?
I get you want to encourage best practice without the initial boilerplate of Automapper, but it feels like if you create a static interface package then you're going against the DI everywhere approach being pushed in ASP.NET Core.
Alternatively, if you put it behind an interface, then you'll end up stuck with the same "lowest common denominator" conflict that riled up the DI container authors previously...
Not invented here... again
Really, that is exactly the kind of stuff why .NET community does not get the traction it should have. There are numerous mapping libraries out there...
I can only speak for AutoMapper which is easy to set up and ramps up with features if you need more power. Now you stick this into your framework, another chance gone to commit to your community and say
"Yes, mapping domain into viewmodels absolutely makes sense in many situations, but we don't need to cover this, the community has it covered quite nicely thank you very much."
Doesn't Microsoft have enough to do already instead of wasting it's time attempting to kill off more community projects?
Gotta say I'm not really sure I'm seeing the point either. If encouraging people to use proper View Model-Domain Model separation is the goal, then stick it in the docs, explain why you should do it, show the handwritten method and then show how to do it in a 'proper' mapping lib.
Providing a rudimentary mapper doesn't encourage people to do it; it subverts the usage of already-established mapper libs, chiefly AutoMapper obviously, encouraging people to drift away from what the community already uses.
While i think there's till plenty of room for Microsoft to get into the mapping game. I'm pretty sure the biggest problem associated with mapping is the lack of language support for intelligent, simple mappings.
The way anonymous objects and object initializers behave, that right there is 85% of the syntax for a gloriously simple mapping system at the language level. Sadly i don't think this can be achieved without language level support, or atleast those projects would all become exercises in insanity expression tree parsing and handling that likely lead to a never ending series of limitations and constraints.
I just want to add my voice to the people that say that this is hurting the community. Other languages are thriving just due to community alone and you (Microsoft) should be trying your hardest to nurture the community and not to provide lightweight alternatives.
Since an open source project is really good, what you should be doing is supporting it by recommending it and potentially contributing to it.
Thanks for the comments and discussion folks! We're certainly open to other ideas here, nothing is set in stone.
As you can imagine there are many considerations when determining whether we recommend, ship, support, and/or contribute to an existing library when looking to fill a gap in our stack. This case is no different and we're equally sensitive to the issue of being perceived to favor one OSS library over another in cases where there is established choice. Ultimately we're trying to do right by all our customers along with the .NET OSS community (that we're also a part of).
Our intent here was to provide the most basic of utility methods to allow customers to perform simple object mapping in the cases outlined in the original issue. We felt this would encourage better (and safer) code while introducing many customers to the concept of mapping. As stated, we intended to steer customers to libraries like AutoMapper for any needs beyond the most basic. Creating an abstraction, e.g. IObjectMapper, was expressly not a goal given the simplicity of the utility and that it was intended as an application helper rather than a sub-system that the framework itself would utilize (and thus warrant suitable abstraction as to allow replacement).
That said, we're going to revisit the idea of either simply recommending (e.g. via documentation) mapping libraries, or going further and shipping something like AutoMapper in our default application templates (with applicable usages within). We'll keep this issue up to date on our thoughts and discussions as we go.
To add to the list of existing .NET Auto Mappers ServiceStack.Text also includes simple, config-free and resilient Auto Mapping via extension methods with a Live Demo you can play around with on Gistlyn.
I think you guys have done an awesome job of going open and putting most of the process out in the open as well, but it seems like there is still a big tendency to have Not Invented Here syndrome. I'm trying to think of an instance where you guys adopted an existing open source project and contributed to it instead of making your own. Nothing is coming to mind besides maybe JSON.net.
agree with @dotnetchris that a better path for MS to take would be to improve lang support for object mapping.
Whether this mapping is intended to be a simple/basic/easy/default implementation or not, it could easily be documented or demoed using existing libraries. There really isn't a need for this or an abstraction.
I second the notion of using an existing, battle-tested mapper from the community as opposed to pulling another NIH and writing something "simple" on your own. AutoMapper as an example isn't too bloated to avoiding using it for simple use-cases. If you want to provide simple mapping capabilities OOTB to "educate users", then examples using community project and showing how to use them will achieve both that and flourishing the community and OSS vibe you say you want to preserve.
We, as a community, don't even need you to contribute to those projects. Just point at them, give them the spotlight, even ask them to provide the documentation to the official channels. They will most likely oblige. Don't act as a monarch; act as an equal member in the community, and sometimes let it truly lead you.
This is how it's done pretty much everywhere else today, and writing something on your own YEARS after it's been written by the community and perfected by it would be a terrible waste.
My 2 cents.
A caring .NET MVP and a long time contributor to OSS in the MS stack and elsewhere.
Let's say for the sake of argument that you include this functionality. Unless you're locking down the feature set from day one (which I'd find unlikely), you're going to slowly add features, because those customers that relied on your simple solution out of the box, need just "one more feature" to make it work for them. So at some point, as your customer's applications starts to grow, and so do their needs, you'll end up having to make a decision - do you continue to add features to serve your customers or do you tell them to dump your solution and go with something like AutoMapper. Even if the change of code is minimal, telling customers that you no longer support what they need won't be easy. And we all know that the reality is that most applications start simple, but they don't end that way.
The alternative to this isn't necessarily to ship a library or favour a specific one, but to actually educate users and guide them to options, much like other frameworks do on other platforms.
Also, even the JSON.net being the sole example of you guys embracing a community project that I can think of isn't a very good case. MS only embraced JSON.net after trying to replace it several times and failing.
@ejsmith they ported AttributeRouting project too in MVC...4? and in the process created coupling that made existing route test scenarios impossible and created collisions with existing library usages which required time-consuming refactoring regardless of whether you replaced their implementation or not.
I hope that the time to learn from our own mistakes (embracing existing OSS project on one hand and reinventing the wheel on another) finally has come, and we as a company and as a community will repeat the success of adopting Json.Net, for instance, or of Git; and not the failures of JavaScriptContractSerializer, etc.
I think @hhariri nailed it with his statement above. AutoMapper is a mature, battle-tested library that many of us have used in our applications for years. Lead developers to that pond, if they haven't already discovered it, and they will drink. My opinion is that the time required to introduce a subset of existing AutoMapper functionality would be better spent elsewhere.
Why encouraging Microsoft to force users to use only AutoMapper? Let there be alternatives, and at the end the best solution wins... After all, there were many DI containers, and yet Microsoft baked in DI into ASP.NET Core by default.. AutoMapper is great, yet many other OSS community members prefer to use other Mappers. If do not like the solution Microsoft will come up with, don't use it...
Because it already exists and is deservedly the standard de facto/default object mapper in .NET for years now? Because this happens not for the first time and the results are known (sometimes it worked, sometimes it didn't)? Because it's time to learn a lesson?
@saint4eva because IMO it ends up breeding code like this in every project you do...
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
over 23k results
@wwwlicious I totally understand and agree with your concerns, but I am looking at it from the lens of options/ alternatives...Let us see how it will all play out at the end...
As someone that did go down the road of trying to object map and ended up using AutoMapper anyway, just use AutoMapper.
It should be easy to make sensible defaults with extension points just like Newtonsoft.Json is the serializer in the input/output formatters.
@saint4eva No one's encouraging everyone the use only one library, there are already many existing alternatives to choose from. If most people want to use AutoMapper, let it be. A "blessed" Microsoft alternative is only going to artificially thwart choice and deflate anyone else from creating/maintaining alternative solutions. Which leads to being stuck with features in Microsoft's implementation and no incentive to develop anything better.
Let there be alternatives, and at the end the best solution wins...
Is counter intuitive to baking a default implementation which is the primary killer of alternatives libraries.
After all, there were many DI containers, and yet Microsoft baked in DI into ASP.NET Core by default..
Now watch what will happen to adoption of alternative DI containers in .NET Core. hint: it doesn't improve because there's now a default implementation.
If do not like the solution Microsoft will come up with, don't use it...
That's not what default implementations do, the question turns into "why aren't you using Microsoft's default implementation?" and invariably most will - killing adoption of community libraries.
.NET has a lack of a vibrant community ecosystem more than it does a lack of Auto Mapping solutions. A vibrant community is what a platform needs most to thrive - an attribute every other popular language has - which doesn't have the same authoritative entity that develops language/tooling to also routinely kill popular high-level community solutions.
I seem to prefer them making something really simple like they said, but leaving object mapping extensible, that way if you want to use the object mapper of your dreams (like AutoMapper) then you can simply plug it in and thus override the default.
That, I think will be a better way to go.
Just my 2 cents.
I think that's completely understandable that if you want to use automapper functionality in deeper level of asp.net you wouldn't want to depend on a 3rd party component. The dependency injection is a good example of this.
But in this case you don't want to use automapper just provide a default minimal implementation of a helper component.
Naturally Microsoft can create a mapper library but do they really want to make competition for the community projects? Because if they make it, it will be a big competition.
Personally, I'm fine with this, with some very specific concerns:
So if you're going to do this, please do it right. Simple, locked-down, acting only to enable spiking with mvc, and as a pointer to documentation on what people SHOULD be researching for themselves, in a perfect world.
Do not go back on your word.
@nbarnwell Can you define SIMPLE? Once defined, can you then please give me some sort of insight into how many applications would fall into the category of being able to use this simple approach and not fall short relatively soon?
I perfectly agree with @nbarnwell .
I say more. I don't want Microsoft might say something that might be interpreted from "dark-matter devs" as: "You MUST use AutoMapper (or any other golden children) to ensure separation of concerns between Business Layer and UI Layer".
I prefer thay say explicitly something like: "You must use repository pattern and ViewModels to ensure separation of concerns" and then they provide a simple impl. of mapping as stated by @nbarnwell , just to implemet easily repo pattern in the Asp.net Mvc default template (that, in my opinion, is the main purpose they need a mapper).
The reason is simple, here the point is not simply to authomatize object mapping but to automatize as much as possible of the whole repository class code. I don't use AutoMapper (or other object mappers) but I have more specific tools that do that, and I don't want to listen some of my customers saying...oooo but your code doesn't use AutoMapper that's wrong,...it is the adviced tool. That might means for me renouncing to the usage of my tools and to increase the production cost of at least 50%.
@frankabbruzzese So I'm curious, what if your customers say "you're not using the one that MS ships out of the box". How would that sit with your tooling preference?
@frankabbruzzese I think @DamianEdwards was clear that they don't want to favour one mapper over the other as 'the golden children' as you put it so that is unlikely to be a concern.
Simple and locked down may work in closed source environment, but when the first PR comes in to add "just that one simple feature that _x_ mapping library has so I don't need to take a dependency on it", this thread will likely be forgotten.
I have certainly found in my career, that scope and functionality creep are inevitable over time as @hhariri said. There are very few examples from previous out-of-the-box implementations MS introduced which overlap with existing mature OSS libraries where their usage increased or their community benefited as a result.
So for me, issues like this are equally about the message MS sends to those who have spent their time building these projects (both code and community), especially those who give up on maintaining their projects after the 'giant' has sucked all the oxygen out of the space.
If we want to have a vibrant .Net community and ecosystem, it has to be about more than the MS built solution introduced over existing mature ones and instead shine the light on the great work that countless others have contributed to help build/grow and improve that community.
Finally, there is never any need to have any object mapper in your code. It is simply code-compression to avoid the tedium of left-right mapping. The principles behind using this technique can be easily explained in guidance along with manual mapping code and promotion of the concept of mapping with references to the existing OSS solutions in that space if you want them.
Microsoft,
What you are doing here is what is pushing experienced developers away from your platform.
You are probably not understanding what kind of weight you throw around when you release something.
Users of your platform will continue to believe that what you produce is what they should use, that will become the de-facto standard.
This results in software developed using the "simple" tools you provide, which in the end means lesser quality, more technical debt etc. remember DataSets, Linq to SQL, etc.?
While the developers that want to build a better platform are pushed out, their efforts are shadowed by these NIH tools you release.
You created Asp.NET core to compete with NodeJS.
Then why don't you let that happen, the power is in the community, not in your ability to create replicas of existing libraries.
FOMO.
As Trump would say, it is SAD. The hurt on OSS yuge.
But even sadder is to see the resurgence of old Microsoft's "let's promote the lowest common denominator" since there are some who cannot be bothered to PM> install-package AutoMapper - and literally on ASP.NET MVC, which was the very first break from this mindset back in 2008 and towards "let's aim for the stars and some who might be left behind will still look upwards". It is easy to take for granted how revolutionary and uncompromising MVC was in those dark days.
SAD.
hhariri, the key should be their imp is too simple to be used in a true life project.
@wwwlicious I think, basically, they need a tool to add repository pattern in Asp.net. Mvc default template. What you propose other than implementing a Microsoft mapper?
@frankabbruzzese good old fashioned manual left-right mapping to promote the rationale behind mapping with guidance that there are such things as 'automappers' which can also be used. To re-iterate ...
there is never any need to have any object mapper in your code. It is simply code-compression to avoid the tedium of left-right mapping. The principles behind using this technique can be easily explained in guidance along with manual mapping code and promotion of the concept of mapping with references to the existing OSS solutions in that space if you want them.
@frankabbruzzese then apologies, because I'm missing your point.
I didn't say I recommend this approach, but as someone who still remembers being in a situation where learning one thing ends up growing exponentially into learning an entire stack at once, I can see the benefit in a simple OOTB solution, as long as all it does is enable nearly New Project->F5 to get things running.
"Can you define SIMPLE?"
As I described originally. Even more specifically, a single static class with a single method that maps one object, using reflection, to another.
"Once defined, can you then please give me some sort of insight into how many applications would fall into the category of being able to use this simple approach and not fall short relatively soon?"
No, that's my point. I don't believe any apps should make it into production using this thing, should MS go ahead with it. They should fall short as soon as non-trivial requirements come up (properties of non-built-in types, recursion etc.
"what if your customers say "you're not using the one that MS ships out of the box""
If they ask why you aren't using it, you tell them it's not fit for the requirements. If they ask why, you say because it's a spike and you'll be investigating mapping if you really need it.
"Simple and locked down may work in closed source environment, but when the first PR comes in to add "just that one simple feature that x mapping library has so I don't need to take a dependency on it", this thread will likely be forgotten."
If the people doing the pull request merging are aware (and the readme etc should all back this up) then PRs will simply be politely declined with a note that includes a link to the docs that already stated it wasn't going to be enhanced, and what to do if you require enhancements (i.e. use something else).
"those who give up on maintaining their projects after the 'giant' has sucked all the oxygen out of the space."
I totally agree. MS has a responsibility to NOT DO THAT THIS TIME. Whatever they put together, if they go ahead, needs to purposefully NOT COMPETE with the other, more mature choices available. If they implement a mapper, it's really just a way of saying "and here's where you'd use your object mapper, if you're going that way".
"Finally, there is never any need to have any object mapper in your code. It is simply code-compression to avoid the tedium of left-right mapping."
Agreed. The benefit really is that it makes it clear that some sort of translation from one object to another is a good idea (e.g. don't just use your EF model as your viewmodel objects). But we're talking about people who won't see that as a problem unless the examples/docs point to it specifically.
"What you are doing here is what is pushing experienced developers away from your platform."
Experienced developers should know better and be mature enough that this sort of thing wouldn't be the thing that pushes them away from the platform, IMHO.
"there are some who cannot be bothered to PM> install-package AutoMapper"
This is missing the point - merely installing automapper is not the point. Should I use Mapper.Map() or Mapper.DynamicMap()? How do I configure it to know how to make complex objects, lists etc? It's not hard to learn how to configure automapper, but it IS friction when what you're trying to do is get to grips with MVC.
"Doesn't Microsoft have enough to do already instead of wasting it's time attempting to kill off more community projects?"
That's a bit unfair. Maybe I'm naive, but surely that's not their goal. Yes, there are people who use MS because it's MS and this can be the unfortunate side-effect. Typically where MS have obviously and actively taken that approach, it's because they want to make money. In this case, there's no money to be made, so there's no motive to "kill off" AutoMapper et al. With the recent Rider NET Core debugging debacle, there was at least a motive. They didn't want to enable Rider, because that will take away a lot of money in the form of VS Subscriptions (and it will, there's nothing MS can do about that other than "be better", which will be tricky). It was pointless if that was the motive, because the peeps at JetBrains aren't going to be slowed down for long by something like that. It's just not the case here.
Please don't. Take whatever resources you have that are on these types of wasteful projects and have them work on the stability of the yet-to-be-stable core/net standard. There is SO many places that value could be added.....this is not one of them.
If there has to be a common interface that all third party tools can implement, please also make it easy to do manual mappings (Useful even if you are using Automapper when your entities don't match up). If you move the generic types into the interface like so:
public interface ITranslator<in TSource, in TDestination>
{
void Translate(TSource source, TDestination destination);
}
You can write some very useful extension methods (See full source here):
public static class TranslatorExtensions
{
public static TDestination Translate<TSource, TDestination>(
this ITranslator<TSource, TDestination> translator,
TSource source)
public static List<TDestination> TranslateList<TSource, TDestination>(
this ITranslator<TSource, TDestination> translator,
IEnumerable<TSource> source)
public static TDestination[] TranslateArray<TSource, TDestination>(
this ITranslator<TSource, TDestination> translator,
IEnumerable<TSource> source)
// ...More Extension Methods Omitted
}
The IObjectMapper interface you currently have would not allow this.
public interface IObjectMapper
{
TDest Map<TSource, TDest>(TSource source, TDest dest);
}
All I'm suggesting is to make the simplest possible thing i.e. mapping by hand easier.
@RehanSaeed No no no. Have you read none of this thread? If you want extra functionality, USE AUTOMAPPER. The whole argument is around MS building something that grows enough to be used by most people, when really AutoMapper (or one of the other mature libraries) should be what they use.
@nbarnwell I'm not raining on anybodies Automapper parade. Even the use of Automapper requires an interface, in fact Automapper has one built in itself called IMapper. Tying everybody into Automapper as opposed to the other mappers is not a good thing. All I'm saying is that if there has to be a common interface that third party tools like Automapper and others implement, then consider one with generic arguments in the interface declaration.
That's a bit unfair. Maybe I'm naive, but surely that's not their goal. Yes, there are people who use MS because it's MS and this can be the unfortunate side-effect. Typically where MS have obviously and actively taken that approach, it's because they want to make money. In this case, there's no money to be made, so there's no motive to "kill off" AutoMapper et al.
It's totally fair. MS needs to spend more time on ACTUAL problems, and focusing on getting people onto Azure, regardless of platform they use. Adding mapping is only wasting their time. They have so much more stuff in .net core to worry about, if they have so many free resources in the asp.net team then get them working on missing functionality of dotnet core.
Better to leave the generic arguments out of this implementation, which will therefore allow people to have a little go, but when they feel the pain of casting etc, they'll look to the docs, which will say "Learn about Object Mapping and use a dedicated library for it.". I wouldn't even have an interface - make it a static method on a static class. There will be no choice to extend it, one will HAVE to go looking elsewhere.
@RehanSaeed I don't think it makes sense to introduce a new abstraction over mapping. These "common interfaces" tend to work not well because they only define the lowest common denominator.
If someone wants to hide the mapper of choice, one should create it`s own application interface of choice - this can be done within minutes.
@phillip-haydon How MS should spend their resources is a fair point, except the impl being suggested, if they go ahead at all, could've been done in less time than has been spent debating it on this thread.
The reason not to do it is because they could be doing something else, and everyone is panicking that it will somehow kill off AutoMapper et al. These are valid concerns, and I agree entirely.
The reason to go for it, is that it will hopefully guide a certain kind of developer away from using their EF models as viewmodels yet avoid friction that would come from having to go off on a tangent to "get started" with AutoMapper.
The only way it will succeed though, is if it removes that friction but is still SIMPLE ENOUGH TO NOT COMPETE with established libraries, and in fact embraces that and points users to those libraries. No-one believes MS is capable of this, that some innate greed will force them to twhirl their moustaches and crush all other object mapping libraries in their wake.
There is a precedent for that, so it's up to MS to avoid that trap, and turn things around so the community can begin to trust them again.
It's like teaching someone to fish rather than giving them a fish, but just letting them have a little taste first to motivate them.
@nbarnwell - the whole reason people use EF as view models is because Microsoft taught them.
OMG Every single year MS does demo's "hey checkout web api, we will just add EF, query the database, return the data, bam done" then a flood of questions on Stack Overflow popup "it throws an exception, it times out" all caused by returning EF models and allowing lazy loading to occur.
Microsoft screwed up, fixing the problem of bad designs doesn't mean "lets introduce another new concept", it's going to be yet another pattern which is abused. View Model reuse it abused. Repositories are abused. EF is abused. The entire MS ecosystem is abused every day.
But let's debate adding another abstract baked right into mvc so that all the MS shills can be jump for joy.
I'm against MS trying to get their fingers into everything, every time they do this they kill off more of the community.
Adding my voice to the conversation because, like many people above, I think this sort of behaviour is at odds with Microsoft's stated commitment to the .NET open source community. Don't reinvent the wheel - take what already exists and invest in making it better. Please.
Microsoft has proved they can deliver the kind of "out-of-the-box" experience that developers are asking for without having to reinvent every component in the stack. File > New > ASP.NET Web Application installs jQuery, Modernizr, Bootstrap, Newtonsoft.Json - even Antlr3.Runtime. Newing up a Single Page Application gives you Knockout, Sammy and Respond.js as well. It works, it works well, and it's probably the single most effective way of getting 'dark matter developers' using these libraries - make it a seamless part of the native tooling experience. When those developers' requirements become more complex, they don't have to try and swap out SimpleComponent for a more fully-featured open source alternative. It's a pattern that I think works really well - so why can't we do the same with AutoMapper? Instead of creating a new 'simple' mapper, take an existing, proven solution with a rich community around it, and use that. If there's some limitation of AutoMapper which means you can't deliver a great out-of-the-box experience, then open a PR for it.
If the rationale behind this request is enterprise customers insisting that every line of code in their stack is covered by Microsoft support agreements, then start offering Microsoft support for AutoMapper.
Another object mapper isn't going to do anything for .NET OSS - but a show of support for the existing community, like embracing AutoMapper as the de facto mapping solution for new VS projects, could be really valuable.
I think perhaps a general dislike of MS and past mistakes is confusing the issue somewhat. Fine, MS taught people how easy it is to query an EF model and cause lazy-loading etc. But that's fixable by calling ".ToList()" on the result, whether you return the resulting objects or map them to something else.
The question here is, do we just write off everything MS does because they are MS, or do we look at ways to avoid those past mistakes, learn from them, and offer better guidance in the future? How do we turn around this perceived problem where "The entire MS ecosystem is abused every day."? Is it always MS's fault, or is it partly the fault of the people doing the abusing? Who is better placed to help those people change, than the only people they look to for solutions?
Yes, what I'm saying all hinges on MS not repeating those past mistakes. I know that feels like a long-shot, but we can't just let our emotions run our decisions all the time, else we risk cutting our nose off to spite our face.
And for the record, I don't recommend adding another abstract baked into mvc. I'm hoping they do the opposite - a locked-down, bare-minimum thing (it could even throw exceptions when run outside of a debugger, telling you to use something else once you're done spiking) to get amateurs/newbies who've never heard of "object mapping" over that hump without distracting from mvc itself.
On the whole, less code is better. I'm fine with them not going ahead with this, though there is that one small possible benefit of it. But if they are determined, then at least they should make sure it does not "kill off" other community efforts, but instead PROMOTES them to those who perhaps currently only speak Microsoft.
@dylanbeattie That is a fair point, and I agree in principle. The challenge, is that if MS do choose AutoMapper as the golden child, isn't that another way of them "killing off" part of the existing community who are building/using the other available frameworks? Damned if they do, damned if they don't.
They are in a position of power for those devs who blindly take them at their word, those devs who still write business logic code in their OnClick handlers because their expensive MCAD course told them to. The challenge is not just to aid the community, but to reveal it, in all it's glory and variety. To educate, rather than just give another specific "right answer".
Maybe it's a case-by-case basis, and object mapping ends up being debated where no-one (myself included) would suggest they try to offer a "simple jQuery alternative" that points people to the real jQuery when they hit the limits.
I think Microsoft should add specialized tags to NuGet. Like [object-mapping] that need to be approved so people don't abuse the tag system as they already do (there's stuff tagged for things the project doesn't even do).
Then in their documentation they can say "here's the object-mapping concept, if you want to use an object-mapper, here are the object mappers on NuGet". This means:
I am currently not understanding the obsession with AutoMapper. The point is that there are mapping libraries out there and the developer should be free to choose one.
ASP.NET MVC provides plenty of hooks to insert the mapping at an adequate position.
If MS fears lack of LTS of certain functionality provided by the community, it may choose a preferred library and provide the means that said library gets LTS (.NET foundation?).
In other words, on an organizational and community level there are a number of solutions to this problem that
@phillip-haydon Not a bad shout. I never trust tags for that reason, so yeah, if they're moderated somehow, that'd be the perfect way to point people at the current "landscape" without having out-of-date docs.
The only challenge with your point 1 (which would be a goal, don't get me wrong) is that if there isn't an OOTB impl, and they don't promote/use any single framework over another, that you get additional friction when trying to do File-New Project-[bit more stuff]-F5. Maybe that's okay. It's hard for me to say because while I'm not god's gift to programming, I am experienced enough that it's not a problem for me (I know where to get AutoMapper and how to use it, so I'd "just" go and do that). The challenge is how to have minimal friction for those new to it. I'm split fairly evenly down the middle on this, tbh.
/// <summary>
/// Did you know? : It isn't recommended to return EF entities directly so we 'map' them to a data transfer object (DTO) class
/// Want to know more? : http://msdn....
/// </summary>
public class MappingCode {
public PersonDTO MapEntity(PersonEntity ef, PersonDTO dto) {
// did you know? : There are libraries called 'automappers' available which can reduce this kind of code
// want to know more? : http://msdn....
// we'll do this by hand for now though by assigning the left / right properties we want to return
dto.Name = ef.Name;
dto.Age = ef.Age;
return dto;
}
}
is that really so complicated?
Instead of answering these for the next umpteen years of coding pattern torture
@flq AutoMapper's always been my 'de facto' mapping tool - I've used others, most notably the one that's baked into ServiceStack, but when I'm working on a project and I need to map something, AutoMapper's just the one I always go for.
There are mapping tools out there. Many developers are quite comfortable choosing one, plugging it into their project and configuring it to do what they need. This seems to me to be very much a conversation about providing a simple solution aimed at developers who - for whatever reason - do not want to choose and configure one of the many that are already available.
I'd far rather see them adopt and support an existing OSS solution than build something new, and I don't honestly care whether it's AutoMapper or something else.
I'd recommend asking some of these projects to joing the .NET Foundation (or equivalent) and for MS employees to contribute to that. Using the .NET Foundation to promote a range of possible OSS projects makes long term sense because it insulates consumers against someone 'throwing their toys on the floor' or simply 'getting bored' and makes MS contribution easier.
It also flushes out 'alternative' OSS stacks that are funded by business models and thus cannot move to a foundation; those I think should rely on their own marketing.
I don't think everything needs to go a foundation - but where we want to recommend best practice around usage it makes a lot of sense to pick packages that have foundation backing to promote.
@flq just an FYI - nearly all the other mapping tools copied the AutoMapper API to make it easy to switch. The others, at least that I'm aware of, are:
AgileMapper
ExpressMapper
Mapster
ValueInjecter
I hesitated to include EmitMapper, it hasn't had a release in several years.
I'm not sure it would be possible to "kill off" these other mappers - I've collaborated with all of them - because AutoMapper's been the de facto mapper library in .NET since before any of these projects started. Each was started not to copy AutoMapper but to do something it couldn't (or I wouldn't). This wouldn't do any more than what happened with JSON.Net. There are other JSON serializers, for more specialized scenarios.
@wwwlicious
If you're interested in the motivations behind AutoMapper, I've got blog posts from 8-9 years ago that go into it. I don't apologize for it either - it solves a real, specific problem that our teams have on nearly all of our projects, and it allows them to focus on solving business problems rather than rote code (and the bikeshedding discussions that follow) that can be surprisingly buggy.
And that link you have - yes, we support mapping expressions, because for OData-type scenarios it can be super helpful. On top of that, we support building LINQ Select projections directly, so you never even load your entity, you get your mapping passed to your query provider to go straight from SQL -> DTO. Now _that_ I assure isn't easy to write over and over and over again.
@davidroth There are already abstractions over DI, where people can choose to use the excellent Autofac. There needed to be a common IServiceCollection interface so all DI projects could implement it and the interface could be used in MVC internally.
Similarly, there could be a common IObjectMapper interface (I'm not suggesting Microsofts builds their own Automapper, I'm giving one reason for an interface) which third parties implement. This would allow MVC to make the call to do the mapping for you and you could end up with EF models in your action method instead of view models, thus removing the need for you to ever have to call the IObjectMapper.Map method. Something like this:
[Mappable(typeof(Customer))]
public class CustomerViewModel { ... }
public class Customer : DbContext { ... }
public class CustomersController : Controller
{
[HttpPost]
public IActionResult PostCustomer([FromMappedBody] Customer customer) { ... }
}
Just an idea, a flight of fancy if you will...
@RehanSaeed Well this abstraction has been rightly criticizes several times so I don`t think this can be used as an argument for another common abstraction which reflects the lowest common denominator. See this thread for example (about confirming containers):
https://github.com/aspnet/DependencyInjection/pull/416
@RehanSaeed I dont think that its a good idea to build this kind of magic into the framework. It is definitely not the recommended approach to use entities in controllers and this kind of magic always tends to be harmful in the long way. So i don`t see why it would be beneficial to implement this kind of magic into mvc as it would encourage bad design.
@jbogard
I think you misunderstood my intent, I use automapper, its useful, been using for yonks, read your posts years ago and apart from a breaking change circa 3,2.1, nor should you apologise, you should be thanked for your efforts! ;)
My point was that no such default, simple, basic, really won't change implementation of automapping is required in the core framework. Simply an explanation of what automapping is in the appropriate places would be enough.
The link was to demonstrate the type of questions that have been answered a thousand times over for projects like Automapper and all MS are doing is inviting a thousand more. And, as if to create a parody of itself, the requests in this thread to 'just add an interface...one more thing' .. only serve to prove the point that many here are making. Well that plus....no-one actually enjoys writing reflection-heavy expression code do they .... masochists? ;)
...and 'coding pattern torture' was about the horrible crimes all devs commit when you have shiny a new hammer, and everything looks like a nail. Thwak thwak thwak!
Perhaps we can shift the discussion a little bit. I'm not generally in favor of a common mapping interface - switching from one mapper implementation to another is really just an exercise in Find + Replace with regular expressions.
Since @danroth27 and others were already discussing making a separate NuGet package, whatever default choice wouldn't be "baked in" anyway. This is really a discussion around 1) what the project templates should include and 2) what docs.asp.net should "recommend".
From my perspective, I'm most interested in the motivations for originally considering a new MS-built mapper library. If one of the motivations was to provide a simpler alternative, then regardless of what happens I want to incorporate that feedback to make my library simpler/easier to adopt. Half the current features of AutoMapper were inspired by competing libraries, I'm more than happy to continue that trend.
Creating "simpler" implementation by MS, even if its behind interface, doesn't make much sense to me.
As customer project grows, that simple mapping implementation is never good enough, can't scale beyond simplest use case, and 99.9% projects are growing far beyond initial planned feature set. Most devs will keep using and abusing it (like it started happening to MVC Core IOC now!).
AutoMapper and other libs are already simple enough, and as jbogard is saying, they can adopt to meet that new MVC service contract.
I understand MS wants to give full experience out-of-the-box, but hurting OSS projects along the way its not a good message to the community.
I suppose I just don't understand the "goal". Automapper has a simple interface to work with, I'm not sure how much simpler you can get.
If the goal is around "introducing people to mapping", then why introduce them to a different library, when it's likely to be the same setup as Automapper (and the numerous other frameworks).
Therefore, I'm not sure why creating a new library would help with the goal "Introducing people to mapping". If you're simply suggesting that you create a new library, put that in the boilerplate, and document it, it makes no difference what the library is. If that's the case, why spend time doing it, just skip the "create new library" part and use an OSS library.
This also has the side benefit of introducing those customers to the idea that there are OSS projects out there that do interesting/weird/scary things. The old chinese proverb... "Give a man (or person) a fish...."
Create something that's _only_ goal is to avoid mass assignment. Include it in templates.
Templates should help people not to shoot themselves in the foot by default.
In usage add comment to look at docs (+url) for more advanced scenarios; in docs suggest other OSS mapping libraries - additionally provides promotion for OSS libraries.
Looking at the database landscape is this not like complaining that SqlCommand (and other db variants) taking parameters to avoid sql injection is stifling the OSS community around ORMs?
I've read every comment here, and I think the best solution is to not ship this as a binary, but rather as source code in project templates, along with a comment stating something along the lines of
c#
// If you outgrow this (which you probably will) then there are several
// more capable open source libraries available on http://nuget.org
Either that, or just use AutoMapper.
I don't like this idea. Please just support the existing libraries in the community and stay focused on core MVC concerns.
After watching the https://live.asp.net standup, I'm on board with this. It's not about MS replacing AutoMapper, it's a ~100 line method to make the templates simpler and more secure. At the moment, I think the docs/template lead people down the path of not using discreet view models.
As a new user I want to quickly create a new website from a template and avoid common pitfalls like mass assignment for my few simple models.
Automapper would be in the top 5 dlls by size adding another 1/4 MB to a file new publish

OMG, 400 kilobytes! Do you really care?
OMG, 400 kilobytes! Do you really care?
Yes, I really do
Just include source code of a simple mapper in the template, point people to more advanced ones in comments. Problem solved!
...why?
On Tue, Mar 21, 2017 at 7:52 PM Ben Adams notifications@github.com wrote:
OMG, 400 kilobytes! Do you really care?
Yes, I really do
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/aspnet/Mvc/issues/5883#issuecomment-288255602, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AAGYMo8Qp8iUp-eYC0mZ4hhQLcku0C6Aks5roGKngaJpZM4MRuBp
.
@jbogard Jimmy why your code so bloated?
And seriously MS guys, let's just lock comments here and make a decision...
It started out as 100 lines of code ;)
On Tue, Mar 21, 2017 at 7:56 PM Itamar Syn-Hershko notifications@github.com
wrote:
@jbogard https://github.com/jbogard Jimmy why your code so bloated?
And seriously MS guys, let's just lock comments here and make a decision...
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/aspnet/Mvc/issues/5883#issuecomment-288256380, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AAGYMjgbFNA2GdtQ9zO7LsNffu3QXrVLks5roGOygaJpZM4MRuBp
.
Here is a crazy idea. How about stop making the built in MVC scaffolding present EF models to the View? Autogenerate a ViewModel class and a left/right mapping function that clearly looks stupid, forcing people to look for a better way of doing it. The current autogenning of [Bind] to prevent overposting is not great.
OMG, 400 kilobytes! Do you really care?
Yes, I really do
...why?
Density. There isn't a good dead code removal linker for .NET currently. I don't use a server just for one thing but can run hundreds or thousand of services; want to start them fast and shut them down fast. Why is docker popular vs VMs; why is nano server better then full Windows server. Why are people interested in using alpine for their services (which gives you an 8MB base container).
Other people will have different reasons; maybe they are loading up a raspberry pi full of microservices.
I'm not complaining about the size of Automapper; just complaining about the minimum size for the base feature set.
that clearly looks stupid, forcing people to look for a better way of doing it.
Then new people to the ecosystem will say .NET is rubbish. Templates are a lot of people's first exprience
I think @shaynevanasperen's suggestion is probably the best so far - don't ship a binary, just include the simple mapper in the templates, with comments about using other libraries for more complicated/production scenarios
The old MVC 3/4 templates had code that shipped in them. And everyone was annoyed with having to immediately delete them.
Then new people to the ecosystem will say .NET is rubbish.
I think the templates already go a long way down this path. Browser link and application insights are the first two culprits that come to mind.
@benaadams the problem is that the templates and example code always go for the EF models in the View approach, implying it's good, if not best practice. An autogenned mapping function will be annoying to edit, prompting people to wonder if there is a better way, which of course there is.
Just adding my input and support for existing projects. Invest in your community, support the popular projects that already exist. AutoMapper & IS4 would both make a great addition to the .net foundation.
From a different direction; like sample apps rather than starter templates, for example eShopOnContainers I think would be a very good place to demonstrate wider OSS components like Automapper; and it would be good to have more full featured sample apps.
With respect, you're not the target audience of a starter template are you? This is a template meant to "introduce" people to the concept of mapping. If someone is actively looking to reduce their project size, or more to microservices, they're already on a path that would take through many, many, concepts that far beyond just mapping.
The basic empty template wouldn't include automapper I'm sure, but a more complete example should (imho) draw on multiple opensource projects to should that there is a world beyond the core libraries.
That's kinda what I would assume. Empty is actually empty. A starter template would be representative. Because if the template includes EF, then it's not empty.
With respect, you're not the target audience of a starter template are you?
Probably not; though you have to file new now and again and have a look around to catch up with the apis 😉
Empty is actually empty. A starter template would be representative. Because if the template includes EF, then it's not empty.
The starter templates don't currently include EF. Maybe the answer is a few more templates then?
ASP.NET Core Empty
ASP.NET Core Web App
ASP.NET Core Web API
Empty and WebAPI are fine. Web App is fairly opinionated on the front-end; but there could be some that explore the server-side a bit more? (Where other OSS libraries maybe appropriate)
ASP.NET Core Web App + Individual Accounts (for auth) uses EF for the Identity/membership stuff. But no "traditional" data access in the sense of typical CRUD.
I think it would be good to share a kinda complete template with some code of what/where this will impact.
It's important to note how few code is around the mapping. I don't want, nor like to have AutoMapper as default. I don't need all it's complex stuff and also in my experience, it was easier to mess it up than doing plain.
The other idea here is that from my experience, BindingModels are plain contracts, and an Interface suits great for contracts, but they are not always possible to use, maybe something can be done on this front.
So, here is what it looks like. (I omitted the nested BindingModels inside a view model for brevity, but that's also another area I think the model binder can be improved too.)
```c#
public class ApplicationDbContext : DbContext
{
public DbSet
public DbSet
}
public class Country
{
public int CountryId { get; set; }
public string Name { get; set; }
public bool IsAvailable { get; set; }
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public Country Country { get; set; }
public bool IsAdmin { get; set; }
}
public class PersonViewModel : IPersonFullBindingModel // optional but useful interface here.
{
public PersonViewModel(Person person, List
{
// CURRENT CODE: MAPPING NEEDED HERE.
Id = person.Id;
Name = person.Name;
IsAdmin = person.IsAdmin;
Country = person.Country;
Countries = availableCountries;
// NEW MAP CODE: of course, it doesn't need to be here.
// Map(person, this);
}
public int Id { get; }
public string Name { get; }
public bool IsAdmin { get; }
public List<Country> Countries { get; }
public Country Country { get; }
}
public interface IPersonBasicBindingModel
{
[Required]
int Id { get; }
[Required]
[MinLength(3)]
string Name { get; }
}
public interface IPersonDetailsBindingModel
{
[Required]
Country Country { get; }
}
public interface IPersonFullBindingModel : IPersonBasicBindingModel, IPersonDetailsBindingModel
{
}
public class PersonService
{
private readonly ApplicationDbContext context;
public PersonService(ApplicationDbContext context)
{
this.context = context;
}
public Task Update(Person person, IPersonFullBindingModel source)
{
// CURRENT CODE: MAPPING NEEDED HERE.
person.Country = source.Country;
person.Name = source.Name;
// NEW MAP CODE:
// Map(source, person);
context.People.Update(person);
return context.SaveChangesAsync();
}
public Task Update(Person person, IPersonBasicBindingModel source)
{
// MAPPING NEEDED HERE.
person.Name = source.Name;
context.People.Update(person);
return context.SaveChangesAsync();
}
public Task Update(Person person, IPersonDetailsBindingModel source)
{
// MAPPING NEEDED HERE.
person.Country = source.Country;
context.People.Update(person);
return context.SaveChangesAsync();
}
internal Task<Person> GetAsync(int id)
{
return context.People.SingleOrDefaultAsync(p => p.Id == id);
}
}
public class CountryService
{
private readonly ApplicationDbContext context;
public CountryService(ApplicationDbContext context)
{
this.context = context;
}
internal Task<List<Country>> GetAvailableCountriesAsync()
{
return context.Countries.Where(c => c.IsAvailable).ToListAsync();
}
}
public class PersonController : Controller
{
private readonly PersonService personService;
private readonly CountryService countryService;
public PersonController(PersonService personService, CountryService countryService)
{
this.personService = personService;
this.countryService = countryService;
}
[HttpGet]
public IActionResult Index()
{
return View();
}
[HttpGet]
public async Task<IActionResult> Edit(int id)
{
var person = await personService.GetAsync(id);
var countries = await countryService.GetAvailableCountriesAsync();
if (person == null)
{
return NotFound();
}
// CURRENT CODE: MAPPING HERE
ViewData.Model = new PersonViewModel(person, countries);
// Instead of the constructor, it can be a factory-like method that returns a new instance:
// ViewData.Model = Map.From(person).From(countries);
// or
// ViewData.Model = Map.From(person, countries);
return View();
}
[HttpPost]
public async Task<IActionResult> Edit(IPersonFullBindingModel binding)
{
if (!ModelState.IsValid)
{
return await Edit(binding.Id);
}
var person = await personService.GetAsync(binding.Id);
if (person == null)
{
return BadRequest();
}
await personService.Update(person, binding);
// another approach (without a service) would be
// var updated = Map(person, binding)
// and save the updated object.
return RedirectToAction(nameof(Index));
}
}
```
I think that even without a mapper on the framework, using a file new template more like ☝️ will be enough.
Since at least part of this problem stems from people incorrectly using EF models in the views...how about just going in a different direction and ditching EF completely instead? Pushing people towards using EF as the default instead of good OSS community alternatives is just as bad as pusing people towards using a "new simple microsoft mapper" instead of Automapper/Tinymapper/Whatevermapper. Tbh, it's probably worse since EF can cause so much worse performance problems and encourage horrible patterns than a relatively small component such as an objectmapper. :trollface:
Oh, stick to the topic. Please avoid trolling like "ditch EF" and "good OSS community alternatives to EF". This is the ASP.NET repo by the way.
and it would be good to have more full featured sample apps
👍 Fully agree!
@abatishchev What is quite relevant to the topic is that whatever option Microsoft delivers as standard in their templates and teaches in their certification classes etc is what will be seen as "standard" by the majority of programmers and all other options no matter if they are better or worse will have an unfair disadvantage. It doesn't matter if its the ORM or the objectmapper or even the web framework itself. It doesnt matter if MS adopts automapper or if it makes its own, as long as it keeps pushing one option as the "official" one it will have an unfair advantage that is not based on the merit of the library itself but rather on the fact that MS at one point in time decided that it was the "official" one to recommend. This is damaging to the .net platform, to the oss community and to just plain making good software. While I admit that bringing up EF is off-topic, it's still there in plenty of the standard templates and standard examples of how to build an aspnet website making it the exact same situation as it will be with the objectmapper. It's not there by its own merit, it's there because MS made a decision to put it there and make it the default. If we are discussing adding comments and so on in samples/templates for "this is how you can do in the simple case, otherwise search for an objectmapper library on nuget if you need something more advanced" then shouldnt that strategy also be used for other external components such as an ORM, DI Container, etc. Have pure DI as the default and add a comment for "this is how you do it in the simple case, otherwise search for a DI container on nuget if you need something more advanced", have plain ado.net code as the default and add a comment for "this is how you do it in the simple case, otherwise search for an ORM on nuget if you need something more advanced".
_Why should we treat just the objectmapper differently in this case?_ Shouldnt all components that are not part of the core aspnet be treated equally no matter if they are an objectmapper, di container, orm or something else? Let libraries compete based on their merit, not on which library has the official blessing of microsoft.
Maybe instead of debating including AutoMapper we should consider including Mediatr instead so folks know they don't have to write this much code.
Sent from my iPhone
On Mar 21, 2017, at 10:17 PM, Bart Calixto notifications@github.com wrote:
I think it would be good to shared a kinda complete template with some code of what/where this will impact.
It's important to note how few code is around the mapping. I don't want, nor like to have AutoMapper as default. I don't need all it's complex stuff and also in my experience, it was easier to mess it up than doing plain.
The other idea here is that from my experience, BindingModels are plain contracts, and an Interface suits great for contracts, but they are not always possible to use, maybe something can be done on this front.
So, here is what it looks like. (I omitted the nested BindingModels inside a view model for brevity, but that's also another area I think the model binder can be improved too.)
public class ApplicationDbContext : DbContext
{
public DbSetPeople { get; set; }
public DbSetCountries { get; set; }
}public class Country
{
public int CountryId { get; set; }
public string Name { get; set; }
public bool IsAvailable { get; set; }
}public class Person
{
public int Id { get; set; }public string Name { get; set; } public Country Country { get; set; } public bool IsAdmin { get; set; }}
public class PersonViewModel : IPersonFullBindingModel // optional but useful interface here.
{
public PersonViewModel(Person person, ListavailableCountries)
{
// CURRENT CODE: MAPPING NEEDED HERE.
Id = person.Id;
Name = person.Name;
IsAdmin = person.IsAdmin;
Country = person.Country;
Countries = availableCountries;
// NEW MAP CODE: of course, it doesn't need to be here.
// Map(person, this);
}public int Id { get; } public string Name { get; } public bool IsAdmin { get; } public List<Country> Countries { get; } public Country Country { get; }}
public interface IPersonBasicBindingModel
{
[Required]
int Id { get; }[Required] [MinLength(3)] string Name { get; }}
public interface IPersonDetailsBindingModel
{
[Required]
Country Country { get; }
}public interface IPersonFullBindingModel : IPersonBasicBindingModel, IPersonDetailsBindingModel
{}
public class PersonService
{
private readonly ApplicationDbContext context;public PersonService(ApplicationDbContext context) { this.context = context; } public Task Update(Person person, IPersonFullBindingModel source) { // CURRENT CODE: MAPPING NEEDED HERE. person.Country = source.Country; person.Name = source.Name; // NEW MAP CODE: // Map(source, person); context.People.Update(person); return context.SaveChangesAsync(); } public Task Update(Person person, IPersonBasicBindingModel source) { person.Name = source.Name; context.People.Update(person); return context.SaveChangesAsync(); } public Task Update(Person person, IPersonDetailsBindingModel source) { person.Country = source.Country; context.People.Update(person); return context.SaveChangesAsync(); } internal Task<Person> GetAsync(int id) { return context.People.SingleOrDefaultAsync(p => p.Id == id); }}
public class CountryService
{
private readonly ApplicationDbContext context;public CountryService(ApplicationDbContext context) { this.context = context; } internal Task<List<Country>> GetAvailableCountriesAsync() { return context.Countries.Where(c => c.IsAvailable).ToListAsync(); }}
public class PersonController : Controller
{
private readonly PersonService personService;
private readonly CountryService countryService;public PersonController(PersonService personService, CountryService countryService) { this.personService = personService; this.countryService = countryService; } [HttpGet] public IActionResult Index() { return View(); } [HttpGet] public async Task<IActionResult> Edit(int id) { var person = await personService.GetAsync(id); var countries = await countryService.GetAvailableCountriesAsync(); if (person == null) { return NotFound(); } // CURRENT CODE: MAPPING HERE ViewData.Model = new PersonViewModel(person, countries); // Instead of the constructor, it can be a factory-like method that returns a new instance: // ViewData.Model = Map.From(person).From(countries); // or // ViewData.Model = Map.From(person, countries); return View(); } [HttpPost] public async Task<IActionResult> Edit(IPersonFullBindingModel binding) { if (!ModelState.IsValid) { return await Edit(binding.Id); } var person = await personService.GetAsync(binding.Id); if (person == null) { return BadRequest(); } await personService.Update(person, binding); // another approach (without a service) would be // var updated = Map(person, binding) // and save the updated object. return RedirectToAction(nameof(Index)); }}
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
@DamianEdwards and @shanselman make some explanation about this topic in the asp.net community standup https://youtu.be/9Rb7JJixw4o?t=26m49s
It's more clear to me. Thx
@wastaz I don't know if recommending a single library will help push my library over others at this point, as it's years older and a couple orders of magnitude more NuGet downloads than all others combined. From my perspective it's more akin to the JSON.Net decision (though not exactly).
In that case, there were several clones of the library offering not-really-any-different features. Afterwards, libraries emerged that actually differentiated (rather than competed).
Spitballing for example, no one's built a mapper on Roslyn. That's different. It would potentially provide better stack traces and easier debugging. I probably would never do it because I view platform support as a feature, and Roslyn, at the moment, is a narrower platform than NetStandard1.1 that I support today. It would be neat if mapper libraries emerged that had differentiated feature sets than what I had.
I think this entire thread illustrates that there's simply too much code in the templates. Templates, IMO, are not for the "newbie" developer. They're for every developer to get started faster with File|New Project, and that doesn't work if there's superfluous code in it. If you want stuff for newbies, then create samples or create secondary templates that target or illustrate some use case.
@benaadams
Looking at the database landscape is this not like complaining that SqlCommand (and other db variants) taking parameters to avoid sql injection is stifling the OSS community around ORMs?
No, but EF does. EF effectively killed almost all ORMs. E.g. NHibernate was thriving, it's not today. MS promotes it as if it's the only tool there is. And that's the whole point of this thread: as soon as MS releases a library of their own, they tell everyone it's 'the' choice to pick: there are numerous examples of that. Sure not everyone will follow MS' advice, but a lot will ("Why not use MS' stuff? It can't be bad, right?").
There are other things: an MS' library, even if it's OSS, has likely a bigger budget than an OSS library: it has devs who work on it, likely full time, testers, people writing docs, evangelists promoting it, you name it. An OSS lib doesn't: it depends on contributions from volunteers.
TL,DR: a MS default will have a negative effect on its OSS' counterparts. We simply shouldn't want this. I like the idea of @iancooper: it would be better if the OSS lib would join the .NET foundation and at the same time that MS would contribute to those libs instead. It solves the problem that an MS default kills off an OSS counterpart, but it also solves the problem of companies not wanting to use non-MS software: they can now use a .NET foundation library, it can't get more official than that.
@benaadams Taken to it's extreme, how do you even define what MS is allowed to build? So they shouldn't build MVC at all, by this reckoning. They should build a framework with string manipulation and a bit of socket programming and maybe ADO.NET and leave the rest to OSS. Who cares whether they put a class into a template/library for mapping? It's up to them, and AutoMapper will not be weakened by it. If they use AutoMapper (it's possible to use AutoMapper without any configuration, yes?) then that's fine too.
Oh and anyone who says NHibernate is somehow better than EF is living in a cuckoo clock. I could never get that thing working properly. With EF it "just works" in minutes, and then any issues you might run into with EF (accidental SELECT N+1 through lazy loading etc) are not issues one would be immune from in NH anyway.
They're for every developer to get started faster with File|New Project, and that doesn't work if there's superfluous code in it.
Would be nice if there was a proper templating system in ASP.NET similar to what you get in a lot of OSS, like the Angular CLI, when you create it, asks you if you want less or scss, if you want routing, etc.
That way MS could supply an out of the box template which is configurable. But the community could supply basic templates which are described in some DSL form.
New ASP.NET Core
-> Do you want EF?
-> Do you want an object mapper?
-> Do you want the kitchen sink?
Then someone could create one which asks:
-> Do you want Dapper?
-> Do you want Automapper?
-> Do you want SignalR?
@phillip-haydon this exists already in the form of yeoman. The community is already handling generation of templates very well in my experience. For example, aspnetcore.
@phillip-haydon @smudge202 That exists already. It's called dotnet/templating, here is how to use it and here is an API project template built using it which has over a dozen optional features which you can set over the command line like so:
dotnet new --install Boilerplate.Templates::* to install the project template.dotnet new bapi --help to see how to select the features of the project.dotnew new bapi --name "MyTemplate" along with any other custom options to create a project from the template.OT here but one cli to rule them all... did I miss the memo where the dotnet cli was replacing bash?
The extensibility model is all well and good but I don't understand the rationale for dotnet test, build, pack, new etc, it replicates/replaces discreet binaries that already do these things and in the process seems to cause a lot of additional effort. Effort that could be spend on enriching the .net core x-plat support.
It goes against the *nix philosophy of piping which IMO has stood the test of time. Will dotnet cli be around in 30 years time or will it drown in a thousand verbs under it's own ambition?
I think the x-plat vision for .net core is tremendous, typescript is lovely and rosyln, the most interesting thing to happen to compilers in decades; but there are so many choices being made for core like this one which are not progressing that effort and instead re-inventing yeoman, nuget, msbuild, test runners, ioc containers and now object mapping. It seems as confused as the version schemes and a sincere but misguided effort to please everyone but will end up pleasing no one.
MS I don't think this is working... It's not you ... it me! ;-)
Respectfully, this statement makes no sense. It's comparing apples and
carburetors. "dotnet cli was replacing bash." The dotnet CLI is similar to
the node/express CLIs, the angular CLI, the go CLI, etc. It's not a prompt,
it's not a REPL (yet). It's a driver, and is comparable to go, java,
python, ruby, and on and on.
On Wed, Mar 22, 2017 at 12:40 PM, Scott Mackay notifications@github.com
wrote:
OT here but one cli to rule them all... did I miss the memo where the
dotnet cli was replacing bash?The extensibility model is all well and good but I don't understand the
rationale for dotnet test, build, pack, new etc, it replicates/replaces
discreet binaries that already do these things and in the process seems to
cause a lot of additional effort. Effort that could be spend on enriching
the .net core x-plat support.It goes against the *nix philosophy of piping which IMO has stood the test
of time. Will dotnet cli be around in 30 years time or will it drown in a
thousand verbs under it's own ambition?I think the x-plat vision for .net core is tremendous, typescript is
lovely and rosyln, the most interesting thing to happen to compilers in
decades; but there are so many choices being made for core like this one
which are not progressing that effort and instead re-inventing yeoman,
nuget, msbuild, test runners, ioc containers and now object mapping. It
seems as confused as the version schemes and a sincere but misguided effort
to please everyone but will end up pleasing no one.MS I don't think this is working... It's not you ... it me! ;-)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/aspnet/Mvc/issues/5883#issuecomment-288515354, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AAALTGeJbg9Lm6RMRG9XvGUM3RxP3ZHUks5roXkRgaJpZM4MRuBp
.
--
Scott Hanselman
Donate to fight diabetes: http://hnsl.mn/fightdiabetes
Discussion shifted into another subject: templates. As a matter of fact building templates for visual studio projects is as easy as creating a project containing whatever you want to put in the tamplate, and then replacing some "fixed names" with "placeholder names". So if there is an issue with the current default template we may simply promote a Github repos where people may contribute templates specialized for various purpose: newbies, starting project, starting project three layers, etc....
About the main subject.
Thinking more deeply on the subject, what I don't like of this "path" is the "focus on object mapping", instead of separation of layers. Here the focus should be: "repository pattern," and "avoiding references to business objects in the Mvc layer", stop.
Object mapping + ViewModels (and/or DTOs) is just a way to reach the goal. There are several others such as, for instance:
Using and model bindining interfaces insteaad of classes. Then one might put the same business object behind several interfaces, thus avoiding object copying.
The interface between UI and business layer is a Json interface. Good paradigm that works better in distributed environments and in the cloud(microservices for instance). In this case both layers may communicate through interfaces that are then serialized/deserialized in jSon. Each layer choose different implementation of the same interfaces and Json Serializer/Deserializer substitutes object mappers.
And also when using object mapping a more repository centric approach might be taken instead of using general purpose mappers.
So why leaving people with the idea they MUST use object mappers ?
Here a thread about usage of interfaces instead of object mappers.
I am not saying that object mappers are not useful, but just they are one of several choices. Which is the more adequate depends on the overall system architecture.
@frankabbruzzese your link is pointing to Gmail
@frankabbruzzese no. The repository pattern is already misused, and a misunderstood design pattern.
MS's documentation shouldn't be: 'this is how things are done'
MS's documentation is to show people how to use MVC. It's documentation can show some examples of using object mapping, repositories, etc etc, with warning flags above it. But it simply cannot be an authority on how development is done.
@shaynevanasperen , I updated the wrong link in my previous post, now it works. sorry :).
@phillip-haydon ,
"MS's documentation is to show people how to use MVC. It's documentation can show some examples of using object mapping, repositories, etc etc, with warning flags above it. But it simply cannot be an authority on how development is done."
I agrre with you, but unluckly a lot of people interpret "examples" like "MUST BE THIS WAY", so the point is what examples must be about, and mainly how default template ...or better templates (I would like to have several template to choose) should look like.
Remainig with feet on earth, if you read the initial @danroth27 post the main reason they want to introduce object mapping in their templates is they don't want to expose unused properties of DB objects in the views, and obviously to the model binder, since probably they know a lot of people would leave the code as it is (which might cause vulnerabilities and other problems). So no intention to impose patterns, but just a practical reason.
This problem, is more easily solved with the interfaces approach I mentioned in my previous post: the business object might be exposed through interfaces containing just subsets of the object properties.
All that is needed is a binder for interfaces. Better investing on this, that is useful in its own that on object mapping! There is also some validation problem to be solved, but nothing so terrible!
Thanks everyone for the feedback on this issue! At this time we've decided to not tackle this feature, but instead point folks to the many existing .NET community solutions.
@danroth27 Btw, my offer still stands - if there is something missing (features or usability or barrier for entry) from AutoMapper that precluded the team from including it, I'd love to address it.
@jbogard since you ask, I'll take the chance to ask what I would like:
I would like a package that doesn't brings all the configuration complexity and full featured automapper, like only mapping type to type without any further complexity in a lightweight package of the core usage of Map, few kbs/classes/methods.
MAYBE adding a mapper via interface strategy (besides class to class) and that's it. :)
@Bartmax Ah, you want a new mapper! Ostensibly with a different philosophy - all mapping libraries started as small as you say (even AutoMapper of course - though flattening was added nearly immediately) but inevitably grew from the long tail of edge cases. If the mapper was suitably constrained, you wouldn't need to test conventions.
I had thought about a "strict" vs "loose" mode of mapping that doesn't require config. But because AutoMapper supports so many scenarios, this would just get you in trouble. So I discourage everyone from using this feature as much as possible. I get enough crap about people abusing AutoMapper, I don't want exacerbate it.
As for size - I think I can make a lot of headway there. AutoMapper supports several different mapping scenarios outside of "object to object" - LINQ projections, expression mappings for OData and more. I'll take a closer look at that!
Thanks for the feedback!
@jbogard the core premise i've always found missing on AutoMapper is on Mapster RequireDestinationMemberSource. The amount of effort required to configure mappings to pass AssertConfigurationIsValid() in AutoMapper has always just been too high for me. In almost every single mapping scenario I care absolutely nothing about the source object, I only care about the destination object being fully hydrated and want to fail fast if it can't be.
@dotnetchris fyi you can decide how you want validation to happen on CreateMap - "All destination members must be mapped" (default), "All source members must be mapped" or "Neither must be mapped". I'm a little surprised - your scenario of "all destination members must be mapped" has been the default in AutoMapper since....2009? Maybe there's something I'm missing tho. Open a GH issue if you remember the details if you dont mind.
@jbogard i believe the issue occurs that AssertConfigurationIsValid() throws an exception for source properties that are not ignored. honestly it's been several years since i've used automapper because i was never able to be happy with the behavior.
@dotnetchris I think you will find what you're looking for in this post: http://stackoverflow.com/questions/954480/automapper-ignore-the-rest/31182390#31182390
.ForAllOtherMembers(x=>x.Ignore());
@dotnetchris AutoMapper has the opposite behavior, for destination properties, not source. @shaynevanasperen that was a hack - you've got an enum now that lets you decide which members you want to validate - source/destination/none.
@Bartmax ,
While what you are asking for might appear reasonable, a detailed analisys shows that it is impossible.
First of all, a simple type mapping that is just name based is totally uneuseful, since instead of copying the object one might simply hidde it behind various interfaces.
Second, if you use a DB you need also a projection operator, otherwise you might extract from DB more columns that you need. Also in this case you might avoid using DTO by specifying the properties you need with an interface (only the properties of the interface are retrieved.)
Actually, what makes copying necessary are "exceptions", that is, properties of the target that somehow have no direct correspondence with properties of the source object. So any mapping library that makes sense should handle somehow these exceptions.
In order to avoid configuration one might pass an expression to both mapping and projection that speciies just how to handle exceptions:
...Map<T, T1>(m => new Target{prop1=....});
...Proj<T, T1>(m => new Target{prop1=....});
Where one specifies just exceptions, while all other assignements are inferred automatically.
Unluckl,y a similar solution would be very slow, since in both Proj, and Map, the expression needs a complex pre-processing before being used to perform the copy, and in the case of the Map it should be also compiled. Thus we need to cache both processed expression sand compiled code for Map. However, caching with a T, T1 key is possible only if the expression passed is always the same for each T, T1 pair. Thus caching may be achieved only by moving the expression argument out from Map and Proj into a configuration instruction that defines the way to process the T, T1 pait once and for all.
Therefore, both exceptions handling, and configuration can't be avoided!
In my opinion the best solution would be enriching languages with object copy instructions where you specify just the "exceptions" (as in the expression arguments in the code snippets before) and all other assignements are inferred automatically. In this case no cache would be necessary since assignement instructions are created at compile time instead of run-time. This would solve efficiently all problems while keeping maximim flexibility.
Why to put anything in the language what can be (and successfully years ago) in a library? Let's don't exercise this direction.
@abatishchev , simple, because all mapping libraries adds not needed complexity trying to mimic at run-time the compiler behavior by manipulating and compiling expressions. With compile time support there would be no need for any configuration it would be enough to write something like
`
...Map
`where just "exceptions" are explicitely listed in the assignements, while all same name convention properties are matched automatically. On the contrary run-time libraries need configuration to factor out once and for all time spent manipulating and compiling expressions. Moreover, with compile time support there is no need to associate a mapping to the pair T, T1, but each mapping instruction may have a different mapping rule, since the work needed to manipulate and compile expressions is spent at compile time not at run-time.
Anyway, this discussion is just a theoric excercise. For sure C# will not be modified because of this discussion :). Maybe, this will happen in the future when more compelling needs will claim a similar extension.
I would want to use a different mapper for different clients based on clients requirements. Some hate Automapper because of size and performance (both debatable). I personally would like a very basic mapper (that was already there in .NET core 1.x perhaps, ITranslator???) with a possibility to swap it with any other mapper of choice for a client (yes most of my clients are indeed technical & choosy) without the headache of breaking existing code.
This also helps new programmers and for personal projects which only have a very basic mapping need.
Is it too much to ask from MS?
Yes. It's not needed.
Should have kept it closed source. It would have been a lot better :P
cheers
We should something not needed be added? Why do you need the kitchen sink added? Shouldn't MS focus on making everything else awesome instead of adding useless features?
Can this thread be locked?
@phillip-haydon - it's been quiet for 3 months, not too bad for such a "hot" thread 😄 If this thread causes too much noise for people we will consider locking it. BTW anyone can easily "unsubscribe" from the thread's notifications by scrolling up about 5,000,000 pages from here and clicking Unsubscribe 😄 But, we do welcome the discussion - after all, it was the discussion in this very thread that helped us reevaluate what we were doing in this space, and I think most people agree things ended up in the right place.
Most helpful comment
Why not leverage automapper for this?