As I'm having a single DTO, we use DTOs for GET, PUT and POST http method in our Web API.
To make simple we have ActivityDO:
public ActivityDTO
{
public int Id;
public string Name;
public string CategoryName;
public DateTime DateCreated;
public DateTime DateModified;
}
The challenge is when you only have a single DTO for handling multiple conditions i.e. post/get/put method, the mapping as follow:
private MapperConfiguration configuration = new MapperConfiguration(cfg => {
cfg.CreateMap<ActivityDTO, Activity>()
.ForMember(dst => dst.UserId, opt => opt.MapFrom(src => HttpContext.Current.User.Identity.GetUserId()))
.ForMember(dst => dst.CategoryId, opt => opt.MapFrom(src => GetCategoryId(HttpContext.Current.User.Identity.GetUserId(), src.CategoryName)))
.ForMember(dst => dst.DateCreated, opt => opt.MapFrom(src => DateTime.UtcNow))
.ForMember(dst => dst.DateModified, opt => opt.MapFrom(src => DateTime.UtcNow));
});
I want to IGNORE the mapping for DateCreated if we do the update and we can do the condition if the id <= 0, the rest is allowed to mapping for DateCreated.
Is this possible? Would rather to have a seperate DTOs between GET/POST (Add) VS PUT (Update)? Is there any better solution to handle this DateCreated VS DateModified thingy?
I'm appreciated your feedback/comment.
This is the way to add conditions.
Is that what you are looking for?
private MapperConfiguration configuration = new MapperConfiguration(cfg => {
cfg.CreateMap<ActivityDTO, Activity>()
.ForMember(dst => dst.UserId, opt => opt.MapFrom(src => HttpContext.Current.User.Identity.GetUserId()))
.ForMember(dst => dst.CategoryId, opt => opt.MapFrom(src => GetCategoryId(HttpContext.Current.User.Identity.GetUserId(), src.CategoryName)))
.ForMember(dst => dst.DateCreated, opt => opt.MapFrom(src => src.Condition(src.DateCreated != null)))
.ForMember(dst => dst.DateModified, opt => opt.MapFrom(src => DateTime.UtcNow));
});
I used src.DateCreated != null but you can specify any condition using the src.Condition() and the variable will only be mapped when the condition is met.
Also
You can use AutoMapper's PreCondition
var configuration = new MapperConfiguration(cfg => {
cfg.CreateMap<Foo,Bar>()
.ForMember(dest => dest.baz, opt => {
opt.PreCondition(src => (src.baz >= 0));
opt.MapFrom(src => {
});
});
});
Related
I receive the language through endpoint and I want to use the automap to return the same language that I received from endpoint
How can I do something like that knowing I'm using Dependency injection with IMapper
[HttpGet("Products")] public async Task<IActionResult> Get(int SectionId ,bool IsSection, [FromHeader] string lang){....}
public class MappingProfile : Profile
{
public MappingProfile( string lang )
{
CreateMap<Product, ProductDTO>()
.ForMember(dest => dest.Name, (lang== "ar") ? src => src.MapFrom(src => src.NameAr) : src => src.MapFrom(src => src.NameEn))
.ForMember(dest => dest.CountryName, (lang == "ar") ? src => src.MapFrom(src => src.Country.NameAr) : src => src.MapFrom(src => src.Country.NameEn))
.ForMember(dest => dest.HaveSection, src => src.MapFrom(src => src.Id != 0))
.ForMember(dest => dest.ByPiece, src => src.MapFrom(src => src.ProductUnit == Units.number))
.ReverseMap();
}
}
i need to do that but with automapper
List<ProductDTO> productDTOs = new();
if (products !=null)
{
foreach (var product in products)
{
var productDTO = new ProductDTO();
productDTO.Id = product.Id;
productDTO.Name = (lang == "ar") ? product.NameAr : product.NameEn;
productDTO.Price = product.Price;
productDTO.HasOffer = product.HasOffer;
productDTO.OfferPrice = product.OfferPrice;
productDTO.CountryName = (lang == "ar") ? product.Country.NameAr : product.Country.NameEn;
productDTO.ByPiece = (product.ProductUnit == Units.number) ? true : false;
productDTOs.Add(productDTO);
}
}
Personally, I think you should not put domain login inside mappings, but this will become your profile if you want:
public MappingProfile( string lang )
{
CreateMap<Product, ProductDTO>()
.ForMember(dest => dest.Name, src => src.MapFrom(x => (lang == "ar") ? x.NameAr : x.NameEn))
.ForMember(dest => dest.HaveSection, src => src.MapFrom(src => src.Id != 0))
.ForMember(dest => dest.ByPiece, src => src.MapFrom(src => src.ProductUnit == Units.number))
.ReverseMap();
}
Now you need to create a mapper with this profile.
IMapper mapper = new MapperConfiguration(x => x.AddProfile(new MappingProfle("ar"))).CreateMapper();
Now use this to map your object :)
I am using Kendo Grid. The problem I am facing is that I am not able to filter the datetime by selecting any option from filter.
Here is my code:
#(Html.Kendo()
.Grid<IssueViewModel>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(c => c.IssuePostedAt).Format("{0:dd.MM.yyyy hh:mm:ss}").Filterable(filterable => filterable.UI("orderDateFilter")).Title("Posted")
.ClientTemplate("#:kendo.toString(data.IssuePostedAt, \"dd.MM.yyyy hh:mm:ss\")#");
})
.Sortable()
.Pageable(pageable => pageable
.Refresh(true)
.ButtonCount(5))
.Events(events => events.DataBound("onGridDataBound"))
.Filterable(filterable => filterable
.Enabled(true)
.Extra(false)
.Operators(operators => operators.ForString(str => str.Clear().Contains("Содержит")))
)
.DataSource(dataSource => dataSource
.WebApi()
.Model(model => model.Id(i => i.Issue.Id))
.Sort(sort => sort.Add(i => i.IssuePostedAt).Descending())
.Read(read => read.Url("/issue/gridData"))
.PageSize(20)
)
JavaScript:
function orderDateFilter(element) {
element.kendoDateTimePicker({
format: "dd.MM.yyyy hh:mm:ss",
timeFormat: "hh:mm:ss"
});
}
This is code in the controller:
[HttpGet]
[Route("gridData")]
public async Task<ActionResult> GridData([ModelBinder(typeof(DataSourceRequestModelBinder))] DataSourceRequest request)
{
var filterByUser = HttpContext.GetReferrerParam("name");
var gridData = await IssuesRepository.Instance.Get(filterByUser); // get all data from DB
var results = gridData.ToDataSourceResult(request);
return Json(results);
}
DateTime filtering doesn't work at all. gridData.ToDataSourceResult(request); always return empty result.
I will be thankful if anybody could help me out in solving my issue. Thanks in advance.
I'm trying to connect my asp .net identity classes to custom sql database. I have defined the mapping in the OnModelBuilder method as follows:
var user = modelBuilder.Entity<IdentityUser>().HasKey(u => u.Id).ToTable("User");
user.Property(iu => iu.Id).HasColumnName("Id");
user.Property(iu => iu.UserName).HasColumnName("UserName");
user.Property(iu => iu.PasswordHash).HasColumnName("PasswordHash");
user.Property(iu => iu.SecurityStamp).HasColumnName("SecurityStamp");
user.Property(iu => iu.EmailConfirmed).HasColumnName("EmailConfirmed");
user.Property(iu => iu.LockoutEnabled).HasColumnName("LockoutEnabled");
user.Property(iu => iu.LockoutEndDateUtc).HasColumnName("LockoutEndDateUtc");
user.Property(iu => iu.PhoneNumber).HasColumnName("PhoneNumber");
user.Property(iu => iu.PhoneNumberConfirmed).HasColumnName("PhoneNumberConfirmed");
user.Property(iu => iu.TwoFactorEnabled).HasColumnName("TwoFactorEnabled");
user.Property(au => au.AccessFailedCount).HasColumnName("AccessFailedCount");
user.Property(au => au.TwoFactorEnabled).HasColumnName("TwoFactorEnabled");
//--?--
user.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId);
user.HasMany(u => u.Claims).WithRequired().HasForeignKey(ur => ur.UserId);
user.HasMany(u => u.Logins).WithRequired().HasForeignKey(ur => ur.UserId);
user.Property(u => u.UserName).IsRequired();
//--
var applicationUser = modelBuilder.Entity<ApplicationUser>().HasKey(au => au.Id).ToTable("User");
applicationUser.Property(au => au.Id).HasColumnName("Id");
applicationUser.Property(au => au.UserName).HasColumnName("UserName");
applicationUser.Property(au => au.Email).HasColumnName("Email");
applicationUser.Property(au => au.PasswordHash).HasColumnName("PasswordHash");
applicationUser.Property(au => au.SecurityStamp).HasColumnName("SecurityStamp");
applicationUser.Property(au => au.EmailConfirmed).HasColumnName("EmailConfirmed");
applicationUser.Property(au => au.ActivationToken).HasColumnName("ActivationToken");
applicationUser.Property(au => au.FirstName).HasColumnName("FirstName");
applicationUser.Property(au => au.LastName).HasColumnName("LastName");
applicationUser.Property(au => au.LockoutEnabled).HasColumnName("LockoutEnabled");
applicationUser.Property(au => au.LockoutEndDateUtc).HasColumnName("LockoutEndDateUtc");
applicationUser.Property(au => au.PhoneNumber).HasColumnName("PhoneNumber");
applicationUser.Property(au => au.PhoneNumberConfirmed).HasColumnName("PhoneNumberConfirmed");
applicationUser.Property(au => au.AccessFailedCount).HasColumnName("AccessFailedCount");
applicationUser.Property(au => au.Discriminator1).HasColumnName("Discriminator1");
applicationUser.Property(au => au.TwoFactorEnabled).HasColumnName("TwoFactorEnabled");
applicationUser.Property(au => au.IdentityRole_Id).HasColumnName("IdentityRole_Id");
//set the primary key for this class. Use .HasMaxLength(40) to specify max length on property
var role = modelBuilder.Entity<IdentityRole>().HasKey(ir => ir.Id).ToTable("Role");
role.Property(ir => ir.Id).HasColumnName("Id");
role.Property(ir => ir.Name).HasColumnName("Name");
var applicationRole = modelBuilder.Entity<ApplicationRole>().HasKey(ar => ar.Id).ToTable("Role");
applicationRole.Property(ir => ir.Id).HasColumnName("Id");
applicationRole.Property(ir => ir.Name).HasColumnName("Name");
//applicationRole.Property(ir => ir.Description).HasColumnName("Description");
var userRole = modelBuilder.Entity<IdentityUserRole>().HasKey(iur => new{iur.UserId, iur.RoleId}).ToTable("UserRole");
userRole.Property(ur => ur.RoleId).HasColumnName("RoleId");
userRole.Property(ur => ur.UserId).HasColumnName("UserId");
var claim = modelBuilder.Entity<IdentityUserClaim>().HasKey(iuc => iuc.Id).ToTable("UserClaim");
claim.Property(iuc => iuc.Id).HasColumnName("Id");
claim.Property(iuc => iuc.ClaimType).HasColumnName("ClaimType");
claim.Property(iuc => iuc.ClaimValue).HasColumnName("ClaimValue");
claim.Property(iuc => iuc.UserId).HasColumnName("UserId");
var login = modelBuilder.Entity<IdentityUserLogin>().HasKey(iul => new { iul.UserId, iul.LoginProvider, iul.ProviderKey }).ToTable("UserLogin");
login.Property(iul => iul.UserId).HasColumnName("UserId");
login.Property(iul => iul.LoginProvider).HasColumnName("LoginProvider");
login.Property(iul => iul.ProviderKey).HasColumnName("ProviderKey");
However when I run, its giving error saying
Invalid column name 'Discriminator'.
Invalid column name 'IdentityRole_Id'.
Invalid column name 'Discriminator'.
Invalid column name 'Discriminator'.
If I understand correctly, its looking for those column names inside my custom User table, even though they are not defined in IdentityUser or my derived ApplicationUser.
I'm not sure where the error lies, my OnModelCreating method?
This is not an ASP.NET identity issue. You are mapping both, base class and derived class,IdentityUser and ApplicationUser respectively to the same table "User", this is known as "table per class hierarchy", so EF adds Descriminator column accordingly.
In this case you should mapp only ApplicationUser class.
The same applies to IdentityRole and ApplicationRole, etc.
I am struggling calling a create action through a WCF service from a kendo ui grid.When the odataservice calls the business logic controller to write the record it passes a null reference....the customer object is populated up until the call to the business logic CreateEntity method. I originally thought this was because of the content type but I am having my doubts now. Accessing the WCF service directly with fiddler successfully creates the record...
Kendo Grid:
Here is the application level Customer_Create action being called by the kendo grid
#(Html.Kendo().Grid<Application.ServiceProxy.CustomerDTO>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(c => c.salesOrganizationID).Width(15).Title("sales org");
columns.Bound(c => c.customerID).Width(20).Groupable(false);
columns.Bound(c => c.name1).Width(25).Title("name");
columns.Bound(c => c.city).Width(15).Title("city");
columns.Bound(c => c.stateCode).Width(10).Title("state");
columns.Bound(c => c.countryCode).Width(15).Title("country");
columns.Bound(c => c.matchcode).Width(25).Title("matchcode");
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(35);
//Add program type here CMI, VMI etc..
//columns.Width(25).Title("program");
})
.ToolBar(toolbar => toolbar.Create())
.Editable(ed => ed.Mode(GridEditMode.PopUp).Window(w => w.Title("Edit Customer Details").Name("editWindow").HtmlAttributes(new { #style = "width:700px;" })))
.Pageable()
.Sortable()
.Groupable()
.Scrollable()
.Filterable()
.HtmlAttributes(new { style = "height:420px;" })
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.ServerOperation(true)
.Events(events => events.Error("error_handler"))
.Model(model => model.Id(c => c.customerID))
.Create(update => update.Action("Customer_Create", "Customer"))
.Read(read => read.Action("Customer_Read", "Customer"))
.Update(update => update.Action("Customer_Update", "Customer"))
.Destroy(update => update.Action("Customer_Delete", "Customer"))
)
)
Here is the application level Customer_Create action being called by the kendo grid
[System.Web.Http.HttpPost]
public ActionResult Customer_Create([DataSourceRequest] DataSourceRequest request, Application.ServiceProxy.CustomerDTO customer)
{
if (customer != null && ModelState.IsValid)
{
var odataService = new Container(new Uri("http://localhost:8089/odata/"));
//odataService.r
odataService.AddToCustomer(customer);
odataService.SaveChanges();
return Json(ModelState.ToDataSourceResult());
}
return View("Index");
}
Here is the CreateEntity method being called through the generated WCF data service.
protected override CustomerDTO CreateEntity(CustomerDTO customerDTO)
{
var customer = new customer()
{
matchcode = customerDTO.matchcode,
salesOrganizationID = customerDTO.salesOrganizationID,
statusID = customerDTO.statusID,
serviceLevelStatusID = customerDTO.serviceLevelStatusID,
mediaIDLogo = customerDTO.mediaIDLogo,
systemID = customerDTO.systemID,
customerExternalSystemID = customerDTO.customerExternalSystemID,
internationalGroup = customerDTO.internationalGroup,
division = customerDTO.division,
corporateID = customerDTO.corporateID,
inventoryManagerID = customerDTO.inventoryManagerID,
dunsNumber = customerDTO.dunsNumber
};
entity.customer.Add(customer);
entity.SaveChanges();
return GetEntityByKey(customer.customerID);
}
I am building an MVC, Entities application with KendoGrids.
I have build this kendoGrid
#(Html.Kendo().Grid<ModelApp.Models.Tickets>()
.Name("ticketgrid")
.Columns(columns =>
{
columns.Bound(p => p.TicketID).Title("ID");
columns.ForeignKey(p => p.CustomerID, (System.Collections.IEnumerable)ViewData["customers"], "CustomerID", "CustomerName").Title("Customer");
columns.ForeignKey(p => p.AreaOfBusinessID, (System.Collections.IEnumerable)ViewData["areaofbusinesses"], "AreaOfBusinessID", "AreaOfBusiness1").Title("AreaOfBusiness");
columns.Bound(p => p.OccurredOn).Title("Occured").Format("{0:yyyy-MM-dd}");
columns.ForeignKey(p => p.SeverityID, (System.Collections.IEnumerable)ViewData["severities"], "SeverityID", "Severity1").Title("Severity");
columns.ForeignKey(p => p.AssigneeID, (System.Collections.IEnumerable)ViewData["assignees"], "AssigneeID", "AssigneeName").Title("Assignee");
columns.ForeignKey(p => p.TicketStatusID, (System.Collections.IEnumerable)ViewData["ticketstatuses"], "TicketStatusID", "TicketStatus1").Title("Status");
columns.Bound(p => p.UserID).Title("User");
columns.Bound(p => p.DateRegistered).Title("Registered").Format("{0:yyyy-MM-dd}");
})
.DataSource(dataSource =>
dataSource
.Ajax()
.Model(model => model.Id(p => p.TicketID))
.Read(read => read.Action("Index","Ticket"))
.Create(create => create.Action("Create", "Ticket"))
.Update(update => update.Action("Edit", "Ticket"))
//.Destroy(destroy => destroy.Action("Delete", "Ticket"))
)
.Pageable()
.Editable(editing => editing.Mode(GridEditMode.InCell))
.ToolBar(toolbar =>
{
toolbar.Create();
toolbar.Save();
})
.Navigatable()
.Selectable()
)
and I am facing 2 problems
1)The TicketID column is an identity column. When I select the Create button it fetches a zero. How can I make the Gid understand that it should not mess with this column and that the database will handle it?
Of course, no insert is being made anyway which takes me to the second question
2)The Edit does not post to database
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit([DataSourceRequest] DataSourceRequest request, IEnumerable<ModelApp.Models.Tickets> models)
{
if (models != null)
{
try
{
foreach (var updatedEntity in models)
{
var itemToUpdate = db.Tickets.Where(p => p.TicketID == updatedEntity.TicketID).FirstOrDefault();
if (itemToUpdate != null)
{
itemToUpdate.CustomerID = updatedEntity.CustomerID;
itemToUpdate.AreaOfBusinessID = updatedEntity.AreaOfBusinessID;
itemToUpdate.AssigneeID = updatedEntity.AssigneeID;
itemToUpdate.OccurredOn = updatedEntity.OccurredOn;
itemToUpdate.SeverityID = updatedEntity.SeverityID;
itemToUpdate.DateRegistered = updatedEntity.DateRegistered;
itemToUpdate.UserID = updatedEntity.UserID;
db.SaveChanges();
ModelState.Clear();
}
}
}
catch (Exception e)
{
db.add_exception_log(e.Message, "UPDATE RATES");
}
}
return Json(ModelState.ToDataSourceResult());
}
because models is null. Any clues why?
Thanx in advance
1) You should make the field non-editable inside of the Model configurator of the dataSource
model=>{
model.Fiedl(p=>p.TicketID).Editable(false);
}
2) You are not using batch editing to expect collection - change the signate to expect single record
public ActionResult Edit([DataSourceRequest] DataSourceRequest request, ModelApp.Models.Tickets model)