Automapper Mapping for Localization Resolver in a Multi-Language Website - asp.net-mvc

I found a way to use Automapper for Language mapping based on the active Culture.
The question is if it's possible to build a generic Resolver to map all the models that use the Resolver.
In this Case, the models to map have always the same properties, Id and Name (including the language properties Name_PT, Name_FR and Name_EN):
// MODELS
public class MakeDto
{
// Primary properties
public int Id { get; set; }
public string Name { get; set; }
public string Name_PT { get; set; }
public string Name_FR { get; set; }
public string Name_EN { get; set; }
}
public class MakeViewModel
{
// Primary properties
public int Id { get; set; }
public string Name { get; set; }
}
public class ModelDto
{
// Primary properties
public int Id { get; set; }
public string Name { get; set; }
public string Name_PT { get; set; }
public string Name_FR { get; set; }
public string Name_EN { get; set; }
}
public class ModelViewModel
{
// Primary properties
public int Id { get; set; }
public string Name { get; set; }
}
public class FuelDto
{
// Primary properties
public int Id { get; set; }
public string Name { get; set; }
public string Name_PT { get; set; }
public string Name_FR { get; set; }
public string Name_EN { get; set; }
}
public class FuelViewModel
{
// Primary properties
public int Id { get; set; }
public string Name { get; set; }
}
// AUTOMAPPER PROFILE
public class DtoToViewModelMappingProfile : Profile
{
public override string ProfileName
{
get { return "DtoToViewModelMappings"; }
}
protected override void Configure()
{
CreateMaps();
}
private static void CreateMaps()
{
Mapper.CreateMap<ModelDto, ModelViewModel>();
Mapper.CreateMap<MakeDto, MakeViewModel>()
.ForMember(dest => dest.Name, opt => opt.ResolveUsing<CultureResolver>());
Mapper.CreateMap<FuelDto, FuelViewModel>();
}
public class CultureResolver : ValueResolver<MakeDto, string>
{
protected override string ResolveCore(MakeDto makeDto)
{
switch(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToUpperInvariant())
{
case "FR":
return makeDto.Name_FR;
case "EN":
return makeDto.Name_EN;
}
return makeDto.Name_PT;
}
}
}
Thanks.

You can extract an interface like below:
public interface ILocalizable
{
string Name { get; set; }
string Name_PT { get; set; }
string Name_FR { get; set; }
string Name_EN { get; set; }
}
public class FuelDto : ILocalizable
{
// Primary properties
public int Id { get; set; }
public string Name { get; set; }
public string Name_PT { get; set; }
public string Name_FR { get; set; }
public string Name_EN { get; set; }
}
Then tune your resolver like below:
public class CultureResolver : ValueResolver<ILocalizable, string>
{
protected override string ResolveCore(ILocalizable dto)
{
switch(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToUpperInvariant())
{
case "FR":
return dto.Name_FR;
case "EN":
return dto.Name_EN;
}
return dto.Name_PT;
}
}

Related

Null value assigned when response is written to the Model object

public class BClass
{
public class RClass
{
public string stjCd { get; set; }
public string lgnm { get; set; }
public string stj { get; set; }
public string dty { get; set; }
public List<object> adadr { get; set; }
public string cxdt { get; set; }
public string gstin { get; set; }
public List<string> nba { get; set; }
public string lstupdt { get; set; }
public string rgdt { get; set; }
public string ctb { get; set; }
public Pradr pradr { get; set; }
public string tradeNam { get; set; }
public string sts { get; set; }
public string ctjCd { get; set; }
public string ctj { get; set; }
}
public class AClass
{
public string id { get; set; }
public string consent { get; set; }
public string consent_text { get; set; }
public int env { get; set; }
public string response_code { get; set; }
public string response_msg { get; set; }
public int transaction_status { get; set; }
public string request_timestamp { get; set; }
public string response_timestamp { get; set; }
public RClass result { get; set; }
}
}
//COntroller
BClass.AClass btr = new BClass.AClass();
var lst = JsonConvert.DeserializeObject<BClass.AClass>(strresult);
btr.response_code = lst.response_code;
btr.response_msg = lst.response_msg;
btr.result.lgnm = lst.result.lgnm;
The property btr.result.lgnm = lst.result.lgnm; Gives null value error object reference not set to instance of an object. but the lst variable has a value in the response received.Please provide suggesion
You can solve this by adding one line into your code.
btr.result = new BClass.RClass(); //This one. You need to initialize instance before assigning anything to it.
btr.result.lgnm = lst.result.lgnm;
or else, you can also create default constructor for class A.
public AClass()
{
result = new RClass();
}
I would suggest you to please have a look at below web resources for naming conventions widely used for c# language.
Properties naming conventions: https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/names-of-type-members
class naming conventions: https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
Assigning this way does not give null reference exception
RClass rclass=new RClass();
rclass.lgnm=lst.result.lgnm

