How to use automapper in minimal api? - c#

I am trying to use automapper in my new minimal api's project that i connected with cosmos db. When i try to get all of my objects i get the error: "Missing type map configuration or unsupported mapping" what's wrong ?
My CarRequests class:
public static class CarRequests
{
public static WebApplication CarEndpoints(this WebApplication app)
{
app.MapGet("/cars", CarRequests.GetAll);
return app;
}
public static IResult GetAll(ICarService service, IMapper mapper)
{
var cars = service.GetAll();
var result = mapper.Map<List<CarDto>>(cars);
return Results.Ok(result);
}
}
Car class:
public class Car
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "producent")]
public Producent Producent { get; set; }
[JsonProperty(PropertyName = "age")]
public int Age { get; set; }
[JsonProperty(PropertyName = "yearCreated")]
public int YearCreated { get; set; }
[JsonProperty(PropertyName = "engine")]
public Engine Engine { get; set; }
public Car()
{
Id= Guid.NewGuid().ToString();
YearCreated = DateTime.Now.Year - Age;
}
}
Engine class:
public class Engine
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "horsePower")]
public int HorsePower { get; set; }
[JsonProperty(PropertyName = "description")]
public string Description { get; set; }
public Engine()
{
Id= Guid.NewGuid().ToString();
}
}
EngineDto:
public class EngineDto
{
[JsonProperty(PropertyName = "horsePower")]
public int HorsePower { get; set; }
[JsonProperty(PropertyName = "description")]
public string Description { get; set; }
}
CarDto:
public class CarDto
{
[JsonProperty(PropertyName = "producent")]
public Producent Producent { get; set; }
[JsonProperty(PropertyName = "age")]
public int Age { get; set; }
[JsonProperty(PropertyName = "yearCreated")]
public EngineDto Engine { get; set; }
}
my service:
public async Task<IEnumerable<Car>> GetAll()
{
string queryString = "select * from c";
var feedIterator = _container.GetItemQueryIterator<Car>(new QueryDefinition(queryString));
List<Car> cars = new List<Car>();
while (feedIterator.HasMoreResults)
{
var response = await feedIterator.ReadNextAsync();
cars.AddRange(response.ToList());
}
return cars;
}
Mapper profile:
public class AutoMapperProfile:Profile
{
public AutoMapperProfile()
{
CreateMap<Car, CarDto>();
CreateMap<Engine, EngineDto>();
CreateMap<CarDto, Car>();
CreateMap<EngineDto, Engine>();
}
}
I also register my automapper in Program.cs file:
builder.Services
.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());

Related

Web API C# .net: cannot convert the model in the dto in get method

