automapper - how to map object list - c#

Let us say my domain object can contain a bunch of objects like this:
List<Thing> Things
where Thing is defined like this:
class Thing
(
public int ThingId { get; set; }
public string ThingName { get; set; }
)
My DTO contains
List<string> ThingIds;
List<string> ThingNames;
The question is how can I use automapper to map Things to the 'relevant bits' in the DTO?
Thanks.
Christian

By writing custom resolver, i guess.
That's quite unusual requirement - to lose binding between id and name.
I think you are right. sorry I am still learning about the dto/viewmodel mapping. Do you think it is acceptable to put a domain object inside a DTO as there is not much point in creating a dto for Thing?
Do not mix domain model inside view model. You will regret that next week (i did for sure...).
class Thing {
public int ThingId { get; set; }
public string ThingName { get; set; }
public string UnnecessaryProp {get;set;}
}
class ThingViewModel {
public int ThingId { get; set; }
public string ThingName { get; set; }
}
class MyView {
public IEnumerable<ThingViewModel> Things {get;set;}
}
Here You can find some more thoughts about view model.

Related

Is is good practice to have same type of list in a class?

I have created a class and I'm putting a list of same type as a property of that class.
Is it good or bad practice?
I am putting the same type of list because of I want to manage everything by only one object.
I don't want to create a single object and a list of object of the same type.
Any help is highly appreciated!
class AssetSection
{
public string Code { get; set; }
public string Description { get; set; }
public string SITEID { get; set; }
public string PlantID { get; set; }
public string User { get; set; }
public string UpDateTime { get; set; }
public List<AssetSection> AssetSections { get; set; }
public AssetSection(string des, string code)
{
Description = des;
Code = code;
}
}
That's ok. If you can imagine, you can design and use it.
Let's talk about entity framework. We create 2 entities like this:
public class User : IdentityUser
{
[Key]
public string Id { get; set; }
public UserProfile Profile { get; set; }
}
public class UserProfile
{
[Key]
public string UserId { get; set; }
public User User { get; set; }
}
Now, when we try to get current user:
User user = await _userManager.GetUserAsync(User);
user becomes an instance of User class now. This instance has a property name Profile, and this property has another property name User which has a type User.
It's called mapping. So, to answer your question: You can use it. But I'm not saying it's good or not based on the way to design the model.
As a general observation, such a structure is known as a rose tree, or just a tree. It enables you to write code like this:
var t = new AssetSection("foo", "bar")
{
AssetSections = new List<AssetSection>
{
new AssetSection("baz", "qux")
{
new AssetSection("corge", "garply"),
new AssetSection("fred", "plugh")
{
AssetSections = new List<AssetSection>
{
new AssetSection("xyzzy", "thud")
}
}
},
new AssetSection("quux", "quuz")
{
new AssetSection("grault", "waldo")
}
}
};
If what you want to model is a tree-like structure like that, then it's fine. On the other hand, if such a hierarchy is not what you're trying to model, then it's likely to be confusing.
By the way, the code as proposed violates the .NET framework design guidelines:
DO NOT provide settable collection properties.
DO NOT use ArrayList or List<T> in public APIs

Facade a class without writing lots of boilerplate code?

Let's say I have a class from a 3rd-party, which is a data-model. It has perhaps 100 properties (some with public setters and getters, others with public getters but private setters). Let's call this class ContosoEmployeeModel
I want to facade this class with an interface (INavigationItem, which has Name and DBID properties) to allow it to be used in my application (it's a PowerShell provider, but that's not important right now). However, it also needs to be usable as a ContosoEmployeeModel.
My initial implementation looked like this:
public class ContosoEmployeeModel
{
// Note this class is not under my control. I'm supplied
// an instance of it that I have to work with.
public DateTime EmployeeDateOfBirth { get; set; }
// and 99 other properties.
}
public class FacadedEmployeeModel : ContosoEmployeeModel, INavigationItem
{
private ContosoEmployeeModel model;
public FacadedEmployeeModel(ContosoEmployeeModel model)
{
this.model = model;
}
// INavigationItem properties
string INavigationItem.Name { get; set;}
int INavigationItem.DBID { get; set;}
// ContosoEmployeeModel properties
public DateTime EmployeeDateOfBirth
{
get { return this.model.EmployeeDateOfBirth; }
set { this.model.EmployeeDateOfBirth = value; }
}
// And now write 99 more properties that look like this :-(
}
However, it's clear that this will involve writing a huge amount of boilerplate code to expose all the properties , and I'd rather avoid this if I can. I can T4 code-generate this code in a partial class, and will do if there aren't any better ideas, but I though I'd ask here to see if anyone had any better ideas using some super wizzy bit of C# magic
Please note - the API I use to obtain the ContosoEmployeeModel can only return a ContosoEmployeeModel - I can't extend it to return a FacededEmployeeModel, so wrapping the model is the only solution I can think of - I'm happy to be corrected though :)
The other approach may be suitable for you is to use AutoMapper to map base class to your facade here is sample code:
class Program
{
static void Main(string[] args)
{
var model = new Model { Count = 123, Date = DateTime.Now, Name = "Some name" };
Mapper.CreateMap<Model, FacadeForModel>();
var mappedObject = AutoMapper.Mapper.Map<FacadeForModel>(model);
Console.WriteLine(mappedObject);
Console.ReadLine();
}
class Model
{
public string Name { get; set; }
public DateTime Date { get; set; }
public int Count { get; set; }
}
interface INavigationItem
{
int Id { get; set; }
string OtherProp { get; set; }
}
class FacadeForModel : Model, INavigationItem
{
public int Id { get; set; }
public string OtherProp { get; set; }
}
}
Resharper allows the creation of "delegating members", which copies the interface of a contained object onto the containing object and tunnels the method calls/property access through to the contained object.
http://www.jetbrains.com/resharper/webhelp/Code_Generation__Delegating_Members.html
Once you've done that, you can then extract an interface on your proxy class.

