This question already has answers here:
copy chosen properties to object of other type
(2 answers)
How to cast between 2 types of the same name and internal sturcture but from different assemblies?
(5 answers)
Copy two identical object with different namespaces (recursive reflection)
(7 answers)
Closed 2 years ago.
I'm trying to find the best way to populate my constructor with another constructor that have almost the same structure without setting each attribute,
So i have constructor Altridatiidentificativi in ModelRA constructor:
public class Altridatiidentificativi
{
public string denominazione { get; set; }
public string indirizzo { get; set; }
public string numeroCivico { get; set; }
public string cap { get; set; }
public string comune { get; set; }
public string provincia { get; set; }
public string nazione { get; set; }
public bool modificati { get; set; }
public string defAliquotaIVA { get; set; }
public bool nuovoUtente { get; set; }
}
And Altridatiidentificativi in Documenti:
public class Altridatiidentificativi
{
public bool nuovoUtente { get; set; }
public string denominazione { get; set; }
public string indirizzo { get; set; }
public string numeroCivico { get; set; }
public string cap { get; set; }
public string comune { get; set; }
public string provincia { get; set; }
public string nazione { get; set; }
}
As you can see the structure is almost the same, just constructor in ModelRA has this two extras modificati and defAliquotaIVA
So i was wondering if it's possible in some way to pass inside ModelRA.Altridatiidentificativi the Documenti.Altridatiidentificativi and then add the value to the extras
I was trying to do something like this :
public ModelRA initializeRA(Documento documento)
{
ModelRA model = new ModelRA();
model.altriDatiIdentificativi = <Altridatiidentificativi>(documento.altriDatiIdentificativi);
model.altriDatiIdentificativi.defAliquotaIVA = "";
model.altriDatiIdentificativi.modificati = false;
return model;
}
but i get error in <Altridatiidentificativi> "it's a type not a valid constructor in specific context"
Is there a way to reach what i'm trying to do or i have to set all the attributes manually?
Usually this pattern is a signal that there's a concept in your business model that needs to be abstracted into a composable pattern. The ModelRA.Altridatiidentificativi class could look like:
public class Altridatiidentificativi
{
public ModelRA.Altridatiidentificativi ModelRAAltridatiidentificativi { get; set; }
public bool modificati { get; set; }
public string defAliquotaIVA { get; set; }
}
Then your initialization code could look like this:
public ModelRA initializeRA(Documento documento)
{
ModelRA model = new ModelRA();
model.altriDatiIdentificativi.ModelRAAltridatiidentificativi = documento;
model.altriDatiIdentificativi.defAliquotaIVA = "";
model.altriDatiIdentificativi.modificati = false;
return model;
}
Tangentially I should mention that it's usually good practice to use property initializers and constructors unless you have a specific reason that you need initialization methods.
public class Altridatiidentificativi
{
public string ModelRA.Altridatiidentificativi ModelRAAltridatiidentificativi { get; set; }
public bool modificati { get; set; } = false; // unnecessary: this is default.
public string defAliquotaIVA { get; set; } = "";
public Altridatiidentificativi(ModelRA.Altridatiidentificativi modelRAAltridatiidentificativi)
{
this.modelRAAltridatiidentificativi = ModelRAAltridatiidentificativi;
}
}
Related
I have a class like this
public class ListOfBMTTeamMapping
{
public class TeamMapping
{
public List<TeamMappings> results { get; set; }
}
public class TeamMappings
{
public int id { get; set; }
public string areaPath { get; set; }
public string agileReleaseTrainName { get; set; }
public string deliveryTeamName { get; set; }
public string keyedInTeamCode { get; set; }
public string deliveryTeamId { get; set; }
public bool isDeleted { get; set; }
public string modified { get; set; }
public string modifiedBy { get; set; }
}
}
And here is my model class to which I need the above API class to get copied
public class JsonBmtAdoMapping
{
public int? Id { get; set; }
public string AreaPath { get; set; }
public string AgileReleaseTrainName { get; set; }
public string DeliveryTeamName { get; set; }
public string KeyedInTeamCode { get; set; }
public string DeliveryTeamId { get; set; }
public string IsDeleted { get; set; }
public DateTime? Modified { get; set; }
public string ModifiedBy { get; set; }
}
So here is my code I tried
var format = "dd/MM/yyyy";
var dateTimeConverter = new IsoDateTimeConverter { DateTimeFormat = format };
ListOfBMTTeamMapping.TeamMapping Results = new ListOfBMTTeamMapping.TeamMapping();
Results = JsonConvert.DeserializeObject<ListOfBMTTeamMapping.TeamMapping>(responseBody);
List<JsonBmtAdoMapping> jM = new List<JsonBmtAdoMapping>();
jM = _mapper.Map<ListOfBMTTeamMapping.TeamMapping,List<JsonBmtAdoMapping>>(Results);
int n = 10;
And here is my automapper profile
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>();
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
But when the code executes, Ofcourse I am getting the data in results variable without any trouble
But when the mapper code fires, it execute the line without any error, but no data being copied from source to my model class which is the destination
jM.count is always 0 when Results hold 124 rows of data
What I did wrong
Your mapping from TeamMapping to List<JsonBmtAdoMapping> can't be done out of the box by AutoMapper, because your source is an object with a property that contains the list and the destination is a list on itself.
So you have to tell him, how this conversion from a single object to a list can be done. Due to the fact, that you already have a mapping for each individual item, we can use that recursively within our mapping method.
By using this mapping, it should work:
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>()
.ConvertUsing((src, _, context) => src.results.Select(context.Mapper.Map<JsonBmtAdoMapping>).ToList());
Update
Cause a mapper is already defined for the individual items and lists are handled automatically by AutoMapper we can even make it shorter (thanks for Lucian for the hint in the comments):
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>()
.ConvertUsing((src, _, context) => context.Mapper.Map<List<JsonBmtAdoMapping>>(src.results));
I am simply trying to generate a unique cachekey that takes in the object type and property values
GetHashCode returns different results each time so that wont work, so I have to implement a solution but it has to be fast (I can go through the properties and and concat their values to a string but this might be slow and not the best way to go about it)
Nice To Have:
so if 2 different object types have the exact same properties and same values but they are different classes, they should be different cachekeys (chances of this happening are very slim but just in case)
Here is my code
public interface ICachableRequest
{
string GetCacheKey();
}
public class Object1 : ICachableRequest
{
public int IntValue1 { get; set; }
public double DoubleVal1 { get; set; }
public string StringVal1 { get; set; }
public string GetCacheKey()
{
throw new NotImplementedException();
}
}
public class Object2 : ICachableRequest
{
public int SomeIntValue1 { get; set; }
public double SomeOtherDoubleVal1 { get; set; }
public string MoreStringVal1 { get; set; }
public string MoreStringVal2 { get; set; }
public string MoreStringVal3 { get; set; }
public string MoreStringVal4 { get; set; }
public string GetCacheKey()
{
throw new NotImplementedException();
}
}
First of all, please stick to how I accomplish this with the current setup, and not in trying to redesign how it is structured. I have to build an app/web service to receive a JSON query. The JSON is generated by a widget that we can not customize. I used Visual Studio to create the class structure from a JSON example.
I want to test my service, and I'm getting errors in SOAPUI, so I need something where I can debug, so I'm hard-coding the JSON input object for my Service Reference.
Here are the classes, as they reside on the web service -
[DataContract]
public class QuoterIn
{
[DataMember]
public Quoterinput quoterinput { get; set; }
}
public class Quoterinput
{
public string agent_id { get; set; }
public string key { get; set; }
public string auto_assign { get; set; }
public Consumer consumer { get; set; }
public string viaEmail { get; set; }
}
public class Consumer
{
public string brand_id { get; set; }
public string full_name { get; set; }
public Addresses_Attributes[] addresses_attributes { get; set; }
public string birth_or_trust_date { get; set; }
public string gender { get; set; }
public Emails_Attributes[] emails_attributes { get; set; }
public Phones_Attributes[] phones_attributes { get; set; }
public Cases_Attributes[] cases_attributes { get; set; }
}
public class Addresses_Attributes
{
public string zip { get; set; }
}
public class Emails_Attributes
{
public string value { get; set; }
}
public class Phones_Attributes
{
public string value { get; set; }
}
public class Cases_Attributes
{
public Quoting_Details_Attributes[] quoting_details_attributes { get; set; }
}
public class Quoting_Details_Attributes
{
public string carrier_id { get; set; }
public string duration_id { get; set; }
public string policy_type_id { get; set; }
public string plan_name { get; set; }
public string product_type_name { get; set; }
public string face_amount { get; set; }
public string carrier_health_class { get; set; }
public string planned_modal_premium { get; set; }
public string premium_mode_id { get; set; }
public string health_class_id { get; set; }
}
Looking at the sub-class of Consumer, there are several sub-classes that are arrays - address_attributes, phone_attributes, and email_attributes.
I'm able to initialize the main JSON input/inquiry container, and then I can initialize the main class and the sub-class of "Consumer." I can enter data for the main fields, and then fields in the sub-class of Consumer, but I can't initialize the arrays.
Here's the code up until this point for populating that input container -
protected void btnRun_Click(object sender, EventArgs e)
{
QuoterIn req = new QuoterIn();
req.quoterinput = new Quoterinput();
req.quoterinput.consumer = new Consumer();
req.quoterinput.agent_id = "1938";
req.quoterinput.key = "afasdfasdfasdfasdfasd";
req.quoterinput.auto_assign="true";
req.quoterinput.consumer.brand_id = "21264";
req.quoterinput.consumer.full_name = "Fred Smith";
req.quoterinput.consumer.addresses_attributes[0].zip = "53704";
.................(more code like this, but this last line is where the program fails)
Since we aren't going to take in multiple email addresses or phone numbers, I'd be fine with not having it be an array, but I'm worried that the incoming JSON with all the grouping and bracketing will fail if it's not set up like an array. I've tried to initialize instance zero like this -
req.quoterinput.consumer.addresses_attributes[0] = new Addresses_Attributes();
.... and Visual Studio likes the code syntax-wise, but it doesn't initialize an instance when it runs, and then I get the "Object reference not set to an instance of an object." error when it runs. It hasn't allowed me to initialize the array using more generic methods since it has to map to this specific property we've already declared.
I have no doubt it's probably straightforward, but I'm not all that experienced in manipulating arrays and lists like this, and I haven't been able to find examples of arrays of sub-classes within subclasses of properties.
Just instantiate / assign the address at the same time. Something like this should work:
req.quoterinput.consumer.addresses_attributes = new []
{
new Addresses_Attributes
{
zip = "53704"
}
};
Another way (since the property toy are trying to set is an Array), is to create a dynamic sized list, add to it, then convert it back during declaration.
var addresses = new List<Addresses_Attributes>
{
new Addresses_Attributes {zip = "53704"}
};
req.quoterinput.consumer.addresses_attributes = addresses.ToArray();
Or, you can assign it an array of size 1, and then set it up from there:
req.quoterinput.consumer.addresses_attributes = new Addresses_Attributes[1];
req.quoterinput.consumer.addresses_attributes[0] = new Addresses_Attributes { zip = "666" };
I am currently setting some strings via this method:
string marketlabel = allmarketdata.#return.markets.COLXPM.label.ToString();
I would like to set the market label dynamically by having a string for the actual market choice.
string currentMarketSelected= this.marketTextBox.Text; // Specific market: COLXPM
string marketlabel=allmarketdata.#return.markets.currentMarketSelected.label.ToString();
I have been searching for a few hours and probably am not explaining correctly. I tried some stuff with reflections with no success. Basically what I want to do is have a textbox or list which contains all the market names and based on which one is selected start setting the data.
Above is the best type of example of what I want to do even though it is not syntactically possible to use a variable in place.
public class Markets
{
public COLXPM COLXPM { get; set; }
//Lots of markets below here
}
public class COLXPM
{
public string marketid { get; set; }
public string label { get; set; }
public string lasttradeprice { get; set; }
public string volume { get; set; }
public string lasttradetime { get; set; }
public string primaryname { get; set; }
public string primarycode { get; set; }
public string secondaryname { get; set; }
public string secondarycode { get; set; }
public List<Recenttrade> recenttrades { get; set; }
public List<Sellorder> sellorders { get; set; }
public List<Buyorder> buyorders { get; set; }
}
public class Return
{
public Markets markets { get; set; }
}
public class RootObject
{
public int success { get; set; }
public Return #return { get; set; }
}
The proposed solution below that worked
string currentMarketSelected = "DOGEBTC"; // Just selecting one of the markets to test it works
var property = allmarketdata.#return.markets.GetType().GetProperty(currentMarketSelected);
dynamic market = property.GetMethod.Invoke(allmarketdata.#return.markets, null);
string marketlabel = market.label.ToString(); //Gets all my selected market data
Here is a solution using reflection.
string currentMarketSelected= this.marketTextBox.Text; // Specific market: COLXPM
var property = allmarketdata.#return.markets.GetType().GetProperty(currentMarketSelected);
dynamic market = property.GetGetMethod().Invoke(allmarketdata.#return.markets, null);
string marketlabel=market.label.ToString();
You need something like this:
public class Markets
{
public COLXPM this[string key]
{
get
{
COLXPM colxpm;
switch (key)
{
// TODO : use "key" to select instance of COLXPM;
case "example1":
colxpm = ...;
break;
default:
throw new NotSupportedException();
}
return colxpm;
}
}
}
Then you can do something like:
string marketlabel=allmarketdata.#return.markets[currentMarketSelected]label.ToString();
This is an indexed property.
I have these classes:
public abstract class CustomField
{
public String Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public FieldType Type { get; set; }
public enum FieldType
{
String = 0,
Integer = 1,
Boolean = 2,
List = 3
}
}
public class StringCustomField:CustomField
{
public String Value { get; set; }
public Int32 MinLenght { get; set; }
public Int32 MaxLenght { get; set; }
public StringCustomField()
{
this.Type = FieldType.String;
}
}
public class CustomGroup
{
public String Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public List<CustomField> FieldList = new List<CustomField>();
}
When I try to transfer CustomGroup through my webservice I get this error:
The remote server returned an error: NotFound
Serialization is failing when C# tries to transfer my StringField through my CustomField.
What am I doing wrong?
Marc Gravel tell me to do that and i understand the solution but some thing is wrong, no effects, cath the same error!! , help!!
[XmlInclude(typeof(StringCustomField))]
[XmlInclude(typeof(IntegerCustomField))]
[XmlInclude(typeof(BooleanCustomField))]
[XmlInclude(typeof(ListCustomField))]
public abstract class CustomField
{
public String Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public FieldType Type { get; set; }
public enum FieldType
{
String = 0,
Integer = 1,
Boolean = 2,
List = 3
}
}
If you are sending subclasses as xml, you will need [XmlInclude]:
[XmlInclude(typeof(StringCustomField))]
public abstract class CustomField
{...}
You can add multiple [XmlInclude(...)] markers for any other subclasses in the model.
List<CustomField> will serialize and deserialize to a CustomField[] if you're using a web service, won't it?
use
public class CustomGroup
{
public String Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public List<CustomField> FieldList = new List< StringCustomField >();
}
instead
If i understand you correctly, you should
1. connect your web service to your app
2. use the namespace of the WS, so all the classes will be used from the Proxy
i don't think that the local class will be understood by the remote web serivce correctly, even if you're using the same assembly on both parties