As I said in the title, I'm trying to convert in the get method a model object to its DTO.
My method is to get users and is the next piece of code:
// GET: api/Users
[HttpGet]
public async Task<ActionResult<IEnumerable<UserDTO>>> GetUsers()
{
var users = _context.Users.ToList();
var userDtos = new List<UserDTO>();
foreach (var user in users)
{
userDtos.Add(new UserDTO
{
IdUser = user.UserProfessionId,
UserName = user.UserName,
UserCompany = user.UserCompany,
UserMail = user.UserMail,
UserProfession = user.UserProfession,
UserProfessionField = user.UserProfessionField
});
}
return userDtos;
}
These are my model and DTO for user:
namespace Sims.Models
{
public partial class User
{
public User()
{
DataUsages = new HashSet<DataUsage>();
}
public long IdUser { get; set; }
public int UserProfessionId { get; set; }
public int UserProfessionFieldId { get; set; }
public string? UserName { get; set; }
public string? UserMail { get; set; }
public string? UserCompany { get; set; }
public byte[]? UserPicture { get; set; }
public virtual Profession UserProfession { get; set; } = null!;
public virtual ProfessionField UserProfessionField { get; set; } = null!;
public virtual ICollection<DataUsage> DataUsages { get; set; }
}
}
and
namespace sims.DTO
{
public partial class UserDTO
{
public long IdUser { get; set; }
public string? UserName { get; set; }
public string? UserMail { get; set; }
public string? UserCompany { get; set; }
public virtual ProfessionDTO UserProfession { get; set; } = null!;
public virtual ProfessionFieldDTO UserProfessionField { get; set; } = null!;
}
}
Profession and ProfessionField are also models and have their own DTO. But in the get method, the two following lines contain the same error as it "cannot implicitly convert type '....Models.Profession' to '....DTO.ProfessionDTO'".
Do you have any idea ?
In case, here is an example of the Profession Model and DTO:
namespace Sims.Models
{
public partial class Profession
{
public Profession()
{
ProfessionFields = new HashSet<ProfessionField>();
Users = new HashSet<User>();
}
public int IdProfession { get; set; }
public string ProfessionName { get; set; } = null!;
public virtual ICollection<ProfessionField> ProfessionFields { get; set; }
public virtual ICollection<User> Users { get; set; }
}
}
and
namespace sims.DTO
{
public class ProfessionDTO
{
public int IdProfession { get; set; }
public string ProfessionName { get; set; } = null!;
}
}
Thanks for reading
The UserProfession property is of type ProfessionDTO:
public virtual ProfessionDTO UserProfession { get; set; } = null!;
But you're trying to populate it with an object of type Profession:
UserProfession = user.UserProfession,
Just as the error states, they are different types and can't be substituted for one another. Populate the property with an instance of ProfessionDTO instead:
UserProfession = new UserProfessionDTO
{
IdProfession = user.UserProfession.IdProfession,
ProfessionName = user.UserProfession.ProfessionName
},
If the user.UserProfession field is null then you'd need to check for that. For example:
UserProfession = user.UserProfession == null ?
null as UserProfessionDTO :
new UserProfessionDTO
{
IdProfession = user.UserProfession?.IdProfession,
ProfessionName = user.UserProfession?.ProfessionName
},

Parsing JSON data to C# Object

