System.InvalidOperationException' occurred in AutoMapper.dll. Additional information: Mapper not initialized - c#

I use to find AutoMapper very simple to use. I am struggling with the new version. I have two types:
namespace VehicleMVC.Models
{
public class CarModel
{
public int id { get; set; }
public string make { get; set; }
public string model { get; set; }
}
}
and:
namespace Business
{
public class Car
{
private int _id;
private string _make;
private string _model;
public int id
{
get { return _id; }
set { _id = value; }
}
public string make
{
get { return _make; }
set { _make = value; }
}
public string model
{
get { return _model; }
set { _model = value; }
}
}
}
I have tried this in CarController:
public CarController()
{
service = new Service.Service();
//Mapper.Initialize(cfg => cfg.CreateMap<Business.Car,CarModel>());
//Mapper.Initialize(cfg => cfg.CreateMap<List<CarModel>, List<Business.Car>>());
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Business.Car, CarModel>();
} );
config.AssertConfigurationIsValid();
}
private CarModel getCarModel(Business.Car BusinessCar)
{
CarModel CarModel = AutoMapper.Mapper.Map<CarModel>(BusinessCar);
return CarModel;
}
The error I get is: An exception of type 'System.InvalidOperationException' occurred in AutoMapper.dll. Additional information: Mapper not initialized. Call Initialize with appropriate configuration. but was not handled in user code. What is wrong?

Once you have created your configuration, you must initialize the mapper with it:
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Business.Car, CarModel>();
};
config.AssertConfigurationIsValid();
Mapper.Initialize(config);

Related

Fixing WCF Deserialization Error : Invalid Message Body