automapper: skipping/ignoring nested types

I'm trying to create a map between a domain object and viewmodel to support a use case that feels quite common. The fact that I can't find a solution makes me think I'm approaching the problem incorrectly. Here's some psuedo code that represents my source and destination types:
public class DomainClass
{
public NestedDomainClass1 NestedDomainClass1{ get; set; }
}
public class NestedDomainClass1
{
public NestedDomainClass2 NestedDomainClass2 { get; set; }
}
public class NestedDomainClass2
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
}
public class DomainViewModel
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
}
As you can see, DomainViewModel maps perfectly to DomainClass.NestedDomainClass1.NestedDomainClass2. However, for reasons that aren't entirely relevant, I can't simply create a mapping at that level. Instead I have to map two levels higher:
Mapper.CreateMap<DomainObj, DomainViewModel>();
This is unfortunate, as the minute I do this, I can no longer rely on AutoMapper conventions to automagically map similarly named properties, and I end having to write a lot of highly repetitive code:
Mapper.CreateMap<DomainClass, DomainViewModel>().ForMember(dest=>dest.PropertyA, opt=>opt.MapFrom(source=>source.NestedDomainClass1.NestedDomainClass2.PropertyA));
Mapper.CreateMap<DomainClass, DomainViewModel>().ForMember(dest=>dest.PropertyB, opt=>opt.MapFrom(source=>source.NestedDomainClass1.NestedDomainClass2.PropertyB));
I've played with the RecognizeDestinationPrefixes and RecognizeDestinationPostfixes methods in the hopes of getting AutoMapper to "skip" directly to the property I'd like to map from (NestedDomainClass2), but no luck. Any help would be appreciated!
That's because you're trying map between two completely different types. You really need to do something like this:
Mapper.CreateMap<NestedDomainClass2, DomainViewModel>();
Mapper.AssertConfigurationIsValid();
var dvm = Mapper.Map<NestedDomainClass2, DomainViewModel>
(obj.NestedDomainClass1.NestedDomainClass2);
However if you want to, you can hide that detail by defining a TypeConverter. Something like this should work:
public class DomainTypeConverter : TypeConverter<DomainClass, DomainViewModel>
{
protected override DomainViewModel ConvertCore(DomainClass source)
{
return Mapper.Map<NestedDomainClass2, DomainViewModel>
(source.NestedDomainClass1.NestedDomainClass2);
}
}
You can then define your mapping to be something like this:
Mapper.CreateMap<NestedDomainClass2, DomainViewModel>();
Mapper.CreateMap<DomainClass, DomainViewModel>()
.ConvertUsing(new DomainTypeConverter());
Mapper.AssertConfigurationIsValid();
And use it like this:
var dvm = Mapper.Map<DomainClass, DomainViewModel>(dc);

Cloning A Class

