I'm trying to use AutoMapper (v5.1.1) to map an object which inherits from a List or Collection. The map call does not give me an error but the output is an empty list (of correct type though).
I can get a List<DestinationObject> or Collection<DestinationObject>, but it does not seem to work when having a custom class which enherits from List<T> or Collection<T>.
I've tried extending the first map definition to include the base class (List<T>) but that gives me a StackOverflowException.
cfg.CreateMap(typeof(SourceCollection), typeof(DestinationCollection)).Include(typeof(List<SourceObject>), typeof(List<DestinationObject>));
What am I missing here?
public class SourceCollection : List<SourceObject> {
}
public class DestinationCollection : List<DestinationObject> {
}
public class SourceObject {
public string Message { get; set; }
}
public class DestinationObject {
public string Message { get; set; }
}
static void Main(string[] args)
{
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap(typeof(SourceCollection), typeof(DestinationCollection));
cfg.CreateMap<List<SourceObject>, List<DestinationObject>>().Include<SourceCollection, DestinationCollection>();
cfg.CreateMap(typeof(SourceObject), typeof(DestinationObject));
});
AutoMapper.Mapper.AssertConfigurationIsValid();
SourceCollection srcCol = new SourceCollection() { new SourceObject() { Message = "1" }, new SourceObject() { Message = "2" } };
DestinationCollection dstCol = AutoMapper.Mapper.Map<SourceCollection, DestinationCollection>(srcCol);
}
You just have to map sourceobject to destinationobject, AutoMapper will do rest of the magic, More on this can be found on this link
cfg.CreateMap(typeof(SourceObject), typeof(DestinationObject));
Related
I have this model with following attributes. (Simplified)
public class Blog {
private string Code { get; set; }
private string Name { get; set; }
private byte[] Image { get; set; }
}
When I make a request to the OData URL for ex: http://localhost/api/odata/Blog, I want only Code and Name properties to be returned, ignoring the Image. And if I make
a request something like http://localhost/api/odata/Blog?$select=(Code,Name,Image) then I want the Image to be returned. How can I make this work?
Using attributes like [IgnoreDataMember] makes it unavailable for OData query to be accessed, therefore it is not a suitable solution.
First, probably properties of the Blog class are public, not private.
I had a similar scenario and resolve it by implementing a custom serializer:
Serializer provider class:
public class MyODataSerializerProvider : DefaultODataSerializerProvider
{
MyResourceSerializer myResourceSerializer;
public MyODataSerializerProvider(IServiceProvider serviceProvider) : base(serviceProvider)
{
myResourceSerializer = new MyResourceSerializer(this);
}
public override ODataEdmTypeSerializer GetEdmTypeSerializer(IEdmTypeReference edmType)
{
if (edmType.IsEntity())
{
return myResourceSerializer;
}
return base.GetEdmTypeSerializer(edmType);
}
}
Serializer class:
public class MyResourceSerializer : ODataResourceSerializer
{
public MyResourceSerializer(ODataSerializerProvider serializerProvider) : base(serializerProvider) { }
public override ODataResource CreateResource(SelectExpandNode selectExpandNode, ResourceContext resourceContext)
{
var resource = base.CreateResource(selectExpandNode, resourceContext);
if (selectExpandNode.SelectAllDynamicProperties)
{
resource.Properties = resource.Properties.Where(p => p.Name != "Image");
}
return resource;
}
}
And configuration of course:
routeBuilder.MapODataServiceRoute("OData", "odata", b =>
{
b.AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => edmModel);
var conventions = ODataRoutingConventions.CreateDefault();
//Workaround for https://github.com/OData/WebApi/issues/1622
conventions.Insert(0, new AttributeRoutingConvention("OData", app.ApplicationServices, new DefaultODataPathHandler()));
//Custom Convention
b.AddService<IEnumerable<IODataRoutingConvention>>(Microsoft.OData.ServiceLifetime.Singleton, a => conventions);
b.AddService(Microsoft.OData.ServiceLifetime.Singleton, typeof(ODataSerializerProvider), sp => new MyODataSerializerProvider(sp));
});
I'm trying to implement generic interface method but keep getting an error. I'm pasting the code to better explain what I want to do.
What I'm trying to achieve is: based on some input data (SomeModelA, SomeModelB) I want to get the same return type (Template).
namespace GenericInterfacePuzzle
{
class Program
{
static void Main(string[] args)
{
var workerA = new WorkerA();
var itemsBasedOnModelA = workerA.Get(new List<SomeModelA>());
var workerB = new WorkerB();
var itemsBasedOnModelB = workerB.Get(new List<SomeModelB>());
}
}
public interface IWorker
{
Template Get<T>(List<T> someModels);
}
public class WorkerA : IWorker
{
public Template Get<SomeModelA>(List<SomeModelA> someModels)
{
ProcessModels(someModels);
return new Template(); // let's say it's based on the result of ProcessModels
}
private void ProcessModels(List<SomeModelA> models)
{
var x = models.First();
}
}
public class WorkerB : IWorker
{
public Template Get<SomeModelB>(List<SomeModelB> someModels)
{
ProcessModels(someModels);
return new Template(); // let's say it's based on the result of ProcessModels
}
private void ProcessModels(List<SomeModelB> models)
{
var x = models.First();
}
}
public class SomeModelA
{
public string Name { get; set; }
}
public class SomeModelB
{
public string Age { get; set; }
}
public class Template
{
// Irrevelant return type
}
}
I want to know at the level of WorkerA/WorkerB class that I'm dealing with a concrete model, and based on that I want to return a Template class instance
The problem is that in the lines that call Process:
ProcessModels(someModels);
I get an error saying:
Error CS1503 Argument 1: cannot convert from 'System.Collections.Generic.List of SomeModelA' to 'System.Collections.Generic.List of GenericInterfacePuzzle.SomeModelA'
Any feedback appreciated what might be going wrong here, and why doesn't it recognize the model classes when passed to the functions.
Chris
1) You need to define the generic parameter on the level of your interface. Otherwise the T parameter is not known to the compiler:
public interface IWorker<T> where T: SomeModel
{
Template Get(List<T> someModels);
}
2) you need to make a constraint since you probably don't want any type to be given to your interface. It would be preferable to make a baseclass for your models and let them inherit from it:
public abstract class SomeModel { ... }
public class SomeModelA : SomeModel
{
public string Name { get; set; }
}
public class SomeModelB : SomeModel
{
public string Age { get; set; }
}
This way it will allow you to specify the model directly in the declaration of the class which will implement the interface (see point 3)
3) Now you need to specify in the child classes which model belongs to which workertype:
public class WorkerA : IWorker<SomeModelA>
{
public Template Get(List<SomeModelA> someModels)
{
ProcessModels(someModels);
return new Template(); // let's say it's based on the result of ProcessModels
}
private void ProcessModels(List<SomeModelA> models)
{
var x = models.First();
}
}
public class WorkerB : IWorker<SomeModelB>
{
public Template Get(List<SomeModelB> someModels)
{
ProcessModels(someModels);
return new Template(); // let's say it's based on the result of ProcessModels
}
private void ProcessModels(List<SomeModelB> models)
{
var x = models.First();
}
}
You also should remove the generic specification in your Get method!
public Template Get<SomeModelA>(List<SomeModelA> someModels)
^
|
remove this
this is already specified when you implement the interface:
public class WorkerA : IWorker<SomeModelA>
4) and the last thing is you test in the main method:
var worker = new WorkerA();
var itemsBasedOnModelA = worker.Get(new List<SomeModelA>());
var workerB = new WorkerB();
var itemsBasedOnModelB = worker.Get(new List<SomeModelB>());
^
|
this should be [workerB]!
I need pagination type for GraphQL in asp.net core.
I am trying code in below for the type:
using GraphQL.Types;
using WebApi.Data.Entities.Models;
using WebApi.Dtos;
using WebApi.Helpers;
using WebApi.Services;
namespace WebApi.Data.Entities.Graphql.GraphQueryTypes
{
public class PagedResultType<T>: ObjectGraphType<T> where T : class
{
public PagedResultType()
{
Name = "PagedResultType";
Field<IntGraphType>("CurrentPage");
Field<IntGraphType>("PageCount");
Field<IntGraphType>("PageSize");
Field<IntGraphType>("RowCount");
Field<IntGraphType>("FirstRowOnPage");
Field<IntGraphType>("LastRowOnPage");
Field<ListGraphType<T>>("Results");
}
}
}
Also I am trying to create Field on RootQuery:
Field<PagedResultType<ComplaintSourceDTO>>(
"complaintSourceTypes",
arguments: new QueryArguments(
new QueryArgument<IntGraphType> { Name = "page", Description = "Sayfalama için sayfa " },
new QueryArgument<IntGraphType> { Name = "pageSize", Description = "Sayfalama için gerekli sayfa sayısı" }
),
resolve: context => complaintSourceService.GetDataWithPaged(context.GetArgument<int>("page"), context.GetArgument<int>("pageSize"))
);
But it says as error:
The type 'T' cannot be used as type parameter 'T' in the generic type
or method 'ListGraphType'. There is no implicit reference
conversion from 'T' to 'GraphQL.Types.IGraphType'.
So is it possible to create generic graph object type?
How can I gain this?
Thanks
I just ran into this issue as well. I tried looking at the answer from Nkosi and must be misunderstanding it because I couldn't get it to work as described above. Here is how I solved it.
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
}
public class ResultSet<T>
{
public T[] Results { get; set; }
public int TotalResultsCount { get; set; }
}
public class BookType : ObjectGraphType<Book>
{
public BookType()
{
Field(b => b.Id);
Field(b => b.Title);
}
}
public class ResultSetType<T, TType> : ObjectGraphType<ResultSet<T>>
where TType : IGraphType
{
public ResultSetType()
{
Name = $"{typeof(TType).Name}ResultSet";
Field<ListGraphType<TType>>("results");
Field<IntGraphType>("totalResultsCount");
}
}
This can now be used as a field in a query as follows:
Field<ResultSetType<Book, BookType>>(
"books",
arguments: new QueryArguments(new QueryArgument<NonNullGraphType<IntGraphType>> { Name = "pageIndex" }, new QueryArgument<NonNullGraphType<IntGraphType>> { Name = "pageSize" }),
resolve: ctx => booksRepository.ReadBooks(ctx.GetArgument<int>("pageIndex"), ctx.GetArgument<int>("pageSize"))
);
My query allows for paging where a user(or UI) could specify how many results they want to get at once as well as which page they want to view, so it is passing in two arguments, but the part that would be of interest to you would be Field<ResultSetType<Book, BookType>>("books");
ListGraphType<T> is defined as
public class ListGraphType<T> : ListGraphType
where T : IGraphType
{
public ListGraphType()
: base(typeof(T))
{
}
}
That message implies that you are missing the IGraphType constraint that the type argument should be derived from if you want to use it with the ListGraphType<>
public class PagedResultType<T>: ObjectGraphType<T> where T : class, IGraphType {
//...
}
Adding the constraint now means that any type argument used with the page result has to be derived from IGraphType
For example
public class ComplaintSourceDTO: ObjectGraphType<ComplaintSourceDTO> {
//...
}
I have the following data class and VM class:
public interface IData
{
string Name
{
get;
}
}
public class DataPartial: IData
{
public DataPartial()
{
}
public string Name => "Data partial";
}
public class DataFull : IData
{
public string Name => "Data full";
public DataFull()
{
}
}
public interface IVM
{
IData Data { get; }
}
public interface IVM_partial: IVM
{
new DataPartial Data { get; }
}
public class VM_Partial : IVM_partial
{
public VM_Partial()
{
Data = new DataPartial();
}
public DataPartial Data { get; set; }
IData IVM.Data => Data;
}
public interface IVM_Total:IVM_partial
{
new DataFull Data { get; }
}
public class VM_Total : IVM_Total
{
public VM_Total(IVM_partial dataA)
{
Data = new DataFull();
DataA_interface = dataA;
}
public IVM_partial DataA_interface { get; }
public DataFull Data { get; private set; }
DataPartial IVM_partial.Data => DataA_interface.Data;
IData IVM.Data => Data;
}
public static class RunVM<T, VM>
where T: class, IData
where VM :class, IVM
{
public static T RunMe(VM hi)
{
var vmA = (hi as VM); //how to force-cast this to the VM type??!!
return (T)vmA.Data;
}
}
class Program
{
static void Main(string[] args)
{
VM_Partial partialData = new VM_Partial();
var VMClass = new VM_Total(partialData);
RunVM<DataFull, IVM_Total>.RunMe(VMClass);
RunVM<DataPartial, IVM_partial>.RunMe(VMClass); //here it throws exception because I can't force cast the IVM to IVM_partial
}
}
At the method RunVM<DataPartial, IVM_partial>.RunMe(VMClass);, I want it to return me the DataPartial object, which I know it's there in the object VMClass, but I cannot get it done.
I will get an InvalidCastException when I am at the RunMe method, because the parameter hi is always VMClass, and I can never get it to behave like IVM_partial class. In other words, I can't cast hi to a more basic interface IVM_partial.
How to cast hi to a more basic interface IVM_partial? Is it possible at all, and if not, why not?
It's not the cast that's the problem - it's that you expect the compiler (or runtime) to pick up on the fact that the cast is to a type that declares a new Data property.
This line in RunMe:
return (T)vmA.Data;
... will always use the Data property declared by IVM, because that's the only property the compiler knows about when it's compiling that method. It doesn't matter that you're casting to another interface that contains a new Data property... the cast is about an execution-time check; it doesn't change which Data property the method uses.
It's unclear to me exactly what you're trying to achieve here, but I strongly suspect that you'll need to change tack significantly - maybe by adding another generic type parameter into the mix, maybe by using polymorphism more, or maybe changing the design more radically.
I have a bigger Projekt and I would like to change a variable value into the BaseClass if the variable value into the derived class are changed.
Here a simple Example.
What I want are, if I change the value Obj.ModelTyp.Name to “Name123“ then the Base.ModelTyp.Name gets the same value “Name123“ automatically.
Is there a simple way to do that?
Thanks Steffen
namespace Question
{
class Program
{
static void Main(string[] args)
{
DataObjekt Obj = new DataObjekt();
Obj.ModelTyp.Name = "Name123"; // is there a Way to Change Base.ModelTyp.Name
// if Obj.ModelTyp.Name is changed?
Obj.ModelTyp.Data = "4567";
Obj.DoSomithing();
}
}
public class FirstBaseClass
{
public FirstBaseClass() { ModelTyp = new BaseType(); }
public BaseType ModelTyp { get; set; }
}
public class SecondBaseClass : FirstBaseClass
{
public void DoSomithing()
{
string Test = this.ModelTyp.Name; // there is nothing because Base.ModelTyp.Name
//but I Want to have "Name123"
}
}
public class DataObjekt : SecondBaseClass
{
public DataObjekt() { ModelTyp = new ObjektData(); }
new public ObjektData ModelTyp { get; set; }
}
public class BaseType
{
public string Name { get; set; }
}
public class ObjektData : BaseType
{
public string Data { get; set; }
}
}
Your classes' relationships seem really complicated and convoluted. You should probably consider simplifying it a bit.
Anyway, the reason why your code does not work now is because you hid the base class' ModelTyp property, and created another new ModelTyp property in DataObjekt. Hopefully you already knew this.
But you don't really want to create a brand new, separate property, do you? You just want to change the type of ModelTyp to ObjektData. Therefore, you can just make DataObjekt.ModelTyp refer to the same thing as FirstBaseClass.ModelTyp in the constructor:
public DataObjekt() {
ModelTyp = new ObjektData();
base.ModelTyp = this.ModelTyp; // <- this line
}