How to convert Generic.List values into extension method - c#

I am using Linq to Entity , Linq query returning a ToList() and storing multiple rows in DataSourcesModel class. Later i am using foreach to iterate items and store values in DataSourcesModelDTO, till here working fine.
Now question is DataSourcesModelDTO dto storing only one row value.
I am expecting it should store multiple row value. How to achieve this in extension method?
** var datasoruceModeltDTO = DataSourcesDTOTransformers.ToDTO(result);**
public static class DataSourcesDTOTransformers
{
public static DataSourcesModelDTO ToDTO(this List<DataSourcesModel> model)
{
if (model == null) { return null; }
var dto = new DataSourcesModelDTO();
ToDTO(model, dto);
return dto;
}
public static void ToDTO(List<DataSourcesModel> model1, DataSourcesModelDTO dto)
{
foreach (var model in model1)
{
dto.DataSourceConfigID = model.DataSourceConfigID.ToString();
dto.DataSourceID = model.DataSourceID.ToString();
dto.Name = model.Name;
dto.server = model.server;
dto.LastModified = model.LastModified;
dto.Instance = model.Instance;
}
}
}
[DataContract]
public class DataSourcesModelDTO
{
[DataMember]
public string DataSourceID { get; set; }
[DataMember]
public string DataSourceConfigID { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string server { get; set; }
[DataMember]
public string Instance { get; set; }
[DataMember]
public bool Deleted { get; set; }
[DataMember]
public DateTime LastModified { get; set; }
[DataMember]
public DateTime LastSync { get; set; }
}

foreach (var model in model1)
{
dto.DataSourceConfigID = model.DataSourceConfigID.ToString();
You are setting the properties of the same dto object every time in the loop. I would rearrange your toDTO methiod to either:
take in a single DataSourcesModel object and return a single DataSourcesModelDTO object (calling the method from within a loop or Linq query), or
take in an IEnumerable<DataSourcesModel> and return an IEnumerable<DataSourcesModelDTO>
How to achieve this in extension method?
Not sure why you need an extension method, but the appropriate signature would be:
public static IEnumerable<DataSourcesModelDTO> ToDTOCollection (this IEnumerable<DataSourcesModel> model)
I'll let you work out what the implementation would be. Hint: You could create a List<DataSourcesModelDTO> within the method and populate it with new objects the same way you are now.

Related

Serializing Response Inside A Class As A List

I'm trying to fetch Symptoms from an API. I can fetch them already and I'm serializing it inside a class succesfully. The result looks like in image that i share at below:
There are just IDs and Names inside them. The second table from API is like that:
So here my Entity Class;
using System.Collections.Generic;
public class SymptomousInBodySublocations
{
public int ID { get; set; }
public string Name { get; set; }
public bool HasRedFlag { get; set; }
public ICollection<BodyLocations> HealthSymptomLocationIDs { get; set; }
public string ProfName { get; set; }
public List<string> Synonyms { get; set; }
}
And my Serialize Method:
public static List<SymptomousInBodySublocations> SymptomsInBodySublocations()
{
var client = new RestClient("https://priaid-symptom-checker-v1.p.rapidapi.com/symptoms/31/man?format=json&language=en-gb");
var request = new RestRequest(Method.GET);
request.AddHeader("x-rapidapi-host", "priaid-symptom-checker-v1.p.rapidapi.com");
request.AddHeader("x-rapidapi-key", "<api-key>");
List<SymptomousInBodySublocations> SymptomsInBodySublocationsList = new List<SymptomousInBodySublocations>();
var response = client.Execute<List<SymptomousInBodySublocations>>(request);
foreach(SymptomousInBodySublocations variables in response.Data)
{
SymptomsInBodySublocationsList.Add(variables);
}
return SymptomsInBodySublocationsList;
}
And my BodyLocations Class:
public class BodyLocations
{
public int ID { get; set; }
public string Name { get; set; }
}
In this point when i tried to fetch my data inside my List<BodyLocations>() the response.Data is empty. What should i do?
HealthSymptomLocationIDs isn't an object, looking at the response it is an array of integers.
Changing the field to match the response should populate the field with the integer values from the API
public List<int> HealthSymptomLocationIDs { get; set; }

Passing a variable class object through to a class

I'm trying to work out if the following is possible, I've done lots of googling and I'm a bit confused. I'm pretty sure I can work out the class reflection on the object class and updating the database isn't a problem once I have the loop, but I can't work out if this is possible at all.
If I was doing this with a fixed class object it'd be easy I'd just do:
public void updateDB(obj_Users myObject)
But as I have a lot of class objects that will take a long time, so trying to make it more dynamic.
Here is a sample of a class I want to pass through (but could be anything following the same format):
public class obj_Users
{
public Int32 UserID { get; set; }
public String UserName { get; set; }
public String FirstName { get; set; }
public String Surname { get; set; }
public String Email { get; set; }
public Int32 UserRole { get; set; }
public Int32 UserCompanyID { get; set; }
public String UserPassword { get; set; }
public Boolean IsAdmin { get; set; }
public String SessionKey { get; set; }
}
Here is some pseudocode of what I'm trying to achieve to explain:
public void updateDB(AnyClassObject obj_Users)
{
// Loop through obj_Users and grab the properties
// DB update call
}
This:
public void updateDB(object paramobj)
{
foreach(var prop in paramobj.GetType().GetProperties())
{
//grab
}
// update
}
Try this to loop to get the properties
foreach(var prop in obj_Users.GetType().GetProperties()) {
//use your props
}
You just need your parameter to be of type object to pass an instance of any class or struct.
public void updateDB(object whatever)
{
foreach(var prop in whatever.GetType().GetProperties())
{
... //do stuff
}
}
If you're stuck with the problem of having to deal with different classes, a generic method should fit your needs:
public void UpdateDB<T>(T obj)
{
var properties = typeof(T).GetProperties();
foreach (var prop in properties)
{
// Here you loop through the properties.
}
}

Complex array in ServiceStack request

I am sending the following request parameters to my service; among which, is the filter parameter which is a multidimensional array:
filter[0][field]:homeCountry
filter[0][data][type]:string
filter[0][data][value]:united s
page:2
start:200
limit:200
sort:homeCountry
dir:ASC
The querystring is encoded like so:
paymentratetrip.json?filter%5B0%5D%5Bfield%5D=homeCountry&filter%5B0%5D%5Bdata%5D%5Btype%5D=string&filter%5B0%5D%5Bdata%5D%5Bvalue%5D=united%20s&page=2&start=200&limit=200&sort=homeCountry&dir=AS
Currently, my C# request object looks like this:
public class PaymentRateTripRequest
{
public int start { get; set; }
public int limit { get; set; }
public string sort { get; set; }
public string dir { get; set; }
}
How can I modify my request object to receive the filter parameter which could be a multidimensional array?
Note: I am using ServiceStack.
The only way I can think is to send the entire request object as a parameter to my method like so:
public object Get(PaymentRateTripRequest req)
{
return _repository.GetAllRates(req.start, req.limit, req.sort, req.dir, this.Request.OriginalRequest);
}
But, this doesn't seem like the best solution.
Edit: this.Request.QueryString
this.Request.QueryString
{filter%5b0%5d%5bfield%5d=homeCountry&filter%5b0%5d%5bdata%5d%5btype%5d=string&filter%5b0%5d%5bdata%5d%5bvalue%5d=united+s&page=2&start=200&limit=200&sort=homeCountry&dir=ASC}
[System.Web.HttpValueCollection]: {filter%5b0%5d%5bfield%5d=homeCountry&filter%5b0%5d%5bdata%5d%5btype%5d=string&filter%5b0%5d%5bdata%5d%5bvalue%5d=united+s&page=2&start=200&limit=200&sort=homeCountry&dir=ASC}
base {System.Collections.Specialized.NameObjectCollectionBase}: {filter%5b0%5d%5bfield%5d=homeCountry&filter%5b0%5d%5bdata%5d%5btype%5d=string&filter%5b0%5d%5bdata%5d%5bvalue%5d=united+s&page=2&start=200&limit=200&sort=homeCountry&dir=ASC}
_all: null
_allKeys: {string[8]}
AllKeys: {string[8]}
Edit: filter is still empty.
This is an alternative solution that requires no changes to your client and therefore will accept the query string in the format you have currently:
paymentratetrip.json?filter%5B0%5D%5Bfield%5D=homeCountry&filter%5B0%5D%5Bdata%5D%5Btype%5D=string&filter%5B0%5D%5Bdata%5D%5Bvalue%5D=united%20s&page=2&start=200&limit=200&sort=homeCountry&dir=AS
The disadvantage of this method is that it's more code to maintain. The JSV method is simpler.
Request attribute to populate the filter from the querystring:
We can use a ServiceStack filter to intercept the query string before it reaches the action method. It can then parse the custom filter format and populate the filter object of the DTO.
public class FilterAttribute : Attribute, IHasRequestFilter
{
IHasRequestFilter IHasRequestFilter.Copy()
{
return this;
}
public int Priority { get { return int.MinValue; } }
FilterField CreateOrUpdateField(ref Dictionary<string, FilterField> filter, string id)
{
if(filter.ContainsKey(id))
return filter[id];
var field = new FilterField { Data = new Dictionary<string, object>() };
filter.Add(id, field);
return field;
}
public void RequestFilter(IRequest req, IResponse res, object requestDto)
{
var filteredDto = requestDto as IFilter;
if(filteredDto == null)
return;
const string fieldPattern = #"filter\[([A-Za-z0-9]+)\]\[field\]";
const string dataPattern = #"filter\[([A-Za-z0-9]+)\]\[data\]\[([A-Za-z0-9]+)\]";
Dictionary<string, FilterField> filter = new Dictionary<string, FilterField>();
foreach(var property in req.QueryString.AllKeys)
{
Match match = Regex.Match(property, fieldPattern, RegexOptions.IgnoreCase);
if(match.Success)
{
// Field
var id = match.Groups[1].Value;
var field = CreateOrUpdateField(ref filter, id);
field.Field = req.QueryString[property];
} else {
match = Regex.Match(property, dataPattern, RegexOptions.IgnoreCase);
if(match.Success)
{
// Data value
var id = match.Groups[1].Value;
var keyName = match.Groups[2].Value;
var field = CreateOrUpdateField(ref filter, id);
if(!field.Data.ContainsKey(keyName))
field.Data.Add(keyName, req.QueryString[property]);
}
}
}
filteredDto.Filter = filter.Values.ToArray();
}
}
You will also need to add this interface and FilterField class:
public class FilterField
{
public string Field { get; set; }
public Dictionary<string,object> Data { get; set; }
}
public interface IFilter
{
FilterField[] filter { get; set; }
}
Then you simply need to update your DTO so it looks like this:
[Route("/paymentratetrip", "GET"]
[Filter]
public class PaymentRateTripRequest : IFilter
{
public int page { get; set; }
public int start { get; set; }
public int limit { get; set; }
public string sort { get; set; }
public string dir { get; set; }
public FilterField[] filter { get; set; }
}
You should add a property with the filter to your DTO, such as below:
public class PaymentRateTripRequest
{
public int page { get; set; }
public int start { get; set; }
public int limit { get; set; }
public string sort { get; set; }
public string dir { get; set; }
public FilterField[] filter { get; set; }
}
public class FilterField
{
public string field { get; set; }
public Dictionary<string,object> data { get; set; }
}
This will allow you to add any number of fields to filter by, and by making the data property of the FilterField a Dictionary<string, object> you can add as many data properties as needed.
Then you can populate the filter parameter in your PaymentRateTripRequest using JSV format. You can learn about JSV format here. JSV Format (i.e. JSON-like Separated Values) is a JSON inspired format that uses CSV-style escaping for the least overhead and optimal performance.
paymentratetrip.json?filter=[{field:homeCountry,data:{type:string,value:"united s"}},{field:other,data:{type:int,value:34,special:true}}]&page=2&start=200&limit=200&sort=homeCountry&dir=ASC
Then you can access the filter as a regular property on your request.
Hope this helps.

How to convert DataSet to Entity in C#?

Here I came up with the first approach: that is, using foreach clause on DataSet to get the items and fill in your Entity. But this method can't be reused when the something changes.
So I think maybe reflection should be the best approach for my scenario. below are the details:
1.My entity is defined below:
using System.ComponentModel;
namespace WarningServiceForYM.Model
{
public class StuffEntity
{
[Description("企业ID")]
public string EnterpriseID { get; set; }
[Description("冰柜编号")]
public string FridgeID { get; set; }
[Description("冰柜名称")]
public string FridgeName { get; set; }
[Description("手机号码")]
public string PhoneNumber { get; set; }
[Description("设备名称")]
public string EquipmentName { get; set; }
[Description("采集参数")]
public string PickingParams { get; set; }
[Description("一路温度")]
public string TempOne { get; set; }
[Description("二路温度")]
public string TempTwo { get; set; }
[Description("三路温度")]
public string TempThree { get; set; }
[Description("四路温度")]
public string TempFour { get; set; }
[Description("五路温度")]
public string TempFive { get; set; }
[Description("六路温度")]
public string TempSix { get; set; }
[Description("七路温度")]
public string TempSeven { get; set; }
[Description("八路温度")]
public string TempEight { get; set; }
[Description("温度最低")]
public string Min { get; set; }
[Description("温度最高")]
public string Max { get; set; }
[Description("采集时间")]
public string PickingTime { get; set; }
[Description("通知间隔")]
public string WarningPeriod { get; set; }
[Description("延时")]
public string PendingTime { get; set; }
[Description("通知开关")]
public string Switch { get; set; }
[Description("最后通知时间")]
public string LastInformTime { get; set; }
}
}
Below is the DataSet screenshot:
I have saved this DataSet's data into csv file, pls click here to find it.
the inner properties in the StuffEntity have the same Description as the column headers in DataSet.
Would any one give me a method to show how to convert this Dataset to StuffEntity ? thx.
Ok, using reflection:
public static T GetEntity<T>(DataRow row) where T : new()
{
var entity = new T();
var properties = typeof(T).GetProperties();
foreach (var property in properties)
{
//Get the description attribute
var descriptionAttribute = (DescriptionAttribute)property.GetCustomAttributes(typeof(DescriptionAttribute), true).SingleOrDefault();
if (descriptionAttribute == null)
continue;
property.SetValue(entity, row[descriptionAttribute.Description]);
}
return entity;
}
You can use it like:
foreach (DataRow dataRow in dataSet.Tables[0].Rows)
{
var e = GetEntity<StuffEntity>(dataRow);
Console.WriteLine(e.EnterpriseID);
}
It's a generic implementation, so you can use it with any other types or datasets you want.
I took care to made it as simple as possible, so it can be widely improved adding some consistences, like checking if the column name exists before setting the entity value or verifying duplicate descriptions as needed. It can also be converted to an extension method for the DataRow, DataTable or DataSet, for example.
I my case Your code almost worked, but
descriptionAttribute is always null so it continues to the point where I get no results back
var descriptionAttribute = (DescriptionAttribute)property.GetCustomAttributes(typeof(DescriptionAttribute), true).SingleOrDefault();
if (descriptionAttribute == null)
continue;
I am not sure what is happening to the variable descriptionAttribute and it is null all the time.
So I changed #natenho code like this and it worked for me.
public static T GetEntity<T>(DataRow row) where T : new()
{
var entity = new T();
var properties = typeof(T).GetProperties();
foreach (var property in properties)
{
//Get the description attribute
//var descriptionAttribute = (DescriptionAttribute)property.GetCustomAttributes(typeof(DescriptionAttribute), true).SingleOrDefault();
//if (descriptionAttribute == null)
// continue;
if (row[property.Name].ToString() != "")
{
property.SetValue(entity, row[property.Name]);
}
}
return entity;
}

Is it possible to map multiple DTO objects to a single ViewModel using Automapper?

I was wondering if it is possible to map multiple DTO objects to a single ViewModel object using Automapper?
Essentially, I have multiple DTO objects and would like to display information from each on a single screen in ASP.NET MVC 2.0. To do so I would like to flatten the DTO objects (or parts of them...) into the Viewmodel and pass said viewmodel to the view. If I had one DTO this would be easy, but I've never seen it being done with multiple. Obviously there are a number of roundabout ways to do this (outside of automapper), but this is the approach that I would like to take if possible.
Check for following link regarding your query
http://consultingblogs.emc.com/owainwragg/archive/2010/12/22/automapper-mapping-from-multiple-objects.aspx
You could create a composite DTO that holds two or more DTO objects and map the composite DTO to the output view model.
If you have 2 DTO classes and 1 flattened view model:
public class Dto1
{
public string Property1 { get; set; }
}
public class Dto2
{
public string Property2 { get; set; }
}
public class FlattenedViewModel
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
And you create mappings for both DTOs to view model:
CreateMap<Dto1, FlattenedViewModel>();
CreateMap<Dto2, FlattenedViewModel>();
You can map 1st DTO to the model and then just "append" 2nd DTO:
var dto1 = new Dto1 { Property1 = "Value1"; }
var dto2 = new Dto2 { Property2 = "Value2"; }
var model = Mapper.Map<FlattenedViewModel>(dto1); // map dto1 properties
Mapper.Map(dto2, model); // append dto2 properties
You can add a Map override extension method off IMappingEngine that takes a params array. Something like:
public static class AutoMapperExtensions
{
public static T Map<T>(this IMappingEngine engine, params object[] sources) where T : class
{
if (sources == null || sources.Length == 0)
return default(T);
var destinationType = typeof (T);
var result = engine.Map(sources[0], sources[0].GetType(), destinationType) as T;
for (int i = 1; i < sources.Length; i++)
{
engine.Map(sources[i], result, sources[i].GetType(), destinationType);
}
return result;
}
}
You could then call it like this:
var result = Mapper.Engine.Map<MyViewModel>(dto1, dto2, dto3);
This is the information from the expired link in this answer: https://stackoverflow.com/a/8923063/2005596
When using AutoMapper (http://automapper.codeplex.com ) I often have a scenario where I need to map several entities into one entity. Commonly this occurs when mapping from a number domain entities into a single view model (ASP.NET MVC). Unfortunately the AutoMapper API does not expose functionality to map several entities into one entity; however it is relatively simple to create some helper method to do this. Below I will illustrate the approach that I have taken.
In this example I have the following entities in my domain model
public class Person
{
public int Id { get; set; }
public string Firstname { get; set; }
public string Surname { get; set; }
}
public class Address
{
public int Id { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string Country { get; set; }
}
public class Comment
{
public string Text { get; set; }
public DateTime Created { get; set; }
}
In addition to this I have a requirement to render the person details the person’s address and any related comment on a single page (using ASP.NET MVC). To implement this I have created the view model shown below, which includes data from all three of the domain entities shown above
public class PersonViewModel
{
public int Id { get; set; }
[DisplayName("Firstname")]
public string Firstname { get; set; }
[DisplayName("Surname")]
public string Surname { get; set; }
[DisplayName("Address Line 1")]
public string AddressLine1 { get; set; }
[DisplayName("Address Line 2")]
public string AddressLine2 { get; set; }
[DisplayName("Country Of Residence")]
public string Country { get; set; }
[DisplayName("Admin Comment")]
public string Comment { get; set; }
}
In the controller action method I make three separate calls into the domain layer to retrieve the required entities but this still leaves the issue that I need to map several source entities onto a single destination entity. To perform this mapping I created a helper class which encapsulates AutoMapper and exposes functionality which enables the mapping of several source objects onto one destination object. This class is shown below
public static class EntityMapper
{
public static T Map<T>(params object[] sources) where T : class
{
if (!sources.Any())
{
return default(T);
}
var initialSource = sources[0];
var mappingResult = Map<T>(initialSource);
// Now map the remaining source objects
if (sources.Count() > 1)
{
Map(mappingResult, sources.Skip(1).ToArray());
}
return mappingResult;
}
private static void Map(object destination, params object[] sources)
{
if (!sources.Any())
{
return;
}
var destinationType = destination.GetType();
foreach (var source in sources)
{
var sourceType = source.GetType();
Mapper.Map(source, destination, sourceType, destinationType);
}
}
private static T Map<T>(object source) where T : class
{
var destinationType = typeof(T);
var sourceType = source.GetType();
var mappingResult = Mapper.Map(source, sourceType, destinationType);
return mappingResult as T;
}
}
To map several source objects onto one destination I have made use of the functionality provided by AutoMapper which allows you to perform a mapping between a source object and a destination object that already exists.
Finally below is the code from the controller that retrieves the three entities and performs the mapping onto a single view model
public ActionResult Index()
{
// Retrieve the person, address and comment entities and
// map them on to a person view model entity
var personId = 23;
var person = _personTasks.GetPerson(personId);
var address = _personTasks.GetAddress(personId);
var comment = _personTasks.GetComment(personId);
var personViewModel = EntityMapper.Map<PersonViewModel>(person, address, comment);
return this.View(personViewModel);
}
I just worked this out myself and have a great solution. It is most likely that your two views are actually related somehow in your system (especially if you are using Entity Framework). Check your models and you should see something which displays the relationship, if you don't then just add it. (The virtual)
Your models
public class Dto1
{
public int id { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public string Property4 { get; set; }
public string Property5 { get; set; }
public virtual Dto2 dto2{ get; set; }
}
public class Dto2
{
public int id { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
public string PropertyD { get; set; }
public string PropertyE { get; set; }
}
Your ViewModels
public class Dto1ViewModel
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public virtual Dto2VMForDto1 dto2{ get; set; }
}
//Special ViewModel just for sliding into the above
public class Dto2VMForDto1
{
public int id { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
}
Automapper looks like this:
cfg.CreateMap< Dto1, Dto1ViewModel>();
cfg.CreateMap< Dto2, Dto2VMForDto1 >();
I'm assuming you are getting your data with LinQ:
Dto1ViewModel thePageVM = (from entry in context.Dto1 where...).ProjectTo<Dto1ViewModel>();
Viola, everything will work. In your view just access by using model.dto2.PropertyB

Categories