I'm setting up a new WCF service on a new server I got, but when I try to access the service through a xamarin application I get the following error
"Error in deserializing body of request message for operation 'GetString'. OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name 'GetString' and namespace 'http://tempuri.org/'. Found node type 'Element' with name 'GetStringAsync' and namespace 'http://tempuri.org/'"
I have used the method of creating a proxy (with a class library and connected service) for creating the client to be used in my xamarin application. I have used this exact method before without any problems, but now I can't seem to get this to work.
I have tried googling this, but the only similar errors I could find were where the methods name were the same, but the namespace as mentioned above was different which does not apply in my specific error. I have recreated the project, and redeployed a few times without any success.
IService
[ServiceContract]
public interface IPM_Service
{
[OperationContract]
List<dbUsersModel> GetUsers();
[OperationContract]
int InsertUser(dbUsersModel user, int userid);
[OperationContract]
string GetString(string test);
}
IService Implementation
public class PM_Service : IPM_Service
{
xamPropertyManagementEntities Entity = new xamPropertyManagementEntities();
public List<dbUsersModel> GetUsers()
{
var data = Entity.SP_SELECT_USERS().ToList();
List<dbUsersModel> users = new List<dbUsersModel>();
foreach (var item in data)
{
users.Add(new dbUsersModel() { dbUserID = item.USR_ID, dbUserName = item.USR_NAME, dbUserSurname = item.USR_SURNAME, dbUserUsername = item.USR_USERNAME, dbUserPassword = item.USR_PASSWORD, dbUserIDNo = item.USR_IDNO, dbUserContactNo = item.USR_CONTACTNO, dbUserEmail = item.USR_EMAIL, dbUserAddress1 = item.USR_ADDRESS1, dbUserAddress2 = item.USR_ADDRESS2, dbUserAddress3 = item.USR_ADDRESS3, dbUserAddress4 = item.USR_ADDRESS4 });
}
return users;
}
public int InsertUser(dbUsersModel user, int userid)
{
var insert = Entity.SP_INSERT_USER(user.dbUserUsername, user.dbUserPassword, user.dbUserName, user.dbUserSurname, user.dbUserIDNo, user.dbUserContactNo, user.dbUserEmail, user.dbUserAddress1, user.dbUserAddress2, user.dbUserAddress3, user.dbUserAddress4, userid);
decimal? returnID = insert.SingleOrDefault().Value;
int id = (int)returnID.DefaultIfEmpty(0);
return id;
}
public string GetString(string test)
{
return test;
}
}
public class dbUsersModel
{
public int dbUserID { get; set; }
public string dbUserUsername { get; set; }
public string dbUserPassword { get; set; }
public string dbUserName { get; set; }
public string dbUserSurname { get; set; }
public string dbUserIDNo { get; set; }
public string dbUserContactNo { get; set; }
public string dbUserEmail { get; set; }
public string dbUserAddress1 { get; set; }
public string dbUserAddress2 { get; set; }
public string dbUserAddress3 { get; set; }
public string dbUserAddress4 { get; set; }
}
Proxy Code
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// //
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace PMProxy
{
using System.Runtime.Serialization;
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("dotnet-svcutil", "1.0.0.1")]
[System.Runtime.Serialization.DataContractAttribute(Name="dbUsersModel", Namespace="http://schemas.datacontract.org/2004/07/PM_Service")]
public partial class dbUsersModel : object
{
private string dbUserAddress1Field;
private string dbUserAddress2Field;
private string dbUserAddress3Field;
private string dbUserAddress4Field;
private string dbUserContactNoField;
private string dbUserEmailField;
private int dbUserIDField;
private string dbUserIDNoField;
private string dbUserNameField;
private string dbUserPasswordField;
private string dbUserSurnameField;
private string dbUserUsernameField;
[System.Runtime.Serialization.DataMemberAttribute()]
public string dbUserAddress1
{
get
{
return this.dbUserAddress1Field;
}
set
{
this.dbUserAddress1Field = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string dbUserAddress2
{
get
{
return this.dbUserAddress2Field;
}
set
{
this.dbUserAddress2Field = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string dbUserAddress3
{
get
{
return this.dbUserAddress3Field;
}
set
{
this.dbUserAddress3Field = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string dbUserAddress4
{
get
{
return this.dbUserAddress4Field;
}
set
{
this.dbUserAddress4Field = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string dbUserContactNo
{
get
{
return this.dbUserContactNoField;
}
set
{
this.dbUserContactNoField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string dbUserEmail
{
get
{
return this.dbUserEmailField;
}
set
{
this.dbUserEmailField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public int dbUserID
{
get
{
return this.dbUserIDField;
}
set
{
this.dbUserIDField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string dbUserIDNo
{
get
{
return this.dbUserIDNoField;
}
set
{
this.dbUserIDNoField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string dbUserName
{
get
{
return this.dbUserNameField;
}
set
{
this.dbUserNameField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string dbUserPassword
{
get
{
return this.dbUserPasswordField;
}
set
{
this.dbUserPasswordField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string dbUserSurname
{
get
{
return this.dbUserSurnameField;
}
set
{
this.dbUserSurnameField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string dbUserUsername
{
get
{
return this.dbUserUsernameField;
}
set
{
this.dbUserUsernameField = value;
}
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("dotnet-svcutil", "1.0.0.1")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="PMProxy.IPM_Service")]
public interface IPM_Service
{
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IPM_Service/GetUsers", ReplyAction="http://tempuri.org/IPM_Service/GetUsersResponse")]
System.Threading.Tasks.Task<PMProxy.dbUsersModel[]> GetUsersAsync();
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IPM_Service/InsertUser", ReplyAction="http://tempuri.org/IPM_Service/InsertUserResponse")]
System.Threading.Tasks.Task<int> InsertUserAsync(PMProxy.dbUsersModel user, int userid);
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IPM_Service/GetString", ReplyAction="http://tempuri.org/IPM_Service/GetStringResponse")]
System.Threading.Tasks.Task<string> GetStringAsync(string test);
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("dotnet-svcutil", "1.0.0.1")]
public interface IPM_ServiceChannel : PMProxy.IPM_Service, System.ServiceModel.IClientChannel
{
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("dotnet-svcutil", "1.0.0.1")]
public partial class PM_ServiceClient : System.ServiceModel.ClientBase<PMProxy.IPM_Service>, PMProxy.IPM_Service
{
/// <summary>
/// Implement this partial method to configure the service endpoint.
/// </summary>
/// <param name="serviceEndpoint">The endpoint to configure</param>
/// <param name="clientCredentials">The client credentials</param>
static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);
public PM_ServiceClient() :
base(PM_ServiceClient.GetDefaultBinding(), PM_ServiceClient.GetDefaultEndpointAddress())
{
this.Endpoint.Name = EndpointConfiguration.BasicHttpBinding_IPM_Service.ToString();
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
}
public PM_ServiceClient(EndpointConfiguration endpointConfiguration) :
base(PM_ServiceClient.GetBindingForEndpoint(endpointConfiguration), PM_ServiceClient.GetEndpointAddress(endpointConfiguration))
{
this.Endpoint.Name = endpointConfiguration.ToString();
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
}
public PM_ServiceClient(EndpointConfiguration endpointConfiguration, string remoteAddress) :
base(PM_ServiceClient.GetBindingForEndpoint(endpointConfiguration), new System.ServiceModel.EndpointAddress(remoteAddress))
{
this.Endpoint.Name = endpointConfiguration.ToString();
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
}
public PM_ServiceClient(EndpointConfiguration endpointConfiguration, System.ServiceModel.EndpointAddress remoteAddress) :
base(PM_ServiceClient.GetBindingForEndpoint(endpointConfiguration), remoteAddress)
{
this.Endpoint.Name = endpointConfiguration.ToString();
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
}
public PM_ServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}
public System.Threading.Tasks.Task<PMProxy.dbUsersModel[]> GetUsersAsync()
{
return base.Channel.GetUsersAsync();
}
public System.Threading.Tasks.Task<int> InsertUserAsync(PMProxy.dbUsersModel user, int userid)
{
return base.Channel.InsertUserAsync(user, userid);
}
public System.Threading.Tasks.Task<string> GetStringAsync(string test)
{
return base.Channel.GetStringAsync(test);
}
public virtual System.Threading.Tasks.Task OpenAsync()
{
return System.Threading.Tasks.Task.Factory.FromAsync(((System.ServiceModel.ICommunicationObject)(this)).BeginOpen(null, null), new System.Action<System.IAsyncResult>(((System.ServiceModel.ICommunicationObject)(this)).EndOpen));
}
public virtual System.Threading.Tasks.Task CloseAsync()
{
return System.Threading.Tasks.Task.Factory.FromAsync(((System.ServiceModel.ICommunicationObject)(this)).BeginClose(null, null), new System.Action<System.IAsyncResult>(((System.ServiceModel.ICommunicationObject)(this)).EndClose));
}
private static System.ServiceModel.Channels.Binding GetBindingForEndpoint(EndpointConfiguration endpointConfiguration)
{
if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_IPM_Service))
{
System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
result.MaxBufferSize = int.MaxValue;
result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
result.MaxReceivedMessageSize = int.MaxValue;
result.AllowCookies = true;
return result;
}
throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
}
private static System.ServiceModel.EndpointAddress GetEndpointAddress(EndpointConfiguration endpointConfiguration)
{
if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_IPM_Service))
{
return new System.ServiceModel.EndpointAddress("http://localhost:8733/Design_Time_Addresses/PM_Service/PM_Service/");
}
throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
}
private static System.ServiceModel.Channels.Binding GetDefaultBinding()
{
return PM_ServiceClient.GetBindingForEndpoint(EndpointConfiguration.BasicHttpBinding_IPM_Service);
}
private static System.ServiceModel.EndpointAddress GetDefaultEndpointAddress()
{
return PM_ServiceClient.GetEndpointAddress(EndpointConfiguration.BasicHttpBinding_IPM_Service);
}
public enum EndpointConfiguration
{
BasicHttpBinding_IPM_Service,
}
}
}
The only thing that I can possibly think of, is that my IIS may not be set up correctly, since this is the first time I have had to set up IIS by myself. The server is a VPS running Windows Server 2016. I may very well be wrong about the cause, and it may be something I have missed in the config of the service itself, or the proxy client I created.
Any ideas that might be able to help?

Don't get why it keeps throwing an System.InvalidOperationException

I'm kinda new to MVC entity framework core and I've been struggeling with this exception and I don't know what's causing it.
I always get the same error: System.InvalidOperationException: 'No suitable constructor found for entity type 'Rating'. The following parameters could not be bound to properties of the entity: 'date', 'message', 'suggestion'.'
The error is thrown in the GetAll() method:
public class RatingRepository : IRatingRepository {
private readonly ApplicationDbContext _context;
public RatingRepository(ApplicationDbContext context) {
_context = context;
}
public void Add(Rating rating) {
var any = _context.Ratings.Any(r => r.RatingId == rating.RatingId);
if (!any) {
_context.Add(rating);
}
}
public IEnumerable<Rating> GetAll() {
return _context.Ratings.ToList();
}
public IEnumerable<Rating> GetFirst(int amount) {
return GetAll().Take(amount).ToList();
}
public void Remove(Rating rating) {
var any = _context.Ratings.Any(r => r.RatingId == rating.RatingId);
if (any) {
_context.Remove(rating);
}
}
public void SaveChanges() {
_context.SaveChanges();
}
}
This is the interface the repository implements:
public interface ICodeRepository {
IEnumerable<string> GetAll();
void Remove(string code);
void SaveChanges();
}
This is my Rating class:
public class Rating {
#region Fields
private double _foodRating;
private double _atmosphereRating;
#endregion
#region Properties
public int RatingId { get; set; }
public double FoodRating {
get {
return _foodRating;
}
private set {
if (value < 0.0 || value > 5.0) {
throw new ArgumentException("Give a score between 0 and 5 please.");
}
_foodRating = value;
}
}
public double AtmosphereRating {
get {
return _atmosphereRating;
}
private set {
if (value < 0.0 || value > 5.0) {
throw new ArgumentException("Give a score between 0 and 5 please.");
}
_atmosphereRating = value;
}
}
public string PersonalMessage { get; set; } //not mandatory
public string Suggestions { get; set; } //not mandatory
#endregion
#region Constructors
public Rating(double foodRating, double atmosphereRating, DateTime date, string message = null, string suggestion = null) {
FoodRating = foodRating;
AtmosphereRating = atmosphereRating;
PersonalMessage = message;
Suggestions = suggestion;
}
#endregion
}
This is how I mapped it to the database:
public class RatingConfiguration : IEntityTypeConfiguration<Rating> {
public void Configure(EntityTypeBuilder<Rating> builder) {
builder.ToTable("Rating");
builder.HasKey(r => r.RatingId);
builder.Property(r => r.PersonalMessage)
.HasMaxLength(250)
.IsRequired(false);
builder.Property(r => r.Suggestions)
.HasMaxLength(250)
.IsRequired(false);
}
}
In my ApplicationDb have I forseen a DbSet and in the OnModelCreating have I given the RatingConfiguration with.
I need to bind this to a form result so here is my RatingViewModel:
public class RatingViewModel {
#region Properties
[Required]
[DataType(DataType.Text)]
[Display(Name = "How would you rate the food?")]
public double FoodRating { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "How would you rate the atmosphere?")]
public double AtmosphereRating { get; set; }
[Display(Name = "Personal message")]
[DataType(DataType.Text)]
[StringLength(250, ErrorMessage = "Suggestion is needs to be between 250 and 0 characters")]
public string PersonalMessage { get; set; }
[Display(Name = "Any suggestions for next time?")]
[DataType(DataType.Text)]
[StringLength(250,ErrorMessage = "Suggestion is needs to be between 250 and 0 characters")]
public string Suggestions { get; set; }
#endregion
#region Constructor
public RatingViewModel() {
}
public RatingViewModel(Rating rating) : this() {
FoodRating = rating.FoodRating;
AtmosphereRating = rating.AtmosphereRating;
PersonalMessage = rating.PersonalMessage;
Suggestions = rating.Suggestions;
}
#endregion
}
Now if any of you can find why this exception is thrown please let me know. If you need anything else from my code, also let me know!
Entity framework will load data and tries to create the mapped objects. However if you specify a constructor, EF will try to use it, but it does not know how to handle your parameters. To fix this, simply add an empty constructor.

MongoDB Composite Key: InvalidOperationException: {document}.Identity is not supported

I am having issues with hydrating a class which consists of a composite ID which in turn has a base class, I am getting an error saying InvalidOperationException: {document}.Identity is not supported.
The class i am trying to write to the database is below:
public class Product : IEntity<Product>
{
public readonly Sku Sku;
public string Name { get; private set; }
public string Description { get; private set; }
public bool IsArchived { get; private set; }
public Identity<Product> Identity => Sku;
public Product(Sku sku, string name, bool isArchived)
{
Sku = sku;
Name = name;
IsArchived = isArchived;
}
}
public interface IEntity<T>
{
Identity<T> Identity { get; }
}
In turn has an ID Sku which is a class formed of the below composite values (VendorId and a local Value within Sku):
public class Sku : Identity<Product>
{
public readonly VendorId VendorId;
public readonly string Value;
public Sku(VendorId vendorId, string value)
{
VendorId = vendorId;
Value = value;
}
protected override IEnumerable<object> GetIdentityComponents()
{
return new object[] {VendorId, Value};
}
}
public class VendorId : Identity<Vendor>
{
public readonly string Value;
public VendorId(string value)
{
Value = value;
}
protected override IEnumerable<object> GetIdentityComponents()
{
return new object[] {Value};
}
}
I have a base class for my entities Identity which i use in my DDD libraries, essentially the ToString() output here could be used as the ID if this would simplify things:
public abstract class Identity<T> : IEquatable<Identity<T>>
{
public override bool Equals(object obj) { /* snip */ }
public bool Equals(Identity<T> other) { /* snip */ }
public override int GetHashCode() { /* snip */ }
public override string ToString()
{
var id = string.Empty;
foreach (var component in GetIdentityComponents())
{
if (string.IsNullOrEmpty(id))
id = component.ToString(); // first item, dont add a divider
else
id += "." + component;
}
return id;
}
protected abstract IEnumerable<object> GetIdentityComponents();
}
I register the mappings on app start:
// rehydrate readonly properties via matched constructor
// https://stackoverflow.com/questions/39604820/serialize-get-only-properties-on-mongodb
ConventionRegistry
.Register(nameof(ImmutablePocoConvention), new ConventionPack { new ImmutablePocoConvention() }, _ => true);
BsonClassMap.RegisterClassMap<Product>(cm =>
{
cm.AutoMap();
cm.MapIdMember(c => c.Sku);
});
BsonClassMap.RegisterClassMap<Vendor>(cm =>
{
cm.AutoMap();
cm.MapIdMember(c => c.Id);
});
However when i go and write, i get InvalidOperationException: {document}.Identity is not supported.
// my respositoru method
public void Upsert<T>(T entity) where T : IEntity<T>
{
this.Database
.GetCollection<T>(product.GetType().FullName)()
.ReplaceOneAsync(x=>x.Identity.Equals(entity.Identity), entity, new UpdateOptions() {IsUpsert = true})
.Wait();
}
var product = new Product(new Sku(new VendorId("dell"), "12434" ),"RAM", false );
myProductRepo.Upsert(product);
Not sure if this is now overly complicated by me persisting direct from my entities layer (or if i just use an automapper and simpler POCO)... or if I am missing some mapping directives.
Appreciate any help or pointers.
I was looking at the hydration via constructor post which is done through GetProperties.
So public readonly Sku Sku; doesn't show up through classMap.ClassType.GetTypeInfo().GetProperties(_bindingFlags) because it is only can be accessed as member field.
You can change it to public Sku Sku { get; } so it is hydrated through constructor via GetProperties and change all the readonly fields (Sku - VendorId, Value & VendorId - Value fields) to have property getter method.
Also, You've to add cm.MapProperty(c => c.Identity) so x=>x.Identity.Equals(entity.Identity) can be serialized when used as expression because Identity cannot be hydrated and registered through ImmutablePocoConventionas it is not a constructor arg when automap logic runs.
Code changes:
public class Sku : Identity<Product>
{
public VendorId VendorId { get; }
public string Value { get; }
}
public class VendorId : Identity<Vendor>
{
public string Value { get; }
}
BsonClassMap.RegisterClassMap<Product>(cm =>
{
cm.AutoMap();
cm.MapIdMember(c => c.Sku);
cm.MapProperty(c => c.Identity);
});
Here is the code i used:
public class ProductMongoRepository : IProductRepository
{
public ICollection<Product> SearchBySkuValue(string sku)
{
return ProductsMongoDatabase.Instance.GetEntityList<Product>();
}
public Product GetBySku(Sku sku)
{
var collection = ProductsMongoDatabase.Instance.GetCollection<Product>();
return collection.Find(x => x.Sku.Equals(sku)).First();
}
public void SaveAll(IEnumerable<Product> products)
{
foreach (var product in products)
{
Save(product);
}
}
public void Save(Product product)
{
var collection = ProductsMongoDatabase.Instance.GetCollection<Product>();
collection
.ReplaceOneAsync(
x => x.Sku.Equals(product.Sku),
product,
new UpdateOptions() { IsUpsert = true })
.Wait();
}
}
Setting up the mapping here and support for readonly fields via constructor, for more complex scenarios and manual POCO mapping we could use BsonSerializer.RegisterSerializer(typeof(DomainEntityClass), new CustomerSerializer());
public sealed class ProductsMongoDatabase : MongoDatabase
{
private static volatile ProductsMongoDatabase instance;
private static readonly object SyncRoot = new Object();
private ProductsMongoDatabase()
{
BsonClassMap.RegisterClassMap<Sku>(cm =>
{
cm.MapField(c => c.VendorId);
cm.MapField(c => c.SkuValue);
cm.MapCreator(c => new Sku(new VendorId(c.VendorId.VendorShortname), c.SkuValue));
});
BsonClassMap.RegisterClassMap<VendorId>(cm =>
{
cm.MapField(c => c.VendorShortname);
cm.MapCreator(c => new VendorId(c.VendorShortname));
});
BsonClassMap.RegisterClassMap<Product>(cm =>
{
cm.AutoMap();
cm.MapIdMember(c => c.Sku);
cm.MapCreator(c => new Product(c.Sku, c.Name, c.IsArchived));
});
BsonClassMap.RegisterClassMap<Vendor>(cm =>
{
cm.AutoMap();
cm.MapIdMember(c => c.Id);
cm.MapCreator(c => new Vendor(c.Id, c.Name));
});
}
public static ProductsMongoDatabase Instance
{
get
{
if (instance != null)
return instance;
lock (SyncRoot)
{
if (instance == null)
instance = new ProductsMongoDatabase();
}
return instance;
}
}
}
The above implementation (which is a singleton) derives from the below base (any queries or writes are done in the parent implementation):
public abstract class MongoDatabase
{
private readonly IConfigurationRepository _configuration;
private readonly IMongoClient Client;
private readonly IMongoDatabase Database;
protected MongoDatabase()
{
//_configuration = configuration;
var connection = "mongodb://host:27017";
var database = "test";
this.Client = new MongoClient();
this.Database = this.Client.GetDatabase(database);
}
public List<T> GetEntityList<T>()
{
return GetCollection<T>()
.Find(new BsonDocument()).ToList<T>();
}
public IMongoCollection<T> GetCollection<T>()
{
return this.Database.GetCollection<T>(typeof(T).FullName);
}
}
My Sku domain model:
public class Sku : Identity<Product>
{
public readonly VendorId VendorId;
public readonly string SkuValue;
public Sku(VendorId vendorId, string skuValue)
{
VendorId = vendorId;
SkuValue = skuValue;
}
protected override IEnumerable<object> GetIdentityComponents()
{
return new object[] {VendorId, SkuValue};
}
}
My Product domain model:
public class Product : IEntity<Product>
{
public readonly Sku Sku;
public string Name { get; private set; }
public bool IsArchived { get; private set; }
public Product(Sku sku, string name, bool isArchived)
{
Sku = sku;
Name = name;
IsArchived = isArchived;
}
public void UpdateName(string name)
{
Name = name;
}
public void UpdateDescription(string description)
{
Description = description;
}
public void Archive()
{
IsArchived = true;
}
public void Restore()
{
IsArchived = false;
}
// this is used by my framework, not MongoDB
public Identity<Product> Identity => Sku;
}
My VendorID:
public class VendorId : Identity<Vendor>
{
public readonly string VendorShortname;
public VendorId(string vendorShortname)
{
VendorShortname = vendorShortname;
}
protected override IEnumerable<object> GetIdentityComponents()
{
return new object[] {VendorShortname};
}
}
Then i have my entity and identity types:
public interface IEntity<T>
{
Identity<T> Identity { get; }
}
public abstract class Identity<T> : IEquatable<Identity<T>>
{
private const string IdentityComponentDivider = ".";
public override bool Equals(object obj)
{
if (ReferenceEquals(this, obj)) return true;
if (ReferenceEquals(null, obj)) return false;
if (GetType() != obj.GetType()) return false;
var other = obj as Identity<T>;
return other != null && GetIdentityComponents().SequenceEqual(other.GetIdentityComponents());
}
public override string ToString()
{
var id = string.Empty;
foreach (var component in GetIdentityComponents())
{
if (string.IsNullOrEmpty(id))
id = component.ToString(); // first item, dont add a divider
else
id += IdentityComponentDivider + component;
}
return id;
}
protected abstract IEnumerable<object> GetIdentityComponents();
public override int GetHashCode()
{
return HashCodeHelper.CombineHashCodes(GetIdentityComponents());
}
public bool Equals(Identity<T> other)
{
return Equals(other as object);
}
}

Automapper not copy list object to another

I have list of my class type which I need to copy to another class type. In following code I am trying to copy GenderEntity to Gender but getting no results
private void MapGender()
{
List<GenderEntity> _GenderEntity = _GenderServiceObject.GenderEntity();
List<Gender> _Gender = new List<Gender>();
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<List<GenderEntity>, List<Gender>>();
});
IMapper mapper = config.CreateMapper();
_Gender = mapper.Map<List<GenderEntity>, List<Gender>>(_GenderEntity);
var x = "d";
}
GenderEntity - Source
public class GenderEntity
{
public GenderEntity() { }
public string Code { get; set; }
public string Description { get; set; }
}
Gender - Destination
[DataContract]
public class Gender
{
[DataMember]
public string Code { get; set; }
[DataMember]
public string Description { get; set; }
}
Gender entity is used for WCF SOAP services as data contract
Return List Class
public class GenderService
{
#region EBS Service return 'Gender'
public Gender GenderEBSEntity()
{
return GenderEBS.GetGender_EBS();
}
#endregion
#region Mapped Gender Entity
public List<GenderEntity> GenderEntity()
{
return GenderEBS.GetGenderEntity();
}
#endregion
}
You don't need to map Lists with AutoMapper, just create a map like:
cfg.CreateMap<GenderEntity, Gender>();
and then map it like this:
_Gender = mapper.Map<Gender[]>(_GenderEntity).ToList();
my answer...
private void MapGender()
{
List<Gender> MappedGender = new List<Contracts.Data.Gender>();
IList<GenderEntity> genderEntity = _GenderServiceObject.GenderEntity();
if(genderEntity!=null)
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<GenderEntity, Gender>();
});
IMapper mapper = config.CreateMapper();
gender = mapper.Map<IList<GenderEntity>, IList<Gender>>(genderEntity).ToList();
}
}

AutoMapper Ignore() Issue

Okay, I'm hoping I am just somehow overlooking the obvious. I have the following code situation below. For some reason, the SequenceNo property is still getting mapped even though I'm calling Ignore(). I'm using the latest. I also had tested it with two different classes in the same project and it seemed to work, so what's wrong with this scenario then?
This is the domain object:
public class CableID
{
private string _panelID1;
public string PanelID1
{
get { return _panelID1; }
private set { _panelID1 = value; }
}
private string _panelID2;
public string PanelID2
{
get { return _panelID2; }
private set { _panelID2 = value; }
}
private int _sequenceNo;
public int SequenceNo
{
get { return _sequenceNo; }
private set { _sequenceNo = value; }
}
private DateTime _inService;
public DateTime InService
{
get { return _inService; }
set { _inService = value; }
}
private string _id;
public string ID
{
get { return _id; }
private set { _id = value; }
}
public CableID(string panelID1, string panelID2, int sequenceNo)
{
this.PanelID1 = panelID1;
this.PanelID2 = panelID2;
this.SequenceNo = sequenceNo;
this.ID = string.Format("({0}-{1}){2}", this.PanelID1, this.PanelID2, this.SequenceNo);
}
public CableID(string id)
{
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException("id");
this.ID = id;
}
}
And here is the DTO Object:
public class CableIDDTO
{
private string _panelID1;
public string PanelID1
{
get { return _panelID1; }
set { _panelID1 = value; }
}
private string _panelID2;
public string PanelID2
{
get { return _panelID2; }
set { _panelID2 = value; }
}
private int _sequenceNo;
public int SequenceNo
{
get { return _sequenceNo; }
set { _sequenceNo = value; }
}
private string _id;
public string ID
{
get { return _id; }
set { _id = value; }
}
public CableIDDTO()
{ }
public CableIDDTO(string panelID1, string panelID2, int sequenceNo)
{
this.PanelID2 = panelID1;
this.PanelID1 = panelID2;
this.SequenceNo = sequenceNo;
this.ID = string.Format("({0}-{1}){2}", this.PanelID2, this.PanelID1, this.SequenceNo);
}
}
And finally the AutoMapper use-case:
CableID cableID = new CableID("A1", "B1", 2);
Mapper.CreateMap<CableID, CableIDDTO>()
.ForMember(dest => dest.SequenceNo, opt => opt.Ignore());
CableIDDTO dto = Mapper.Map<CableID, CableIDDTO>(cableID);
dto.SequenceNo = 2 when since I had set the Ignore() it should be 0.
This is because AutoMapper is finding this CableIDDTO constructor:
public CableIDDTO(string panelID1, string panelID2, int sequenceNo)
and calling it, setting sequenceNo. I'm not exactly sure how or why it's doing that--i'll continue to dig.
You can fix this by calling .ConstructUsing and telling AutoMapper to use the no-args constructor:
Mapper.CreateMap<CableID, CableIDDTO>()
.ConstructUsing((Func<CableID, CableIDDTO>)(src => new CableIDDTO()))
.ForMember(dest => dest.SequenceNo, opt => opt.Ignore());
Upon further research, this looks like a feature in AutoMapper that tries to match up source property names with destination constructors. Since your destination type (CableIDDTO) had a constructor that perfectly matched up with several property names on the source (panelID1, panelID2, sequenceNo), that constructor was called.
Another way to disable this feature is to call DisableConstructorMapping:
Mapper.Configuration.DisableConstructorMapping()

Categories

Resources