How to hydrate an object with values taken from struct in C# - c#

Is there in C# any hydrating technique allowing to transfer values from one struct/object to another struct/object if they have similar fields or based on certain strategy. I came from Zend Framework 2 world, and it provides the feature "Hydrator" which allows do exactly what I said above. So, I am wondering whether Asp.Net or C# provides something similar.
To make it clear, I want something like this:
struct UserInfo {
public string FirstName { get; set; };
public string LastName { get; set; };
public int Age { get; set; };
}
class UserUpdateModel {
public string FirstName { get; set; };
public string LastName { get; set; };
public int Age { get; set; };
}
...
//supposed UserUpdateModel model I is gotten from the action param
UserInfo info = new UserInfo();
Hydrator hydrator = new Hydrator(Hydrator.Properties);
hydrator.hydrate(info, model);
Now, "info" should be populated with values from "model"
Any help is appreciated.

Yes. AutoMapper. It is designed specifically for this. I personally prefer writing ViewModel constructor that takes an entity and copies the properties. I like the control and familiarity of good old C# code even if it takes a bit more effort.

Automapper should do the trick. You can use it as a nuget package.
Once you have your types and a reference to AutoMapper, you can create a map for the two types.
Mapper.CreateMap<UserUpdateModel, UserInfo>();
The type on the left is the source type, and the type on the right is the destination type. To perform a mapping, use the Map method.
UserInfo info = Mapper.Map<UserInfo>(userUpdateModel);

Related

C# GRPC Reference existing object

Im completely new in using GRPC. I have and question regarding setting up the .proto file.
In my existing solution i have forexample this class:
public class Car
{
public int Id { get; set; }
public string Brand { get; set; }
public string? Type {get; set;}
}
The Car class is placed in a Core project, since it's used by other logic around the solution. But if i like to return in my GRPC Server, is it really necessary to define it in the .proto file again ala this:
message CarReply {
int32 Id = 1;
string Brand = 2;
string Type = 3;
}
What i liked was an reference to my Car() class. Is this not possible?
If you want to use vanilla "contract first" protobuf, then yes: you need to use a schema and the generated type - it is the generated type that knows how to perform the serialization.
However! There may be an alternative; protobuf-net (and protobuf-net.Grpc) provide an independent implementation of protobuf that supports "code first" usage, which allows you to use your existing type model.
The easiest way to do this with protobuf-net is to annotate your model (using either protobuf-net's attributes, or the framework data-contract attributes - the first option giving more control); for example:
[ProtoContract]
public class Car
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Brand { get; set; }
[ProtoMember(3)]
public string? Type {get; set;}
}
It is also possible to configure everything at runtime, but that's a bit harder.
This can also be used fully with gRPC, using interfaces to define the service contract; full guidance is here

Is there a pattern to conversion between classes