I have JSON file which contains multiple arrays of objects:
{
"projects":[{
"issuetypes":[{
"fields":{
"priority":{
"allowedValues":[{
"self":"",
"iconUrl":"",
"name":"",
"id":"1"
}]
},
"components":{
"allowedValues":[{
"self":"",
"id":"",
"name":""
}
And I tried to parse it to C# class.
Google have examples only with simplified version of deserializing JSON do C# Object.
What I created now ?
public class RootObject
{
[JsonProperty(PropertyName = "projects")]
public List<ProjectObject> Projects { get; set; }
}
public class ProjectObject
{
[JsonProperty(PropertyName = "issueTypes")]
public List<IssueObject> Issues { get; set; }
}
public class IssueObject
{
[JsonProperty(PropertyName = "fields")]
public FieldObject Field { get; set; }
}
public class FieldObject
{
[JsonProperty(PropertyName = "components")]
public ComponentObject Component { get; set; }
[JsonProperty(PropertyName = "priority")]
public PriorityObject Priority { get; set; }
}
public class PriorityObject
{
[JsonProperty(PropertyName = "value")]
public PriorityAllowedValues PriorityValues { get; set; }
}
public class PriorityAllowedValues
{
public List<PriorityValues> AllowedValues { get; set; }
}
public class PriorityValues
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "self")]
public string Self { get; set; }
[JsonProperty(PropertyName = "iconUrl")]
public string IconUrl { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
}
public class ComponentObject
{
[JsonProperty(PropertyName = "value")]
public ComponentAllowedValues ComponentAllowedValues { get; set; }
}
public class ComponentAllowedValues
{
public List<SelectObject> AllowedValues { get; set; }
}
public class SelectObject
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "self")]
public string Self { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
}
And when I am trying to execute this line:
RootObject root = JsonConvert.DeserializeObject<RootObject>(data);
Data from JSON file should go properly to RootObject...
There are some tools which can help you generate classes from JSON, e.g. https://jsonutils.com/
This structure should work for provided json:
public class AllowedValue
{
[JsonProperty("self")]
public string Self { get; set; }
[JsonProperty("iconUrl")]
public string IconUrl { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
}
public class Priority
{
[JsonProperty("allowedValues")]
public IList<AllowedValue> AllowedValues { get; set; }
}
public class AllowedValue
{
[JsonProperty("self")]
public string Self { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
public class Components
{
[JsonProperty("allowedValues")]
public IList<AllowedValue> AllowedValues { get; set; }
}
public class Fields
{
[JsonProperty("priority")]
public Priority Priority { get; set; }
[JsonProperty("components")]
public Components Components { get; set; }
}
public class Issuetype
{
[JsonProperty("fields")]
public Fields Fields { get; set; }
}
public class Project
{
[JsonProperty("issuetypes")]
public IList<Issuetype> Issuetypes { get; set; }
}
public class RootObject
{
[JsonProperty("projects")]
public IList<Project> Projects { get; set; }
}

Unable to add an item to a database, ModelState.IsValid == false

I am working on an ASP.NET MVC application. Basically right now I'am trying to do the following: I created an API helper class that deserializes JSON data returned from Google Books API. In my Create.cshtml I only want to pass the ISBN of the book I am trying to add, however, as I discovered in debugger, ModelState.Is valid is false and therefore the new book does not get created. As far as I can see in the debugger, all the data gets pulled from the API correctly into the dictionary, however for some reason I can't store it my DB.
I know that there is probably a more elegant solution for this, but any kind of advice is more than welcome. Thank you for your time.
Here are the code files that might help:
APIHelper : deserializes JSON data and stores it in a Dictionary.
namespace APIHelper
{
public class IndustryIdentifier
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("identifier")]
public string Identifier { get; set; }
}
public class ReadingModes
{
[JsonProperty("text")]
public bool Text { get; set; }
[JsonProperty("image")]
public bool Image { get; set; }
}
public class ImageLinks
{
[JsonProperty("smallThumbnail")]
public string SmallThumbnail { get; set; }
[JsonProperty("thumbnail")]
public string Thumbnail { get; set; }
}
public class VolumeInfo
{
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("subtitle")]
public string Subtitle { get; set; }
[JsonProperty("authors")]
public IList<string> Authors { get; set; }
[JsonProperty("publisher")]
public string Publisher { get; set; }
[JsonProperty("publishedDate")]
public string PublishedDate { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("industryIdentifiers")]
public IList<IndustryIdentifier> IndustryIdentifiers { get; set; }
[JsonProperty("readingModes")]
public ReadingModes ReadingModes { get; set; }
[JsonProperty("pageCount")]
public int PageCount { get; set; }
[JsonProperty("printType")]
public string PrintType { get; set; }
[JsonProperty("categories")]
public IList<string> Categories { get; set; }
[JsonProperty("maturityRating")]
public string MaturityRating { get; set; }
[JsonProperty("allowAnonLogging")]
public bool AllowAnonLogging { get; set; }
[JsonProperty("contentVersion")]
public string ContentVersion { get; set; }
[JsonProperty("imageLinks")]
public ImageLinks ImageLinks { get; set; }
[JsonProperty("language")]
public string Language { get; set; }
[JsonProperty("previewLink")]
public string PreviewLink { get; set; }
[JsonProperty("infoLink")]
public string InfoLink { get; set; }
[JsonProperty("canonicalVolumeLink")]
public string CanonicalVolumeLink { get; set; }
}
public class SaleInfo
{
[JsonProperty("country")]
public string Country { get; set; }
[JsonProperty("saleability")]
public string Saleability { get; set; }
[JsonProperty("isEbook")]
public bool IsEbook { get; set; }
}
public class Epub
{
[JsonProperty("isAvailable")]
public bool IsAvailable { get; set; }
}
public class Pdf
{
[JsonProperty("isAvailable")]
public bool IsAvailable { get; set; }
}
public class AccessInfo
{
[JsonProperty("country")]
public string Country { get; set; }
[JsonProperty("viewability")]
public string Viewability { get; set; }
[JsonProperty("embeddable")]
public bool Embeddable { get; set; }
[JsonProperty("publicDomain")]
public bool PublicDomain { get; set; }
[JsonProperty("textToSpeechPermission")]
public string TextToSpeechPermission { get; set; }
[JsonProperty("epub")]
public Epub Epub { get; set; }
[JsonProperty("pdf")]
public Pdf Pdf { get; set; }
[JsonProperty("webReaderLink")]
public string WebReaderLink { get; set; }
[JsonProperty("accessViewStatus")]
public string AccessViewStatus { get; set; }
[JsonProperty("quoteSharingAllowed")]
public bool QuoteSharingAllowed { get; set; }
}
public class SearchInfo
{
[JsonProperty("textSnippet")]
public string TextSnippet { get; set; }
}
public class Item
{
[JsonProperty("kind")]
public string Kind { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("etag")]
public string Etag { get; set; }
[JsonProperty("selfLink")]
public string SelfLink { get; set; }
[JsonProperty("volumeInfo")]
public VolumeInfo VolumeInfo { get; set; }
[JsonProperty("saleInfo")]
public SaleInfo SaleInfo { get; set; }
[JsonProperty("accessInfo")]
public AccessInfo AccessInfo { get; set; }
[JsonProperty("searchInfo")]
public SearchInfo SearchInfo { get; set; }
}
public class RootObject
{
[JsonProperty("kind")]
public string Kind { get; set; }
[JsonProperty("totalItems")]
public int TotalItems { get; set; }
[JsonProperty("items")]
public IList<Item> Items { get; set; }
}
public class APIHelper
{
public string Get(string uri)
{
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(uri);
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
public Dictionary<string, string> DictionaryReturnData(string isbn)
{
string path = "https://www.googleapis.com/books/v1/volumes?q=isbn:" + isbn;
string json = Get(path);
Dictionary<string, string> responses = new Dictionary<string, string>();
var rootObject = JsonConvert.DeserializeObject<RootObject>(json);
foreach (var obj in rootObject.Items )
{
responses.Add("Title", obj.VolumeInfo.Title);
responses.Add("Description", obj.VolumeInfo.Description);
responses.Add("Image", obj.VolumeInfo.ImageLinks.Thumbnail);
responses.Add("Authors", string.Join(",", obj.VolumeInfo.Authors)); //list of strings
responses.Add("Genre", string.Join(",", obj.VolumeInfo.Categories)); //list of strings
responses.Add("Isbn", isbn);
responses.Add("Publisher", obj.VolumeInfo.Publisher);
responses.Add("PublishedDate", obj.VolumeInfo.PublishedDate);
responses.Add("PageCount", obj.VolumeInfo.PageCount.ToString());
}
return responses;
}
}
}
My Book class:
namespace BookstoreWeb.Models
{
public class Book
{
public int Id { get; set; }
[Required]
public string Isbn { get; set; }
[Required]
public string Title { get; set; }
public string Author { get; set; }
public double Price { get; set; }
[Required]
public string Description { get; set; }
public string Publisher { get; set; }
public string PublishedDate { get; set; }
public string PageCount { get; set; }
public string Thumbnail { get; set; }
public string Genre { get; set; }
}
}
Create Action
[HttpPost]
public IActionResult Create(Book model)
{
APIHelper.APIHelper helper = new APIHelper.APIHelper();
var responses = helper.DictionaryReturnData(model.Isbn);
model.Author = responses["Authors"];
model.Genre = responses["Genre"];
model.Isbn = responses["Isbn"];
model.Price = 10.00;
model.Title = responses["Title"];
model.Description = responses["Description"];
model.Publisher = responses["Publisher"];
model.PublishedDate = responses["PublishedDate"];
model.PageCount = responses["PageCount"];
model.Thumbnail = responses["Image"];
if (ModelState.IsValid) //check for validation
{
var newBook = new Book
{
Author = model.Author,
Genre = model.Genre,
Isbn = model.Isbn,
Price = model.Price,
Title = model.Title,
Description = model.Description,
Publisher = model.Publisher,
PublishedDate = model.PublishedDate,
PageCount = model.PageCount,
Thumbnail = model.Thumbnail,
};
newBook = _bookstoreData.Add(newBook);
_bookstoreData.Commit();
return RedirectToAction("Details", new {id = newBook.Id});
}
Removing the annotations [Required] from Book class seems to have solved the issue.

Entity to model mapping in LINQ

I have article and author classes.
Fetch articles like so and map entity to model:
public List<Model.Article> GetArticleList() {
using (var db = new ArticlesContext()) {
return db.Articles.Select(t => new Model.Article() {
Author = MapUserEntityToModel(db.Users.FirstOrDefault(u => u.UserID == t.UserID))
Title = t.Title,
Teaser = t.Teaser
// etc
}).ToList();
}
}
This doesn't work because LINQ can't run that function at run-time. What's the simplest and cleanest way to do the mapping?
Here are models:
namespace Model {
public class Article {
public string Title { get; set; }
public string Teaser { get; set; }
public User Author { get; set; }
public DateTime DateAdded { get; set; }
}
public class User {
public string DisplayName { get; set; }
public string Email { get; set; }
public string Website { get; set; }
public string PasswordHash { get; set; }
}
}
Here are entities:
namespace MyProj {
public class Article {
[Key]
public int ArticleID { get; set; }
public string Title { get; set; }
public string Teaser { get; set; }
public int UserID { get; set; }
public DateTime DateAdded { get; set; }
}
public class User {
[Key]
public int UserID { get; set; }
public string DisplayName { get; set; }
public string Email { get; set; }
public string Website { get; set; }
public string PasswordHash { get; set; }
}
public class ArticleContext : DbContext {
public ArticleContext() : base("name=conn") {
public DbSet<Article> Articles { get; set; }
public DbSet<User> Users { get; set; }
}
}
}
Before continue, map your relationship in a navigation property:
public class Article {
[Key]
public int ArticleID { get; set; }
public string Title { get; set; }
public string Teaser { get; set; }
[ForeignKey("UserID")]
public virtual User Author {get; set; } // navigation property
public int UserID { get; set; }
public DateTime DateAdded { get; set; }
}
And then just project your navigation property to his equivalent Model:
public List<Model.Article> GetArticleList() {
using (var db = new ArticlesContext()) {
return db.Articles.Select(t => new Model.Article() {
Author = new Model.User {
DisplayName = t.User.DisplayName,
Email = t.User.Email,
Website = t.User.Website,
PasswordHash = t.User.PasswordHash
},
Title = t.Title,
Teaser = t.Teaser
// etc
}).ToList();
}
}
You don't need to do anything, just return db.Articles directly:
using Model;
public List<Article> GetArticleList() {
using(var db = new ArticlesContext()) {
return db.Articles.ToList();
}
}
Assuming your EF model is set-up correctly with Foreign Keys, your Article type will have a lazily-evaluated Author property which will return a User object when accessed.

Cannot convert source type 'void' to target type 'ICollection<Character>'

I have a DataContract class that I'm trying to convert to another class, Movie but for the property Movie.Characters I'm getting the error...
Cannot convert source type 'void' to target type 'ICollection<Character>'
How can I create a new Movie so the Character property is set properly mapped to each Person and Movie?
var movies = dataContract.Movies.Select(m => new Movie {
Id = m.Id,
Title = m.Title,
Characters = m.AbridgedCast.ToList().ForEach(p => new Person { Name = p.Name,
RottenTomatoesId = p.Id,
Characters = p.Characters.ToList().ForEach(c => new Character { Name = c })})
});
MoviesDataContract.cs
public class MoviesDataContract {
[DataMember(Name = "total")]
public int Total { get; set; }
[DataMember(Name = "movies")]
public IEnumerable<Movie> Movies { get; set; }
#region Internal Classes
[DataContract]
public class Movie {
[DataMember(Name = "id")]
public int Id { get; set; }
[DataMember(Name = "title")]
public string Title { get; set; }
[DataMember(Name = "abridged_cast")]
public virtual IEnumerable<Person> AbridgedCast { get; set; }
}
[DataContract]
public class Person {
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "id")]
public int Id { get; set; }
[DataMember(Name = "characters")]
public IEnumerable<string> Characters { get; set; }
}
#endregion
}
Movies.cs
public partial class Movie {
public Movie() {
this.Characters = new HashSet<Character>();
}
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<Character> Characters { get; set; }
}
public partial class Character {
public System.Guid Id { get; set; }
public int MovieId { get; set; }
public System.Guid PersonId { get; set; }
public string Name { get; set; }
public virtual Movie Movie { get; set; }
public virtual Person Person { get; set; }
}
public partial class Person {
public Person() {
this.Characters = new HashSet<Character>();
}
public System.Guid Id { get; set; }
public string Name { get; set; }
public int RottenTomatoesId { get; set; }
public virtual ICollection<Character> Characters { get; set; }
}
List<T>.ForEach(...) doesn't return anything. See on MSDN.
You might want to do a projection with Select(...) then ToList().

Categories