Table Value Function mapping with Entity Framework 6.3

How do I map table value functions in Code with Entity Framework 6.3? I'm trying to a DB Context in code with an existing database, because EDMX is currently not supported in ASP.NET Core 3. I've tried setting up my DbContext clasee as below. I can successfully query the Grade table. But when I try to query my function "fn_GetCatgeories", I get the following error: No EdmType found for type 'WebApplication6.Data.ApplicationContext+fn_GetCategories'.
public class ApplicationContext : DbContext
{
public ApplicationContext(string cstr)
: base(cstr)
{
Database.SetInitializer<ApplicationContext>(null);
}
[Table("Grade")]
public class Grade
{
[Key]
public string Grade_ID { get; set; }
public string SchoolType { get; set; }
public int Sortorder { get; set; }
}
public partial class fn_GetCategories
{
public int Category_ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Nullable<bool> Active { get; set; }
public Nullable<System.DateTime> Month { get; set; }
public Nullable<int> Order { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new FunctionsConvention<ApplicationContext>("dbo"));
base.OnModelCreating(modelBuilder);
}
[DbFunction("ApplicationContext", "fn_GetCategories")]
public IQueryable<fn_GetCategories> GetCategories(Nullable<System.DateTime> month)
{
var monthParameter = month.HasValue ?
new ObjectParameter("Month", month) :
new ObjectParameter("Month", typeof(System.DateTime));
return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<fn_GetCategories>(string.Format("[0].{1}", GetType().Name, "[fn_GetCategories](#Month)"), monthParameter);
}
// DbSets here
public DbSet<Grade> Grades { get; set; }
}
This works:
public class ApplicationContext : DbContext
{
public ApplicationContext(string cstr)
: base(cstr)
{
Database.SetInitializer<ApplicationContext>(null);
}
[Table("Grade")]
public class Grade
{
[Key]
public string Grade_ID { get; set; }
public string SchoolType { get; set; }
public int Sortorder { get; set; }
}
public partial class fn_GetCategories_Result
{
[Key]
public int Category_ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Nullable<bool> Active { get; set; }
public Nullable<System.DateTime> Month { get; set; }
public Nullable<int> Order { get; set; }
}
// DbSets here
public DbSet<Grade> Grades { get; set; }
public DbSet<fn_GetCategories_Result> fn_GetCategoriesSet { get; set; }
public List<fn_GetCategories_Result> fn_GetCategories(DateTime month)
{
var m = new SqlParameter("Month", DateTime.Now);
return this.fn_GetCategoriesSet.SqlQuery("select * from dbo.fn_GetCategories(#month)", m).ToList();
}

How to transfer object value to modal class using ASP.Net MVC?

I'm having a hard time passing the value of an object to a model.
I wanted to pass the data from this obj to the model class
SingleTransactResponse obj = JsonConvert.DeserializeObject<SingleTransactResponse>(await response.Content.ReadAsStringAsync());
SaveTransaction(JsonConvert.SerializeObject(obj));
I used this function to get the data from the model and save it to the database
PayoutEntities payoutdb = new PayoutEntities();
public String SaveTransaction(payout_transaction model)
{
payoutdb.payout_transaction.Add(model);
payoutdb.SaveChanges();
return "Success";
}
SingleTransactResponse Class
public class SingleTransactResponse {
public String senderRefId { get; set; }
public String tranRequestDate { get; set; }
public String particulars { get; set; }
public List<Beneficiary> beneficiary { get; set; }
}
Beneficiary Class
public class Beneficiary
{
public String accountNumber { get; set; }
public String name { get; set; }
public List<Address> address { get; set; }
}
Address Class
public class Address
{
public String line1 { get; set; }
public String line2 { get; set; }
public String city { get; set; }
public String province { get; set; }
public String zipCode { get; set; }
public String country { get; set; }
}
payout_transaction class
public partial class payout_transaction
{
public string transid { get; set; }
public string batchid { get; set; }
public string senderRefId { get; set; }
public string requestDate { get; set; }
public string benefName { get; set; }
public string benefacctno { get; set; }
public string status { get; set; }
public string errdesc { get; set; }
public string transaction_fee { get; set; }
}
I'm just having a hard time converting the obj to the model. I've tried JsonConvert.SerializeObject(obj) but it only converts it to string. Is there any possible way to do this or any work around to solve this problem?
you can do like this
var payoutModel = new payout_transaction
{
senderRefId = obj.senderRefId,
requestDate = obj.tranRequestDate,
.... other properties
}
SaveTransaction(payoutModel);

mvc json to object value missing

I just converted json to c# class using json2csharp.com. Then trying to pass that json from view to my controller but problem is only "create_time" object value is garbing successfully no any other value is able to grab. Also please check my debug picture to get better idea. What mistake it can be?
Json i am passing from view:
{"id":"WH-0G571461Y8752214W-8RU19841BY148894W","create_time":"2017-02-27T23:14:14Z","resource_type":"invoices","event_type":"INVOICING.INVOICE.CREATED","summary":"An invoice has been created","resource":{"id":"INV2-3RK5-HZV6-35UP-3LLU","number":"8035","template_id":"TEMP-6MT19746YC041742U","status":"DRAFT","merchant_info":{"email":"ppaas_default#paypal.com","first_name":"Dennis","last_name":"Doctor","business_name":"Medical Professionals, LLC","phone":{"country_code":"001","national_number":"5032141716"},"address":{"line1":"1234 Main St.","city":"Portland","state":"OR","postal_code":"97217","country_code":"US"}},"billing_info":[{"email":"example#example.com"}],"shipping_info":{"first_name":"Sally","last_name":"Patient","business_name":"Not applicable","phone":{"country_code":"001","national_number":"5039871234"},"address":{"line1":"1234 Broad St.","city":"Portland","state":"OR","postal_code":"97216","country_code":"US"}},"items":[{"name":"Sutures","quantity":100,"unit_price":{"currency":"USD","value":"5.00"}}],"invoice_date":"2017-02-27 PDT","payment_term":{"term_type":"NET_45","due_date":"2017-04-13 PDT"},"tax_calculated_after_discount":false,"tax_inclusive":false,"note":"Medical Invoice 27 Feb, 2017","total_amount":{"currency":"USD","value":"500.00"},"metadata":{"created_date":"2017-02-27 14:42:03 PDT"},"allow_tip":false,"links":[{"rel":"self","href":"https://api.paypal.com/v1/invoicing/invoices/INV2-3RK5-HZV6-35UP-3LLU","method":"GET"},{"rel":"send","href":"https://api.paypal.com/v1/invoicing/invoices/INV2-3RK5-HZV6-35UP-3LLU/send","method":"POST"},{"rel":"update","href":"https://api.paypal.com/v1/invoicing/invoices/INV2-3RK5-HZV6-35UP-3LLU/update","method":"PUT"},{"rel":"delete","href":"https://api.paypal.com/v1/invoicing/invoices/INV2-3RK5-HZV6-35UP-3LLU","method":"DELETE"}]},"links":[{"href":"https://api.paypal.com/v1/notifications/webhooks-events/WH-0G571461Y8752214W-8RU19841BY148894W","rel":"self","method":"GET","encType":"application/json"},{"href":"https://api.paypal.com/v1/notifications/webhooks-events/WH-0G571461Y8752214W-8RU19841BY148894W/resend","rel":"resend","method":"POST","encType":"application/json"}],"event_version":"1.0"}
Custom ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebApplication2.WebhookModels.paypal
{
public class Phone
{
public string country_code { get; set; }
public string national_number { get; set; }
}
public class Address
{
public string line1 { get; set; }
public string city { get; set; }
public string state { get; set; }
public string postal_code { get; set; }
public string country_code { get; set; }
}
public class MerchantInfo
{
public string email { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string business_name { get; set; }
public Phone phone { get; set; }
public Address address { get; set; }
}
public class BillingInfo
{
public string email { get; set; }
}
public class Phone2
{
public string country_code { get; set; }
public string national_number { get; set; }
}
public class Address2
{
public string line1 { get; set; }
public string city { get; set; }
public string state { get; set; }
public string postal_code { get; set; }
public string country_code { get; set; }
}
public class ShippingInfo
{
public string first_name { get; set; }
public string last_name { get; set; }
public string business_name { get; set; }
public Phone2 phone { get; set; }
public Address2 address { get; set; }
}
public class UnitPrice
{
public string currency { get; set; }
public string value { get; set; }
}
public class Item
{
public string name { get; set; }
public int quantity { get; set; }
public UnitPrice unit_price { get; set; }
}
public class PaymentTerm
{
public string term_type { get; set; }
public string due_date { get; set; }
}
public class TotalAmount
{
public string currency { get; set; }
public string value { get; set; }
}
public class Metadata
{
public string created_date { get; set; }
}
public class Link
{
public string rel { get; set; }
public string href { get; set; }
public string method { get; set; }
}
public class Resource
{
public string id { get; set; }
public string number { get; set; }
public string template_id { get; set; }
public string status { get; set; }
public MerchantInfo merchant_info { get; set; }
public List<BillingInfo> billing_info { get; set; }
public ShippingInfo shipping_info { get; set; }
public List<Item> items { get; set; }
public string invoice_date { get; set; }
public PaymentTerm payment_term { get; set; }
public bool tax_calculated_after_discount { get; set; }
public bool tax_inclusive { get; set; }
public string note { get; set; }
public TotalAmount total_amount { get; set; }
public Metadata metadata { get; set; }
public bool allow_tip { get; set; }
public List<Link> links { get; set; }
}
public class Link2
{
public string href { get; set; }
public string rel { get; set; }
public string method { get; set; }
public string encType { get; set; }
}
public class RootObject
{
public string id { get; set; }
public DateTime create_time { get; set; }
public string resource_type { get; set; }
public string event_type { get; set; }
public string summary { get; set; }
public Resource resource { get; set; }
public List<Link2> links { get; set; }
public string event_version { get; set; }
}
}
Controller:
[HttpPost]
public ActionResult InvoicePaid(RootObject rootObject)
{
using (var ctx = new db_someEntities())
{
}
return Json("ok");
}
I'll assume you're on dotnet core (maybe on a migrated project?) because the code you're posting doesn't have any issues on previous versions of asp.net mvc.
If that's the case, it turns out that on dotnet core the model binding behaviour has changed a little compared to previous versions.
If you want the solution quickly just decorate the parameter of your POST action with [FromBody] attribute. It should work.
[HttpPost]
public ActionResult InvoicePaid([FromBody]RootObject rootObject)
{
using (var ctx = new db_someEntities())
{
}
return Json("ok");
}
The story is a little longer though, and very interesting by the way. If you want the details, I've not found any better resource than this post from Andrew Lock.
UPDATE
I can confirm that if you add the [FromBody] on the action, (I've tested using a bare new asp.net core 2. web app project) it binds the model correctly.
Please let me know if you want me to provide the sources I've used so you can troubleshot from there.
Hope this helps!
Most probably the data being sent it not formatted properly
From comments it was indicated that the data was being sent like
$.post(hookUrl, { testJson: testJson }).done(function (data) { console.log(data); });
consider formatting the data and including the content type
var data = JSON.stringify(testJson); //replace content with your JSObject
$.post(hookUrl, data, null, "application/json")
.done(function (data) { console.log(data); });
Or using the longer syntax
var data = JSON.stringify(testJson); //replace content with your JSObject
$.ajax({
type: "POST",
url: hookUrl,
data: data,
dataType: "application/json",
success: function (data) { console.log(data); }
});
You need to use [FromBody], so MVC knows where to look for the data.
[HttpPost]
public ActionResult InvoicePaid([FromBody]RootObject rootObject)

Missing type map configuration or unsupported mapping, one to one relationship

I have relationship one to one
public class Book
{
public int BookId { get; set; }
public string Name { get; set; }
public string Annotation { get; set; }
public virtual File File { get; set; }
public int? SeriesId { get; set; }
public DateTime UploadDate { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public virtual ICollection<Author> Authors { get; set; }
public virtual ICollection<Genre> Genres { get; set; }
public virtual ICollection<Mark> Marks { get; set; }
public Book()
{
Comments = new List<Comment>();
Authors = new List<Author>();
Genres = new List<Genre>();
}
}
public class File
{
[Key,ForeignKey("Book")]
public int BookId { get; set; }
public string FileName { get; set; }
public string ContentType { get; set; }
public byte[] Content { get; set; }
public virtual Book Book { get; set; }
}
And I want to transfer data to classes:
public class BookDO
{
public int BookId { get; set; }
public string Name { get; set; }
public string Annotation { get; set; }
public virtual FileDO File { get; set; }
}
public class FileDO
{
public int BookId { get; set; }
public string FileName { get; set; }
public string ContentType { get; set; }
public byte[] Content { get; set; }
public virtual BookDO Book { get; set; }
}
in such way:
var books = Database.Books.GetAll().ToList();
Mapper.Initialize(cf => cf.CreateMap<Book, BookDO>());
return Mapper.Map<List<Book>, List<BookDO>>(books);
but i'm getting Missing type map configuration or unsupported mapping.
Mapping types:
File -> FileDO
Domain.File -> BusinessLogic.Data_Objects.FileDO
Maybe i need to initialize one more mapper to map File to FileDO or modify existing mapper configuration? help me please.
Yes, you also need to create a map for File -> FileDo. This map must be configured for the same mapper as used for Book -> BookDo.
It is good practice to wrap your mapping configuration into an AutoMapper.Profile:
using AutoMapper;
public class BookMappingProfile: Profile {
public BookMappingProfile() {
CreateMap<Book, BookDo>();
CreateMap<File, FileDo>();
}
}
And then initialize the mapper with these profiles:
Mapper.Initialize(cfg => {
cfg.AddProfile<BookMappingProfile>();
cfg.AddProfile<MyOtherProfile>();
});

Resources