I know this has been answered a lot of places on stack and the best possible answer is Here. I've tried it and a lot of other answers too. I have a library that returns me a collection of an Interface (IMasterAutoSuggestOutlet)
public interface IMasterAutoSuggestOutlet : IBaseAutoSuggestOutlet
{
IAddressData AddressData { get; }
IPlaceActivity PlaceActivity { get; }
string ELoc { get; }
Geopoint ExactLocation { get; }
Geopoint EntranceLocation { get; }
LocationType TypeOfLocation { get; }
}
Now, I want to transfer this interface data from one page to another in my application. Since Interfaces cannot be serialized, I created a concrete class that implements this interface:
My Concrete Class,
public class MasterAutoSuggestModel : IMasterAutoSuggestOutlet
{
public IAddressData AddressData { get; set; }
public IPlaceActivity PlaceActivity { get; set; }
public string ELoc { get; set; }
public Geopoint ExactLocation { get; set; }
public Geopoint EntranceLocation { get; set; }
public LocationType TypeOfLocation { get; set; }
}
What I want to do is, convert the ICollection to ICollection. My code below shows my implementation of such an operation:
var collection = mainPageViewModel?.SearchPageVM?.searchManager?.AutoSuggestResponse;
var ob = collection.First();
if (ob is IMasterAutoSuggestOutlet)
{
var ToBeTransfered = collection.OfType<MasterAutoSuggestModel>(); //Simply returns the collection with a count 0
var serializedData = JsonConvert.SerializeObject(ToBeTransfered);
ScenarioFrame.Navigate(typeof(MasterSearchResultPage), serializedData);
}
The issue is with var ToBeTransfered = col.OfType<MasterAutoSuggestModel>(); it returns me a collection with count 0 even though the collection has 10 items in it.
Can someone please tell me where am I going wrong? Please note I need to use this Converted collection to serialize and send as the navigation parameter to send to the next page
The ofType method filters the connection by the type specified. If you are retrieving the objects from some other library, they would not be that specific type.
https://msdn.microsoft.com/en-us/library/bb360913(v=vs.110).aspx
What you would probably want to do is convert the items retrieved from the library into your dto for serialisation. You can use something like automapper for the conversion
if (ob is IMasterAutoSuggestOutlet) {
var transferObject = new MasterAutoSuggestModel(){
//Set Properties
}
// var ToBeTransfered = collection.OfType<MasterAutoSuggestModel>(); //Simply returns the collection with a count 0
var serializedData = JsonConvert.SerializeObject(transferObject);
ScenarioFrame.Navigate(typeof(MasterSearchResultPage), serializedData); }
Related
I have the following use case, I want to serialize/deserialize my IPagedList of T using JSON.net (Newtonsoft.Json). This seems not to be working. It does not serialize everything, only the items (or with my own ContractResolver, the object with empty properties). I am using the X.PagedList nuget.
A test case:
var list = new List<int>(Enumerable.Range(1, 1000));
var paged = list.AsQueryable().ToPagedList(3, 10);
var json = JsonConvert.SerializeObject(paged); (output: [21,22,23,24,25,26,27,28,29,30])
var obj = JsonConvert.DeserializeObject<PagedList<int>>(json);
When I extend the DefaultContractResolver and override the CreateContract method, it deserializes to the IPagedList object but with no properties filled, and also no items.. I tried to override the CreateProperties but that didn't work as I expected.
protected override JsonContract CreateContract(Type objectType)
{
if (typeof(IPagedList).IsAssignableFrom(objectType))
{
return CreateObjectContract(objectType);
}
return base.CreateContract(objectType);
}
So how can I successfully serialize/deserialize this class?
When you serialize IPagedList it serializes the contents/data of the requested page and not the meta data (i.e. FirstItemOnPage, HasNextPage, etc. properties) will be lost.
So to overcome this issue you can create an anonymous class like the following which will have two properties
items holds current page contents
metaData holds super list metadata.
So change first part of your code to:
var list = new List<int>(Enumerable.Range(1, 1000));
var paged = list.AsQueryable().ToPagedList(3, 10);
var pagedWithMetaData = new { items = paged, metaData = paged.GetMetaData() };
then serialize that object
//Serialize
var json = JsonConvert.SerializeObject(pagedWithMetaData);
this will generate a sub-list with the metaData for your example it is like following:
{"items":[21,22,23,24,25,26,27,28,29,30],"metaData":{"PageCount":100,"TotalItemCount":1000,"PageNumber":3,"PageSize":10,"HasPreviousPage":true,"HasNextPage":true,"IsFirstPage":false,"IsLastPage":false,"FirstItemOnPage":21,"LastItemOnPage":30}}
now to deserialize you need to create three classes:
PaginationMetaData class to encapsulate the meta-data so when we deserialize the sub list it's metadata will be deserialzed to this type.
PaginationEntityClass where T : class class to encapsulate the anonymous class so when we deserialize the sub list its content and metadata will be deserialzed to this type.
PaginationEntityStruct where T : struct same as PaginationEntityClass but T here is a struct so it hold struct types instead of classes like your case for int.
So these three classes will as follow:
public class PaginationMetaData
{
public int FirstItemOnPage { get; set; }
public bool HasNextPage { get; set; }
public bool HasPreviousPage { get; set; }
public bool IsFirstPage { get; set; }
public bool IsLastPage { get; set; }
public int LastItemOnPage { get; set; }
public int PageCount { get; set; }
public int PageNumber { get; set; }
public int PageSize { get; set; }
public int TotalItemCount { get; set; }
}
public class PaginationEntityClass<T> where T : class
{
public PaginationEntityClass()
{
Items = new List<T>();
}
public IEnumerable<T> Items { get; set; }
public PaginationMetaData MetaData { get; set; }
}
public class PaginationEntityStruct<T> where T : struct
{
public PaginationEntityStruct()
{
Items = new List<T>();
}
public IEnumerable<T> Items { get; set; }
public PaginationMetaData MetaData { get; set; }
}
Now to deserialize you need just to deserialize to PaginationEntityStruct of integers then use the second constructor overload of StaticPagedList class (class comes with PagedList package) to recreate the subclass with metadata.
//Deserialize
var result = JsonConvert.DeserializeObject<PaginationEntityStruct<int>>(json);
StaticPagedList<int> lst = new StaticPagedList<int>(
result.Items,
result.MetaData.PageNumber,
result.MetaData.PageSize,
result.MetaData.TotalItemCount);
Perhaps you could consider using the built in LINQ functions .skip() & .take().
As per my comment above it seems the repo for PagedList hasn't been maintained in a long while. Before knocking your head against the wall perhaps try the above built in functions.
PagedList github repo.
Samples for Skip & Take
I have this situation:
List<Details> trace;
private class Details
{
public string date { get; set; }
public string type { get; set; }
public string mex { get; set; }
}
private class Context
{
public List<object> context { get; set; }
}
how can I insert in the trace list the class Details and Context? My goal is create a multidimensional list that have as key the class properties such as: date, type, mex, context and as value a dynamic content.
You can use for that purpose an abstraction contract between both classes...
for example if both classes implement a new interface, lets say MyCustomInterface that you define, then declare the list as List<MyCustomInterface> trace; and then you can add objects of both classes...
Example:
List<MyCustomInterface> trace;
private class Details: MyCustomInterface
{
public string date { get; set; }
public string type { get; set; }
public string mex { get; set; }
}
private class Context:MyCustomInterface
{
public List<object> context { get; set; }
}
then you can always do
trace.Add(new Context(...));
trace.Add(new Details(...));
You can use Tuple<Details, Context> to hold instance of either as item in the list, but then when iterating items you will then have to use Item1 and such names to access underlying values:
List<Tuple<Details, Context>> trace;
// add
trace.Add(new Tuple(new Details(), new Context()));
// iterate
foreach(var item in trace)
if(item.Item1?.date == ... && item.Item2?.context != null) { ... }
A better idea might be to construct own type to hold both: Details and Context instance (as properties with same names):
class ContextDetails
{
public Context { get; set; }
public Details { get; set; }
// todo: add constructor to simplify constructing items when adding
}
and use it
List<ContextDetails> trace;
// add
trace.Add(new ContextDetails()
{
Details = new Details(),
Context = new Context(),
});
// iterate
foreach(var item in trace)
if(item.Details?.date == ... && item.Context?.context != null) { ... }
Hmm if you really wanted to have both in a List, i'd give you two options:
First:
Create a parent-Class which both inherit.
Next step is to put the name of the parent class into your List.
Both will fit if they were extended by the same parent class
Second:
Create an Objekt that contains a Context and Details object and put that into the list.
I have a weird situation where I have objects and Lists of objects as part of my entities and contracts to interface with a third-party service. I'm going to try to see if I can replace the actual object class with something more specific in the entities and contracts to get around this, but I am curious if there is a way to get AutoMapper to handle this as is.
Here are some dummy classes:
public class From
{
public object Item { get; set; }
}
public class FromObject
{
public string Value { get; set; }
}
public class To
{
public object Item { get; set; }
}
public class ToObject
{
public string Value { get; set; }
}
And the quick replication:
Mapper.CreateMap<From, To>();
Mapper.CreateMap<FromObject, ToObject>();
From from = new From { Item = new FromObject { Value = "Test" } };
To to = Mapper.Map<To>(from);
string type = to.Item.GetType().Name; // FromObject
Basically, the question is this: Is there a way to get AutoMapper to understand that from.Item is a FromObject and apply the mapping to ToObject? I'm thinking there's probably not a way to make it automatic, since there's nothing that would indicate that to.Item has to be a ToObject, but is there a way to specify during the CreateMap or Map calls that this should be taken into account?
I don't think there is an "automatic" way of doing it, since AutoMapper won't be able to figure out that From.Item is FromObject and To.Item is ToObject.
But, while creating mapping, you can specify that
Mapper.CreateMap<FromObject, ToObject>();
Mapper.CreateMap<From, To>()
.ForMember(dest => dest.Item, opt => opt.MapFrom(src => Mapper.Map<ToObject>(src.Item)));
From from = new From { Item = new FromObject { Value = "Test" } };
To to = Mapper.Map<To>(from);
string type = to.Item.GetType().Name; // ToObject
If you're willing to use an additional interface, this can be accomplished using Include. You can't just map object to object in this fashion, though.
public class From
{
public IItem Item { get; set; }
}
public class FromObject : IItem
{
public string Value { get; set; }
}
public class To
{
public object Item { get; set; }
}
public class ToObject
{
public string Value { get; set; }
}
public interface IItem
{
// Nothing; just for grouping.
}
Mapper.CreateMap<From, To>();
Mapper.CreateMap<IItem, object>()
.Include<FromObject, ToObject>();
From from = new From { Item = new FromObject { Value = "Test" } };
To to = Mapper.Map<To>(from);
string type = to.Item.GetType().Name; // ToObject
I have an object containing different properties like the object below:
public class CompressedLogResponse
{
public string LoggerType { get; set; }
public int NumberOfRegisters { get; set; }
public int NewLogId { get; set; }
public DateTime LoggerAnnounceTime { get; set; }
public List<Log> Log{ get; set; }
}
How can I return a List of this objekt that does not include the List<Log> Log property?
Linq would be preffered
Thanks for any help that you can provide
You cannot just hide a property of a class (you declared it a as public)
Option 1:
Althought as Robson wrote you can set it null (thats not very reliable thaught cause nobody expects a class containing a property that is always null)
Option2:
If you consume the class on the same place use a anonymous type as Mez wrote, althought it sounds like you want to hide the Property from external usage. (I don't like the dynamic approach, the dynamic keyword was made for interop/DOM not for transporting anonymous types.)
Option3:
If you want a List of this type to be returned without the Log property, you have to create a new class (Inheritance is a good way to realize this):
public class CompressedLogResponseBase
{
public string LoggerType { get; set; }
public int NumberOfRegisters { get; set; }
public int NewLogId { get; set; }
public DateTime LoggerAnnounceTime { get; set; }
}
public class CompressedLogResponse : CompressedLogResponseBase
{
public List<Log> Log{ get; set; }
}
Now you can return a list of base items (that do not have a Log property at all)
public List<CompressedLogResponseBase> ReturnWithoutLog(IEnumerable<CompressedLogResponse> items)
{
return ((IEnumerable<CompressedLogResponseBase>)items).ToList();
}
If a IEnumerable as return type is suficient it becomes really easy
public IEnumerable<CompressedLogResponseBase> ReturnWithoutLog(IEnumerable<CompressedLogResponse> items)
{
return items
}
whith "does not include the List Log property" i guess you mean that the property "public List Log" will be blanked but still there, so you can just null that property out, because if you create an object that doesn't contain the "public List Log" property, than it will not be a "CompressedLogResponse" but will be another type.
List<CompressedLogResponse> listOne = new List<CompressedLogResponse>();
//....
//fill the listOne
//....
List<CompressedLogResponse> listWithoutListLog = (from item in listOne
select new CompressedLogResponse(
LoggerType = item.LoggerType,
NumberOfRegisters = item.NumberOfRegisters ,
NewLogId = item.NewLogId ,
LoggerAnnounceTime = item.LoggerAnnounceTime ,
Log= null)).ToList();
You can return an anonymous list of your original list like the following;
public static List<dynamic> Test() {
List<CompressedLogResponse> list = new List<CompressedLogResponse>();
var result = list.Select(x => new
{
x.LoggerAnnounceTime,
x.LoggerType,
x.NewLogId,
x.NumberOfRegisters
});
return result.ToList<dynamic>();
}
Take a look at the .Select(), and also the dynamic keyword.
Then to call it,
var x = Test();
foreach(dynamic o in x)
{
int NumberOfRegisters;
//You have 2 ways... either by
NumberOfRegisters = o.NumberOfRegisters;
// or reflection
NumberOfRegisters = o.GetType().GetProperty("NumberOfRegisters").GetValue(o, null);
}
I have two classes which contain the same fields, however one inherits some properties from somewhere else and the other does not.
I have created a generic list using the class "ZEUS_ResearchStocksHistory" , but then I need to clone all of the fields over to the other list "ZEUS_ResearchStocksHistoryWithExcel". I don't want to have to loop through each field in one list and populate the other, or write some sort of linq join, there must be a faster way?
The reason I can't use the same class in both instances is that when inheriting the ExcelReport function it adds additional fields which I do not want when I display this list in a data grid.
internal class ZEUS_ResearchStocksHistory
{
public String Amendment { get; set; }
public String AmendedBy { get; set; }
public String Sedol { get; set; }
public String Date { get; set; }
}
internal class ZEUS_ResearchStocksHistoryWithExcel : ExcelReport
{
public String Amendment { get; set; }
public String AmendedBy { get; set; }
public String Sedol { get; set; }
public String Date { get; set; }
}
Is this possible?
Thanks
Did you have a look at automapper?
example from codeproject:
CustomerViewItem customerViewItem =
Mapper.Map<Customer, CustomerViewItem>(customer);
Check out Automapper, which is designed to do exactly this. Automapper is up on NuGet.
http://lostechies.com/jimmybogard/2009/01/23/automapper-the-object-object-mapper/
You could do something as simple as:
Mapper.CreateMap<ZEUS_ResearchStocksHistory, ZEUS_ResearchStocksHistoryWithExcel>();
var newObject = Mapper.Map<ZEUS_ResearchStocksHistory, ZEUS_ResearchStocksHistoryWithExcel>(oldObject);
Or, since you said you have a list, you could do:
var newList = oldList.Select(x => Mapper.Map<ZEUS_ResearchStocksHistory, ZEUS_ResearchStocksHistoryWithExcel>(x));