I have a class, from a native library, I want to convert to my own type, and I need to do that in several places. I created, then, a static method, so I don't need to repeat the instantiation of the class in so many places, but somehow it doesn't seem right.
If there is a need to create a conversion from 8 different types, I would have 8 different methods of conversion all inside the Record.
Is this the best way to do it, or is there any known pattern that covers this subject?
class Record
{
public String Id { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
public String FingerPrints { get; set; }
//
// This is a simplification of the method and in fact, I created several of
// them, and the class doesn't look clean anymore.
//
public static Record CreateFromMaciRecord(MaciRecord maci)
{
return new Record
{
Id = maci.GetRecordId(),
FirstName = Encoding.UTF8.GetString(maci.GetUserDataField("first_name")),
LastName = Encoding.UTF8.GetString(maci.GetUserDataField("name"))
};
}
}
If you don't want a constructor or a static factory method, you could introduce extension methods. EG
static class Conversions
{
public static Record ToRecord(this MaciRecord maci) => new Record
{
Id = maci.GetRecordId(),
FirstName = Encoding.UTF8.GetString(maci.GetUserDataField("first_name")),
LastName = Encoding.UTF8.GetString(maci.GetUserDataField("name"))
};
}
Which you would call like
var maciRecord = ...;
var record = maciRecord.ToRecord();
You can always provide an implicit conversion in the Record and simply do:
Record record = someMaciRecord;
Add this to the Record.
public static implicit operator Record(MaciRecord maci)
{
return new Record
{
Id = maci.GetRecordId(),
FirstName = Encoding.UTF8.GetString(maci.GetUserDataField("first_name")),
LastName = Encoding.UTF8.GetString(maci.GetUserDataField("name"))
};
}
If your Record is converting an interface of MaciRecord so as to work with rest of the application then I would recommend Class or Object Adapter GOF design pattern. If Record is adding new functionality to MaciRecord, then its an opportunity for Decorator GOF design pattern. Necessarily we are asking for Wrapper over MaciRecord. Point to be noted here is that both these design patterns are also known as Wrapper.

FileHelpers error: The field: 'k__BackingField' has the type: XXX that is not a system type, so this field need a CustomConverter

I need to read a CSV file with FileHelpers based on type, automatically generated by my MVC model. The model looks like this:
public partial class Merchant
{
public long Id { get; set; }
public string Name { get; set; }
public Nullable<int> Category { get; set; }
public virtual MerchantCategory MerchantCategory { get; set; }
}
The last field is obviously generated by a foreign key in database, referring to table MerchantCategories.
Then I attempt to create an instance of FileHelperEngine with this type:
var engine = new FileHelperEngine<Merchant>();
And get the following exception:
The field: 'k__BackingField' has the type: MerchantCategory that is not a system type, so this field need a CustomConverter ( Please Check the docs for more Info).
Actually I don't need this field at all for my import, so I tried to ignore it in derived class:
[DelimitedRecord(",")]
public class MerchantForImport : Merchant {
[FieldHidden]
new public MerchantCategory MerchantCategory;
}
var engine = new FileHelperEngine<MerchantForImport>();
And still the same error. I don't need this field at all, I don't want to implement any FieldConverter for it, I never asked for this k__BackingField and it's nowhere to be found in my code!
I can't call FileHelperEngine.Options.RemoveField() because the exception is thrown by the constructor.
Where does that come from? How do I get rid of it?
From a design perspective, I think you are going about it the wrong way. You are trying to use the Merchant class for two incompatible uses. Instead you should have two separate classes.
FileHelpers is a library for describing csv files so that you can import them easily. You should have a MerchantFileSpec for describing your file. It's really not a proper C# class - it may have: dummy fields to represent unused columns; lots of attributes [FieldNullValue], [FieldQuoted], [FieldConverter]; etc. It works best with public fields (a FileHelpers limitation which is not C# best practice), etc. It is a convenience syntax for describing the import file. It should not include any business logic or special constructors, or backing fields. Keep it as simple as possible.
Then you can have your MVC-generated Merchant class which is separate. Its purpose is to describe the merchant as required by the MVC framework, with foreign keys, ids, whatever.
Then you use a FileHelperEngine<MerchantFileSpec> to read the records into an array and map it to an enumerable of Merchant (via Linq or a library like AutoMapper).
Something like:
/// Your MVC-generated class. Add methods, getters, setters, whatever.
/// FileHelpers doesn't use this class.
class Merchant
{
public long Id { get; set; }
public string Name { get; set; }
public Nullable<int> Category { get; set; }
public virtual MerchantCategory MerchantCategory { get; set; }
}
/// This is the class FileHelpers will use
/// This class describes the CSV file only. Stick to whatever
/// syntax conventions are required by FileHelpers.
[DelimitedRecord(";")]
class ProductMerchantFileSpec
{
[FieldQuoted(QuoteMode.OptionalForRead)]
public long Id;
[FieldQuoted(QuoteMode.OptionalForRead)]
public string Name;
[FieldQuoted(QuoteMode.OptionalForRead)]
// Handle non-US formats such as , decimal points
// convert from inches to centimetres?
// you get the idea...
[FieldConverter(MyCustomizedCategoryConverter)] // you get the idea
public int Category;
}
class Program
{
static void Main(string[] args)
{
var engine = new FileHelperEngine<ProductMerchantFileSpec>();
var productMerchantRecords = engine.ReadFile(filePath);
var productMerchants = productMerchantRecords
.Select(x => new Merchant() { Id = x.Id, Name = x.Name, Category = x.Category });
}
}
I received this error specifically because my object (i.e. Merchant) was missing a column that existed in the source file. I was able to work around the issue prior to realizing the missing column by adding a new property to my object class public string[] MyProperty { get; set; }. This work-around help me realize a column was missing.
i.e..
public partial class Merchant
{
public long id { get; set; }
..
..
..
public string[] MyProperty { get; set; }
}

LINQ navigation property multiple sources

I have a database which stores different locations. Based on the type of the location, the unique details are stored in a different table than the common properties (i.e. Name, Coordinates, Description are stored in the Locations table, while Population is stored in the CityDetails table).
The tables are connected via FK in the "specific details" table.
Since there are more than one "specific details" table I'm scratching my head how to query those multiple tables.
My Location object looks like this:
[Table("Locations")]
public class LocationData
{
public Guid Id { get; set; }
// multiple different properties here.
public string Type { get; set; }
public DetailsData { get; set; }
}
based on the Type property I can see which details table I have to query. A details table looks at least like this:
public abstract class DetailsData
{
[Key, ForeignKey("Location")]
public Guid { get; set; }
public LocationData Location { get; set; }
}
Every table that represents a location type then inherits from the DetailsData class and is configured to use the "Table-per-concrete-class" inheritance hierarchy.
Here is an example of what a "specific details" table might look like:
[Table("CityDetails")]
public class CityDetailsData : DetailsData
{
public string Planet { get; set; }
public int Population { get; set; }
}
How can I populate the DetailsData property in the Location class. Here is my current LINQ query:
from l in Locations
select new
{
Id = l.Id,
Name = l.Name,
Description = l.Description,
Coordinates = l.Coordinates,
Type = l.Type,
DetailsData = CityDetails // Here lies the problem. How can I populate this property properly?
}
Okay, I'm working on the assumption that your details tables all have different sets of columns, that you want to be able to use IEnumerable<LocationData> instances, and that you want to be able to directly access the properties of the instances of whatever details table object you return.
That's a toughie. There are basically three ways you can write code for an object of unknown type:
Give it a type of Object.
Make all "details" tables inherit from a common interface, and make CityDetails an object that implements that interface.
Use a generic type, which means you do ultimately specify the type, but you can push that decision up the chain to a declarer of your implemented type.
Using System.Object means that you either need to cast all your DetailsData objects to the required type (or use Reflection to access their properties), whereas using an interface means you can access some properties directly, but probably not everything you want.
I think a generic type might be your best, hybrid, solution.
I would do something like this:
Accept that there isn't a perfect solution.
Instead of creating an anonymous type, as you are doing in your example code, define a class like this (akin to a ViewModel, if you're using ASP.NET MVC):
public class LocationViewModel<TDetailsData>
{
public Guid Id { get; set; }
// multiple different properties here.
public string Type { get; set; }
public TDetailsData DetailsData { get; set; }
}
Define a helper method that takes a type parameter and returns a value of type TDetailsData. Use that to populate your DetailsData property on LocationViewModel.
TDetailsData GetLocationDetails<TDetailsData>(string type, Guid ID)
{
// get the appropriate data based on the type.
}
If you need to keep an IEnumerable of these objects, define an interface ILocationDataViewModel and another of ILocationDataViewModel<TDetailsData>, make LocationViewModel implement both of them, and use IEnumerable<ILocationDataViewModel> or IEnumerable<ILocationDataViewModel<CityDetailsData>>, etc., as called for by the situation.
If I understood correctly, you would like to dynamically determine the type and deal with it on the fly. In that case, you can go with dynamic. I have not tested this code, but you can think in that line
public DetailsData GetDetailsData(Type t)
{
dynamic typVal = new ExpandoObject();
if(t == typeof(CityDetails))
{
typVal = new CityDetails();
}
// add other types
return (DetailsData)PopulateDetailsData(typVal);
}
public DetailsData PopulateDetailsData(CityDetails cd)
{
cd.Planet = new CityDetails().Planet;
return cd;
}
// Add other type related methods with same
// signature with input parameter differentiated by types
// for example
public DetailsData PopulateDetailsData(TownDetails td)
{
td.Income = new TownDetails().Income;
return td;
}
in query, you can have something like below
from l in Locations
select new
{
Id = l.Id,
Name = l.Name,
Description = l.Description,
Coordinates = l.Coordinates,
Type = l.Type,
DetailsData = GetDetailsData(l.Type)
}

Serializing Name/Value Pairs in a Custom Object via Web Service

This is a very complicated question concerning how to serialize data via a web service call, when the data is not-strongly typed. I'll try to lay it out as best possible.
Sample Storage Object:
[Serializable]
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
public List<NameValuePairs> OtherInfo { get; set; }
}
[Serializable]
public class NameValuePairs {
public string Name { get; set; }
public string Value { get; set; }
}
Sample Use:
[WebMethod]
public List<StorageObject> GetStorageObjects() {
List<StorageObject> o = new List<StorageObject>() {
new StorageObject() {
Name = "Matthew",
Birthday = "Jan 1st, 2008",
OtherInfo = new List<NameValuePairs>() {
new NameValuePairs() { Name = "Hobbies", Value = "Programming" },
new NameValuePairs() { Name = "Website", Value = "Stackoverflow.com" }
}
},
new StorageObject() {
Name = "Joe",
Birthday = "Jan 10th, 2008",
OtherInfo = new List<NameValuePairs>() {
new NameValuePairs() { Name = "Hobbies", Value = "Programming" },
new NameValuePairs() { Name = "Website", Value = "Stackoverflow.com" }
}
}
};
return o;
}
Return Value from Web Service:
<StorageObject>
<Name>Matthew</Name>
<Birthday>Jan 1st, 2008</Birthday>
<OtherInfo>
<NameValuePairs>
<Name>Hobbies</Name>
<Value>Programming</Value>
</NameValuePairs>
<NameValuePairs>
<Name>Website</Name>
<Value>Stackoverflow.com</Value>
</NameValuePairs>
</OtherInfo>
</StorageObject>
What I want:
<OtherInfo>
<Hobbies>Programming</Hobbies>
<Website>Stackoverflow.com</Website>
</OtherInfo>
The Reason & Other Stuff:
First, I'm sorry for the length of the post, but I wanted to give reproducible code as well.
I want it in this format, because I'm consuming the web services from PHP. I want to easily go:
// THIS IS IMPORANT
In PHP => "$Result["StorageObject"]["OtherInfo"]["Hobbies"]".
If it's in the other format, then there would be no way for me to accomplish that, at all. Additionally, in C# if I am consuming the service, I would also like to be able to do the following:
// THIS IS IMPORANT
In C# => var m = ServiceResult[0].OtherInfo["Hobbies"];
Unfortunately, I'm not sure how to accomplish this. I was able to get it this way, by building a custom Dictionary that implemented IXmlSerializer (see StackOverflow: IXmlSerializer Dictionary), however, it blew the WSDL schema out of the water. It's also much too complicated, and produced horrible results in my WinFormsTester application!
Is there any way to accomplish this ? What type of objects do I need to create ? Is there any way to do this /other than by making a strongly typed collection/ ? Obviously, if I make it strongly typed like this:
public class OtherInfo {
public string Hobbies { get; set; }
public string FavoriteWebsite { get; set; }
}
Then it would work perfectly, I would have no WSDL issues, I would be able to easily access it from PHP, and C# (.OtherInfo.Hobbies).
However, I would completely lose the point of NVP's, in that I would have to know in advance what the list is, and it would be unchangeable.. say, from a Database.
Thanks everyone!! I hope we're able to come up with some sort of solution to this. Here's are the requirements again:
WSDL schema should not break
Name value pairs (NVP's) should be serialized into attribute format
Should be easy to access NVP's in PHP by name ["Hobbies"]
Should be easy to access in C# (and be compatible with it's Proxy generator)
Be easily serializable
Not require me to strongly type the data
Now, I am /completely/ open to input on a better/different way to do this. I'm storing some relatively "static" information (like Name), and a bunch of pieces of data. If there's a better way, I'd love to hear it.
This is like dynamic properties for a object.
C# is not quite a dynamic language unlike javascript or maybe PHP can parse the object properties on the fly. The following two methods are what I can think of. The second one might fit into your requirements.
The KISS Way
The Keep It Simple Stupid way
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
public List<string> OtherInfo { get; set; }
}
You can have name value pairs which is separated by '|'
OtherInfo = {"Hobbies|Programming", "Website|Stackoverflow.com"}
Serialized forms
<StorageObject>
<Name>Matthew</Name>
<Birthday>Jan 1st, 2008</Birthday>
<OtherInfo>
<string>Hobbies|Programming</string>
<string>Website|Stackoverflow.com</string>
</OtherInfo>
</StorageObject>
The Dynamic Way in C#
Make the name value pair part become an XML element so that you can build it dynamically.
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
public XElement OtherInfo { get; set; } // XmlElement for dot net 2
}
You can easily build up OtherInfo object as element centric
e.g.
XElement OtherInfo = new XElement("OtherInfo");
OtherInfo.Add( ..Hobbies xelement & text value..);
OtherInfo.Add( ..WebSite xelement & text value..);
The serialized form will be
<OtherInfo>
<Hobbies>Programming</Hobbies>
<Website>Stackoverflow.com</Website>
</OtherInfo>
or build it as attribute centric
XElement OtherInfo = new XElement("OtherInfo");
OtherInfo.Add( ..nvp xattribute Hobbies & value..);
OtherInfo.Add( ..nvp xattribute WebSite & value..);
<OtherInfo>
<nvp n="Hobbies" v="Programming" />
<nvp n="Website" v="Stackoverflow.com" />
</OtherInfo>
For any dynamic language, it can access to the properties directly.
For the rest, they can access the value by read the XML. Reading XML is well supported by most of framework.
This is what I've settled on.
Class Structure:
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
[XmlAnyElement("Info")] // this prevents double-nodes in the XML
public XElement OtherInfo { get; set; }
}
Usage:
StorageObject o = new StorageObject();
o.OtherInfo.Add(new XElement("Hobbies","Programming");
o.OtherInfo.Add(new XElement("Website","Stackoverflow.com");
Output:
<Info>
<Hobbies>Programming</Hobbies>
<Website>Stackoverflow.com</Website>
</Info>
I would like to thank everyone for their assistance, I really appreciate the help and ideas.
As a completely different take on this, why not think about doing it completely differently. Have one web service method to return the serialized storage object, minus the OtherInfo and another method to return the list of properties (keys) for OtherInfo, and a third to return the list of values for any key. Granted, it will take more round trips to the web service if you want all of the data, but the solution will be much simpler and more flexible.
[Serializable]
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
[Nonserializable]
public Dictionary<string,List<string>> OtherInfo { get; set; }
}
[WebMethod]
public List<StorageObject> GetStorageObjects() {
// returns list of storage objects from persistent storage or cache
}
[WebMethod]
public List<string> GetStorageObjectAttributes( string name )
{
// find storage object, sObj
return sObj.Keys.ToList();
}
[WebMethod]
public List<string> GetStorageObjectAtributeValues( sting name, string attribute )
{
// find storage object, sObj
return sObj[attribute];
}
Have a look into the System.Xml.Serialization.XmlSerializerAssemblyAttribute attribute. This lets you specify a custom class-level serializer. You'll be able to spit out whatever XML you like.
A quick way to get up to speed on these is to use sgen.exe to generate one and have a peek at it with Reflector.
-Oisin
I'm not sure this would solve your problem (it would in C#, but maybe not in PHP), but try using Dictionary<string,List<string>> OtherInfo instead of List<NameValuePairs>. Then "Hobbies" and "Websites" would be your keys and the values would be the list of hobbies or web sites. I'm not sure how it would serialize, though.
You would be able to reference the lists of hobbies as:
List<string> hobbies = storageObject.OtherInfo["Hobbies"];
[EDIT] See here for a generic XML serializable dictionary. This derived class is the one you would need to use instead of generic Dictionary.

Categories