I have two classes which contain the same fields, however one inherits some properties from somewhere else and the other does not.
I have created a generic list using the class "ZEUS_ResearchStocksHistory" , but then I need to clone all of the fields over to the other list "ZEUS_ResearchStocksHistoryWithExcel". I don't want to have to loop through each field in one list and populate the other, or write some sort of linq join, there must be a faster way?
The reason I can't use the same class in both instances is that when inheriting the ExcelReport function it adds additional fields which I do not want when I display this list in a data grid.
internal class ZEUS_ResearchStocksHistory
{
public String Amendment { get; set; }
public String AmendedBy { get; set; }
public String Sedol { get; set; }
public String Date { get; set; }
}
internal class ZEUS_ResearchStocksHistoryWithExcel : ExcelReport
{
public String Amendment { get; set; }
public String AmendedBy { get; set; }
public String Sedol { get; set; }
public String Date { get; set; }
}
Is this possible?
Thanks
Did you have a look at automapper?
example from codeproject:
CustomerViewItem customerViewItem =
Mapper.Map<Customer, CustomerViewItem>(customer);
Check out Automapper, which is designed to do exactly this. Automapper is up on NuGet.
http://lostechies.com/jimmybogard/2009/01/23/automapper-the-object-object-mapper/
You could do something as simple as:
Mapper.CreateMap<ZEUS_ResearchStocksHistory, ZEUS_ResearchStocksHistoryWithExcel>();
var newObject = Mapper.Map<ZEUS_ResearchStocksHistory, ZEUS_ResearchStocksHistoryWithExcel>(oldObject);
Or, since you said you have a list, you could do:
var newList = oldList.Select(x => Mapper.Map<ZEUS_ResearchStocksHistory, ZEUS_ResearchStocksHistoryWithExcel>(x));

How to "DRY up" C# attributes in Models and ViewModels?

