automapper issue in nested entity - model-view-controller

Entity:
public class AccountEntity: MasterEntity
{
public AccountType AccountType { get; set; }
public DepartmentEntity Department { get; set; }
public string LeadSource { get; set; }
public ResourceEntity AccountManager { get; set; }
public AccountQualificationStatus QualificationStatus { get; set; }
}
public class DepartmentEntity : MasterEntity
{
}
public class ResourceEntity : MasterEntity
{
public string Email { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
public abstract class MasterEntity: Entity
{
public string Name { get; set; }
public string Code { get; set; }
}
Model
public class Accounts
{
private string depname;
public int Id { get; set; }
public string Name { get; set; }
public int Code { get; set; }
public string AccountType { get; set; }
public string Department { get; set; }
}
public AccountMappingProfile()
{
CreateMap<Account, AccountTest>().ReverseMap();
CreateMap<Opportunity, OpportunityEntity>().ReverseMap();
CreateMap<Accounts, AccountEntity>().ReverseMap();
CreateMap<Resource, ResourceEntity>().ReverseMap();
CreateMap<Projects, ProjectEntity>().ReverseMap();
}
public static class AccountMapper
{
private static readonly Lazy<IMapper> Lazy = new Lazy<IMapper>(() =>
{
var config = new MapperConfiguration(cfg => {
cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
cfg.AddProfile<AccountMappingProfile>();
});
var mapper = config.CreateMapper();
return mapper;
});
public static IMapper Mapper => Lazy.Value;
}
I am able to fetch resource details .while I am fetching accounts with department and resources, the value for department is giving me null after automapping.
public async Task<IEnumerable<Accounts>> GetAccounts()
{
try
{
var accounts = await _context.Account.Include(c=>c.Director).ToListAsync();
// accounts = await _context.Account.Include(c => c.Department).ToListAsync();
return AccountMapper.Mapper.Map<List<Accounts>>(accounts);
}
}
controller method:
public async Task<IEnumerable<Accounts>> GetClients()
{
var result = await _repository.GetAccounts();
return result;
}
if I am uncommenting the code to include department, its is giving the object name.
I need to get the department details as well. how can i get that.Department entity is inheriting master entity.

Related

Receiving Multi-part form data in dotnet core web API

I'm working on an web API, where it needs to receive the multi-part form data with in a model. As of now it's not receiving the request and showing the Bad request When I tried from the Postman.
My model :
public class InvoiceDetails
{
public int? po_id { get; set; }
public DateTime created_date { get; set; }
public string grn_status { get; set; }
public int utilization_amount { get; set; }
public int currency_id { get; set; }
public string currency_code { get; set; }
public string currency_symbol { get; set; }
[FromForm(Name = "invoice_file")]
public List<IFormCollection> invoice_file { get;set;}
[FromForm(Name = "other_files")]
public List<IFormCollection> other_files { get; set; }
}
In the above class/model "invoice_file" and "other_files" can have multiple file uploads so I made it List.
My Action Method :
[HttpPost]
[Route("CreateInvoice")]
public IActionResult CreateInvoice([FromForm]InvoiceDetails idobj )
{
//var modelData = Request.Form["invoice_file"];
Response resobj = new Response();
try
{
if (idobj.invoice_file.Count > 0)
{
resobj = _dataContext.AddInvoice(idobj);
if (resobj.flag == true)
{
Upload(idobj);
}
}
else
{
resobj.flag = false;
resobj.message = "please upload atleast one invioce file";
}
}
catch (Exception ex)
{
}
return Ok(resobj);
}
How can I make the action method or model, in such a way that user can upload the model with multiple files to the properties other_files & invoice_file.
Reference of postman Image
As CodeCaster says,add Content-Type:multipart/form-data; and change List<IFormCollection> to List<IFormFile>.It is not changing the whole model to List.So you can also retrieve other information which exists in your model with idobj.xxx.Change
public class InvoiceDetails
{
public int? po_id { get; set; }
public DateTime created_date { get; set; }
public string grn_status { get; set; }
public int utilization_amount { get; set; }
public int currency_id { get; set; }
public string currency_code { get; set; }
public string currency_symbol { get; set; }
[FromForm(Name = "invoice_file")]
public List<IFormCollection> invoice_file { get;set;}
[FromForm(Name = "other_files")]
public List<IFormCollection> other_files { get; set; }
}
to
public class InvoiceDetails
{
public int? po_id { get; set; }
public DateTime created_date { get; set; }
public string grn_status { get; set; }
public int utilization_amount { get; set; }
public int currency_id { get; set; }
public string currency_code { get; set; }
public string currency_symbol { get; set; }
[FromForm(Name = "invoice_file")]
public List<IFormFile> invoice_file { get; set; }
[FromForm(Name = "other_files")]
public List<IFormFile> other_files { get; set; }
}
result:
IFormCollection is used to retrieve all the values from posted form data.refer to the official document.
If you want to use c,you can try to use it,you can do like this
public IActionResult CreateInvoice([FromForm]IFormCollection idobj)
and you need to get the data you want to foreach keys of IFormCollection,so public List<IFormCollection> invoice_file { get;set;} is better than use IFormCollection.

ServiceStack validators not firing

I am trying to use fluent validation in ServiceStack. I've added the validation plugin and registered my validator.
Plugins.Add(new ValidationFeature());
container.RegisterValidators(typeof(CreateLeaveValidator).Assembly);
I have implemented a validator class for my service model:
public class CreateLeaveValidator : AbstractValidator<CreateLeave>
{
public CreateLeaveValidator()
{
RuleFor(cl => cl.StudentId).NotEmpty();
RuleFor(cl => cl.LeaveDepart).NotEmpty().GreaterThan(DateTime.Now).WithMessage("Leave must begin AFTER current time and date.");
RuleFor(cl => cl.LeaveReturn).NotEmpty().GreaterThan(cl => cl.LeaveDepart).WithMessage("Leave must end AFTER it begins.");
RuleFor(cl => cl.ApprovalStatus).Must( status => ( ("P".Equals(status)) || ("C".Equals(status)) || ("A".Equals(status)) || ("D".Equals(status)) ) );
}
}
Service Model:
[Route("/leaves", "POST")]
public class CreateLeave : IReturn<LeaveResponse>, IUpdateApprovalStatus
{
public int StudentId { get; set; }
public DateTime RequestDate { get; set; }
public DateTime LeaveDepart { get; set; }
public DateTime LeaveReturn { get; set; }
public string Destination { get; set; }
public string HostRelationship { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Postal { get; set; }
public string Hostphone { get; set; }
public string Cellphone { get; set; }
public string Transport { get; set; }
public string Driver { get; set; }
public string Companions { get; set; }
public string Reason { get; set; }
public string ApprovalStatus { get; set; }
public DateTime ApprovalDate { get; set; }
public string ApprovalComment { get; set; }
public string ApprovalReason { get; set; }
public int ApprovalUser { get; set; }
}
But when I create a request with no StudentId or an invalid ApprovalStatus, the validator does not appear to fire and catch the invalid request.
How can I go about troubleshooting the cause of this?
UPDATE: Correction it appears validators are working with my actual service but not in my unit tests. I'm guessing I must not be configuring my apphost correctly in the unit test setup. Here's my test constructor:
public LeaveTests()
{
Licensing.RegisterLicense(#"[license key]");
appHost = new BasicAppHost(typeof(ApiServices).Assembly).Init();
ServiceStack.Text.JsConfig.DateHandler = ServiceStack.Text.DateHandler.ISO8601;
appHost.Plugins.Add(new ValidationFeature());
appHost.Container.RegisterValidators(typeof(CreateLeaveValidator).Assembly);
}
ServiceStack Validation filters are executed in a Global Request Filter which require a full integration test to run, e.g:
public class MyIntegrationTests
{
ServiceStackHost appHost;
public MyIntegrationTests()
{
appHost = new AppHost()
.Init()
.Start("http://localhost:8000/");
}
[OneTimeTearDown] void OneTimeTearDown() => appHost.Dispose();
[Test]
public void Execute_validation_filters()
{
var client = new JsonServiceClient("http://localhost:8000/");
try
{
var response = client.Post(new CreateLeave { ... });
}
catch(WebServiceException ex)
{
//...
}
}
}

Microsoft Cognitive Services Web Search API - DeSerialization Issues

I want to learn Cognitive Services Web Search APIs so I started creating a bot application . I already have a account sub- key and other required information also I read many articles and watch build 2016 videos on this as well.I am having trouble while deserializing the result .
I am not able to find the proxy class that I can use to do that .
The url I am using is https://api.cognitive.microsoft.com/bing/v5.0/search/
and I found a proxy class for previous api version . Can anybody tell me how to get proxy class of the api request / response in VS 2015 for these service.
My Code look like this:
string BingSearchUrl = "https://api.cognitive.microsoft.com/bing/v5.0/search/";
const string bingKey = "Key";
public static async Task<string> Search(string query)
{
var client = HttpClientFactory.Create();
var queryString = BingSearchUrl + "?q=" + query + "&count=10";
// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", bingKey);
client.DefaultRequestHeaders.Add("Accept", "application/json");
// Request parameters
string r = await client.GetStringAsync(queryString);
var jsonResult = JsonConvert.DeserializeObject<Bing.ExpandableSearchResult>(r);
return jsonResult.Web.First().Title;
Try below code
public string BingSearchUrl = "https://api.cognitive.microsoft.com/bing/v5.0/search/";
const string bingKey =[KEY];
public async void Search()
{
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", bingKey);
// Request parameters
queryString["q"] = "microsoft";
queryString["count"] = "10";
queryString["offset"] = "0";
queryString["mkt"] = "en-us";
queryString["safeSearch"] = "Moderate";
var uri = "https://api.cognitive.microsoft.com/bing/v5.0/news/search?" + queryString;
var response = await client.GetStringAsync(uri);
var jsonResult = JsonConvert.DeserializeObject<BingJson>(response);
string title = jsonResult.value[0].name.ToString();
}
With the jsonResult.value[0] you can loop through the results. First results is at [0] position.
I Created a model class looking at the bing search response json. It looks like,
public class BingJson
{
public string _type { get; set; }
public Instrumentation instrumentation { get; set; }
public string readLink { get; set; }
public int totalEstimatedMatches { get; set; }
public Value[] value { get; set; }
}
public class Instrumentation
{
public string pingUrlBase { get; set; }
public string pageLoadPingUrl { get; set; }
}
public class Value
{
public string name { get; set; }
public string url { get; set; }
public string urlPingSuffix { get; set; }
public Image image { get; set; }
public string description { get; set; }
public About[] about { get; set; }
public Provider[] provider { get; set; }
public DateTime datePublished { get; set; }
public string category { get; set; }
}
public class Image
{
public Thumbnail thumbnail { get; set; }
}
public class Thumbnail
{
public string contentUrl { get; set; }
public int width { get; set; }
public int height { get; set; }
}
public class About
{
public string readLink { get; set; }
public string name { get; set; }
}
public class Provider
{
public string _type { get; set; }
public string name { get; set; }
}
With this model, I am able to get the desired result. The Model which is presented in the other answer is not working in my case.
namespace BingSearchBot
{
public class RootObject
{
public string _type { get; set; }
public WebPages webPages { get; set; }
public RelatedSearches relatedSearches { get; set; }
public RankingResponse rankingResponse { get; set; }
}
public class WebPages
{
public string webSearchUrl { get; set; }
public int totalEstimatedMatches { get; set; }
public List<Value> value { get; set; }
}
public class Value
{
public string id { get; set; }
public string name { get; set; }
public string url { get; set; }
public List<About> about { get; set; }
public string displayUrl { get; set; }
public string snippet { get; set; }
public List<DeepLink> deepLinks { get; set; }
public string dateLastCrawled { get; set; }
public List<SearchTag> searchTags { get; set; }
}
public class About
{
public string name { get; set; }
}
public class DeepLink
{
public string name { get; set; }
public string url { get; set; }
public string snippet { get; set; }
}
public class SearchTag
{
public string name { get; set; }
public string content { get; set; }
}
public class Value2
{
public string text { get; set; }
public string displayText { get; set; }
public string webSearchUrl { get; set; }
}
public class RelatedSearches
{
public string id { get; set; }
public List<Value2> value { get; set; }
}
public class Value3
{
public string id { get; set; }
}
public class Item
{
public string answerType { get; set; }
public int resultIndex { get; set; }
public Value3 value { get; set; }
}
public class Mainline
{
public List<Item> items { get; set; }
}
public class RankingResponse
{
public Mainline mainline { get; set; }
}
}

insert data in two class(table) in Entity Framwork by rerlation many to many

i create two class in my model and create relation many to many by Entity
in sql my classes is created tables Properly
when i try to insert data in this table get show error "Object reference not set to an instance of an object." my cod is:
public class News
{
public int ID { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime Date { get; set; }
public virtual Picture Picture { get; set; }
public virtual NewsType NewsType { get; set; }
public ICollection<Tag> Tag { get; set; }
public News(int id, string title, string content, DateTime date)
{
this.ID = id;
this.Title = title;
this.Content = content;
this.Date = date;
}
public News()
{
}
}
public class Tag
{
public int ID { get; set; }
public string Title { get; set; }
public ICollection<News> News { get; set; }
public Tag()
{
}
}
public class DatabaseContext : DbContext
{
public DatabaseContext()
: base("News")
{
}
static DatabaseContext()
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<DatabaseContext>());
}
public DbSet<News> newsInfo { get; set; }
public DbSet<Picture> pictures { get; set; }
public DbSet<NewsType> Types { get; set; }
public DbSet<Tag> Tags { get; set; }
}
[HttpPost]
public ActionResult AddNews(NewsViewModel newsInfo)
{
using (Models.DatabaseContext dbContext = new DatabaseContext())
{
ViewData["Type"] = new SelectList(dbContext.Types.ToList(), "Id", "Title");
}
if (!ModelState.IsValid)
{
return View();
}
else
{
Models.DatabaseContext dbContext = new Models.DatabaseContext();
Models.News news = new Models.News();
news.Title = newsInfo.Title;
news.Content = newsInfo.Content;
news.Date = DateTime.Now;
string newsinput = newsInfo.Tag.cleanTag();
string[] tags = new string[] { };
if (newsinput != null)
{
tags = newsinput.Split(',');
}
foreach (string item in tags)
{
Tag findTag = dbContext.Tags.Where(x => x.Title == item).FirstOrDefault();
if (findTag != null)
{
news.Tag.Add(findTag)
////////////////////////show error in this line
}
}
news.NewsType = dbContext.Types.Find(Convert.ToInt32(Request.Form["rdb"]));
dbContext.newsInfo.Add(news);
dbContext.SaveChanges();
return View();
}

Use Automapper to flatten sub-class of property

Given the classes:
public class Person
{
public string Name { get; set; }
}
public class Student : Person
{
public int StudentId { get; set; }
}
public class Source
{
public Person Person { get; set; }
}
public class Dest
{
public string PersonName { get; set; }
public int? PersonStudentId { get; set; }
}
I want to use Automapper to map Source -> Dest.
This test obviously fails:
Mapper.CreateMap<Source, Dest>();
var source = new Source() { Person = new Student(){ Name = "J", StudentId = 5 }};
var dest = Mapper.Map<Source, Dest>(source);
Assert.AreEqual(5, dest.PersonStudentId);
What would be the best approach to mapping this given that "Person" is actually a heavily used data-type throughout our domain model.
Edit: The intent is to persist the "Dest" objects which will have fields defined for all properties of the sub-types of "Person". Hence we could have source objects like the following and would prefer not to have to create Dest objects for every possible combination of "Person" sub-classes:
public class Source2
{
public Person Value1 { get; set; }
public Person Value2 { get; set; }
public Person Value3 { get; set; }
public Person Value4 { get; set; }
public Person Value5 { get; set; }
}
Well using Jimmy's suggestion I've settled on the following solution:
public class Person
{
public string Name { get; set; }
}
public class Student : Person
{
public int StudentId { get; set; }
}
//all subtypes of person will map to this dto
public class PersonDto
{
public string Name { get; set; }
public int? StudentId { get; set; }
}
public class Source
{
public Person Person { get; set; }
}
public class DestDto
{
public PersonDto Person { get; set; }
}
public class Dest
{
public string PersonName { get; set; }
public int? PersonStudentId { get; set; }
}
[TestFixture]
public class RandomTests
{
[Test]
public void Test1()
{
Mapper.CreateMap<Person, PersonDto>();
Mapper.CreateMap<Student, PersonDto>();
Mapper.CreateMap<Source, DestDto>();
Mapper.CreateMap<DestDto, Dest>();
var source = new Source() { Person = new Student() { Name = "J", StudentId = 5 } };
var destDto = Mapper.Map<Source, DestDto>(source);
var destFinal = Mapper.Map<DestDto, Dest>(destDto);
Assert.AreEqual(5, destFinal.PersonStudentId);
}
}
Would love to hear suggestions/improvements.

Resources