This question was inspired by my struggles with ASP.NET MVC, but I think it applies to other situations as well.
Let's say I have an ORM-generated Model and two ViewModels (one for a "details" view and one for an "edit" view):
Model
public class FooModel // ORM generated
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public int Age { get; set; }
public int CategoryId { get; set; }
}
Display ViewModel
public class FooDisplayViewModel // use for "details" view
{
[DisplayName("ID Number")]
public int Id { get; set; }
[DisplayName("First Name")]
public string FirstName { get; set; }
[DisplayName("Last Name")]
public string LastName { get; set; }
[DisplayName("Email Address")]
[DataType("EmailAddress")]
public string EmailAddress { get; set; }
public int Age { get; set; }
[DisplayName("Category")]
public string CategoryName { get; set; }
}
Edit ViewModel
public class FooEditViewModel // use for "edit" view
{
[DisplayName("First Name")] // not DRY
public string FirstName { get; set; }
[DisplayName("Last Name")] // not DRY
public string LastName { get; set; }
[DisplayName("Email Address")] // not DRY
[DataType("EmailAddress")] // not DRY
public string EmailAddress { get; set; }
public int Age { get; set; }
[DisplayName("Category")] // not DRY
public SelectList Categories { get; set; }
}
Note that the attributes on the ViewModels are not DRY--a lot of information is repeated. Now imagine this scenario multiplied by 10 or 100, and you can see that it can quickly become quite tedious and error prone to ensure consistency across ViewModels (and therefore across Views).
How can I "DRY up" this code?
Before you answer, "Just put all the attributes on FooModel," I've tried that, but it didn't work because I need to keep my ViewModels "flat". In other words, I can't just compose each ViewModel with a Model--I need my ViewModel to have only the properties (and attributes) that should be consumed by the View, and the View can't burrow into sub-properties to get at the values.
Update
LukLed's answer suggests using inheritance. This definitely reduces the amount of non-DRY code, but it doesn't eliminate it. Note that, in my example above, the DisplayName attribute for the Category property would need to be written twice because the data type of the property is different between the display and edit ViewModels. This isn't going to be a big deal on a small scale, but as the size and complexity of a project scales up (imagine a lot more properties, more attributes per property, more views per model), there is still the potentially for "repeating yourself" a fair amount. Perhaps I'm taking DRY too far here, but I'd still rather have all my "friendly names", data types, validation rules, etc. typed out only once.
I'll assume that your doing this to take advantage of the HtmlHelpers EditorFor and DisplayFor and don't want the overhead of ceremoniously declaring the same thing 4000 times throughout the application.
The easiest way to DRY this up is to implement your own ModelMetadataProvider. The ModelMetadataProvider is what is reading those attributes and presenting them to the template helpers. MVC2 already provides a DataAnnotationsModelMetadataProvider implementation to get things going so inheriting from that makes things really easy.
To get you started here is a simple example that breaks apart camelcased property names into spaces, FirstName => First Name :
public class ConventionModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
HumanizePropertyNamesAsDisplayName(metadata);
if (metadata.DisplayName.ToUpper() == "ID")
metadata.DisplayName = "Id Number";
return metadata;
}
private void HumanizePropertyNamesAsDisplayName(ModelMetadata metadata)
{
metadata.DisplayName = HumanizeCamel((metadata.DisplayName ?? metadata.PropertyName));
}
public static string HumanizeCamel(string camelCasedString)
{
if (camelCasedString == null)
return "";
StringBuilder sb = new StringBuilder();
char last = char.MinValue;
foreach (char c in camelCasedString)
{
if (char.IsLower(last) && char.IsUpper(c))
{
sb.Append(' ');
}
sb.Append(c);
last = c;
}
return sb.ToString();
}
}
Then all you have to do is register it like adding your own custom ViewEngine or ControllerFactory inside of Global.asax's Application Start:
ModelMetadataProviders.Current = new ConventionModelMetadataProvider();
Now just to show you I'm not cheating this is the view model I'm using to get the same HtmlHelper.*.For experience as your decorated ViewModel:
public class FooDisplayViewModel // use for "details" view
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[DataType("EmailAddress")]
public string EmailAddress { get; set; }
public int Age { get; set; }
[DisplayName("Category")]
public string CategoryName { get; set; }
}
Declare BaseModel, inherit and add another properties:
public class BaseFooViewModel
{
[DisplayName("First Name")]
public string FirstName { get; set; }
[DisplayName("Last Name")]
public string LastName { get; set; }
[DisplayName("Email Address")]
[DataType("EmailAddress")]
public string EmailAddress { get; set; }
}
public class FooDisplayViewModel : BaseFooViewModel
{
[DisplayName("ID Number")]
public int Id { get; set; }
}
public class FooEditViewModel : BaseFooViewModel
EDIT
About categories. Shouldn't edit view model have public string CategoryName { get; set; } and public List<string> Categories { get; set; } instead of SelectList? This way you can place public string CategoryName { get; set; } in base class and keep DRY. Edit view enhances class by adding List<string>.
As LukLed said you could create a base class that the View and Edit models derive from, or you could also just derive one view model from the other. In many apps the Edit model is basically the same as View plus some additional stuff (like select lists), so it might make sense to derive the Edit model from the View model.
Or, if you're worried about "class explosion", you could use the same view model for both and pass the additional stuff (like SelectLists) through ViewData. I don't recommend this approach because I think it's confusing to pass some state via the Model and other state via ViewData, but it's an option.
Another option would be to just embrace the separate models. I'm all about keeping logic DRY, but I'm less worried about a few redundant properties in my DTOs (especially on projects using code generation to generate 90% of the view models for me).
First thing i notice - you got 2 view models. See my answer here for details on this.
Other things that springs in mind are already mentioned (classic approach to apply DRY - inheritance and conventions).
I guess i was too vague. My idea is to create view model per domain model and then - combine them at view models that are per specific view. In your case: =>
public class FooViewModel {
strange attributes everywhere tralalala
firstname,lastname,bar,fizz,buzz
}
public class FooDetailsViewModel {
public FooViewModel Foo {get;set;}
some additional bull**** if needed
}
public class FooEditViewModel {
public FooViewModel Foo {get;set;}
some additional bull**** if needed
}
That allows us to create more complex view models (that are per view) too =>
public class ComplexViewModel {
public PaginationInfo Pagination {get;set;}
public FooViewModel Foo {get;set;}
public BarViewModel Bar {get;set;}
public HttpContext lol {get;set;}
}
You might find useful this question of mine.
hmm... turns out i actually did suggest to create 3 view models. Anyway, that code snippet kind a reflects my approach.
Another tip - i would go with filter & convention (e.g. by type) based mechanism that fills viewdata with necessary selectList (mvc framework can automagically bind selectList from viewData by name or something).
And another tip - if you use AutoMapper for managing your view model, it has nice feature - it can flatten object graph. Therefore - you can create view model (which is per view) that directly has props of view model (which is per domain model) whatever how much deep you want to go (Haack said it's fine).
These display names (the values) could perhaps be displayed in another static class with a lot of const fields. Wouldn't save you having many instances of DisplayNameAttribute but it would make a name change quick and easy to make. Obviously this is isn't helpful for other meta attributes.
If I told my team they would have to create a new model for every little permutation of the same data (and subsequently write automapper definitions for them) they'd revolt and lynch me. I'd rather model metadata that was, too some degree use aware. For example making a properties required attribute only take effect in an "Add" (Model == null) scenario. Particularly as I wouldn't even write two views to handle add/edit. I would have one view to handle the both of them and if I started having different model classes I'd get into trouble with my parent class declaration.. the ...ViewPage bit.

Categories

Resources