У меня очень странная проблема. Я создаю внешний интерфейс ASP.Net Core и API-интерфейс ASP.Net Core. API задней панели использует ядро Entity Framework для сохранения.Попытка сопоставить один класс домена для просмотра класса модели пропускает свойства
Я использую класс модели представления для публикации данных с веб-сайта в API, затем я использую AutoMapper для сопоставления из класса модели представления класса сущности, чтобы передать его в репозиторий на основе EF. Это работало для двух других отношений модели представления/сущности в этом проекте, связанных с другими таблицами базы данных.
Однако я добавляю новую таблицу базы данных и связанную с ней модель модели/сущности класса, которая дает мне эту странную проблему.
С помощью этой конкретной связи модели объекта/вида Automapper выходит из строя без ошибок. Он просто пропускает любое свойство, которое не определено в классе сущности, с вопросительным знаком после типа данных (что делает свойство nullable).
Я создал метод ручной сопоставления свойств, один за другим, из класса модели представления в класс сущности, и я вижу ту же проблему, поэтому считаю, что это не проблема AutoMapper.
Вот мой класс сущности;
using System;
using System.Collections.Generic;
namespace API.Models
{
public partial class UserFeaturesEvs
{
public int UserId { get; set; }
public bool Active { get; set; }
public string LoginNickname { get; set; }
public string CarrierLoginName { get; set; }
public string CarrierLoginPassword { get; set; }
public int CarrierId { get; set; }
public int? CarrierLoginId { get; set; }
public string PermitNumber { get; set; }
public string PermitType { get; set; }
public string PermitName { get; set; }
public int? McdPrimaryId { get; set; }
public string Crid { get; set; }
public string CapsId { get; set; }
public bool? IsGovernment { get; set; }
public string CityStateOfPo { get; set; }
public string PoOfAccountZip { get; set; }
public string MasterMid { get; set; }
public string ChildMid { get; set; }
public string IndiciaText { get; set; }
public string LoginId { get; set; }
public string PostageType { get; set; }
public int? SiteId { get; set; }
}
}
И вот мой класс модели просмотра;
using System.ComponentModel.DataAnnotations;
namespace API.ViewModels.EVS
{
public class UserFeaturesEvsViewModel
{
public bool Active { get; set; }
[Display(Name = "User ID")]
public int UserId { get; set; }
[Display(Name = "Carrier ID")]
[Required]
public int CarrierId { get; set; }
[Display(Name = "Site ID")]
public int SiteId { get; set; }
[Display(Name = "Nick Name")]
public string LoginNickname { get; set; }
[Display(Name = "Login Name")]
[Required]
public string CarrierLoginName { get; set; }
[Display(Name = "Password")]
[Required]
public string CarrierLoginPassword { get; set; }
[Display(Name = "Carrier Login ID")]
public int CarrierLoginId { get; set; }
[Display(Name = "MCD Primary ID")]
public int McdPrimaryId { get; set; }
[Display(Name = "Permit Number")]
public string PermitNumber { get; set; }
[Display(Name = "Permit Type")]
public string PermitType { get; set; }
[Required]
[Display(Name = "Permit Name")]
public string PermitName { get; set; }
[Display(Name = "CRID")]
public string Crid { get; set; }
[Display(Name = "CAPS ID")]
public string EvsCapsId { get; set; }
[Display(Name = "Government Permit")]
public bool EvsGovernmentPermit { get; set; }
[Display(Name = "PO of Account - City/State")]
public string EvsCityStateOfPo { get; set; }
[Display(Name = "PO of Account - Zipcode")]
public string EvsPoOfAccountZip { get; set; }
[Display(Name = "Master MID")
public string EvsMasterMid { get; set; }
[Display(Name = "Child ID")]
public string EvsChildMid { get; set; }
[Display(Name = "Indicia Text")]
public string EvsIndiciaText { get; set; }
[Display(Name = "Login ID")]
public string EvsLoginId { get; set; }
[Display(Name = "Postage Type")]
public string PostageType { get; set; }
}
}
Это метод теста, который я создал в классе контроллера API вручную карту из класса вида модели к классу сущностей
private UserFeaturesEvs MapUserFeaturesEvsViewModelToUserFeaturesEvs(UserFeaturesEvsViewModel a_model)
{
try
{
UserFeaturesEvs model = new UserFeaturesEvs();
if (a_model != null)
{
model.SiteId = a_model.SiteId;
model.Active = a_model.Active;
model.UserId = a_model.UserId;
model.CarrierId = a_model.CarrierId;
model.LoginNickname = a_model.LoginNickname;
model.CarrierLoginName = a_model.CarrierLoginName;
model.CarrierLoginPassword = a_model.CarrierLoginPassword;
model.CarrierLoginId = a_model.CarrierLoginId;
model.McdPrimaryId = a_model.McdPrimaryId;
model.PermitNumber = a_model.PermitNumber;
model.PermitType = a_model.PermitType;
model.PermitName = a_model.PermitName;
model.Crid = a_model.Crid;
model.CapsId = a_model.EvsCapsId;
model.IsGovernment = a_model.EvsGovernmentPermit;
model.CityStateOfPo = a_model.EvsCityStateOfPo;
model.PoOfAccountZip = a_model.EvsPoOfAccountZip;
model.MasterMid = a_model.EvsMasterMid;
model.ChildMid = a_model.EvsChildMid;
model.IndiciaText = a_model.EvsIndiciaText;
model.LoginId = a_model.EvsLoginId;
model.PostageType = a_model.PostageType;
}
return model;
}
catch (Exception ex)
{
m_logger.LogError(1, ex, "An exception occurred in the MapUserFeaturesEvsViewModelToUserFeaturesEvs method while trying to map the UserFeaturesEvsViewModel [{VM}] to the UserFeaturesEvs Model.", a_model);
return null;
}
Теперь я могу видеть, что проблема происходит, как я за один шаг в Visual Studio 2015, с помощью метода MapUserFeaturesEvsViewModelToUserFeaturesEvs с использованием F11. Как только я пройду мимо строки if (a_model! = Null), отладка останавливается только на строках для SiteId, CarrierLoginId, McdPrimaryId и EvsGovernmentPermit, пропуская все остальные. И возвращенный объект UserFeaturesEvs имеет только данные в этих 4 полях. Я подтвердил, что объект UserFeaturesEvsViewModel, переданный в метод, имеет данные во всех свойствах.
Свойства класса UserFeatruesEvs, которые являются успешно назначенными данными, являются только теми, у которых есть значения NULL, обозначенные символом? после типа данных, как показано в выдержках свойств из класса UserFeaturesEvs, ниже;
public int? CarrierLoginId { get; set; }
public int? McdPrimaryId { get; set; }
public bool? IsGovernment { get; set; }
public int? SiteId { get; set; }
Класс объекта, UserFeaturesEvs был сгенерирован из существующей таблицы базы данных, используя ..
dotnet ef dbcontext scaffold ...
... команду.
Вышеуказанная команда командной строки также добавляет код ниже к классу DbContext ...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserFeaturesEvs>(entity =>
{
entity.HasKey(e => e.UserId)
.HasName("PK_UserFeatures_EVS");
entity.ToTable("UserFeatures_EVS");
entity.Property(e => e.UserId)
.HasColumnName("UserID")
.ValueGeneratedNever();
entity.Property(e => e.CapsId)
.HasColumnName("CapsID")
.HasColumnType("varchar(50)");
entity.Property(e => e.CarrierId).HasColumnName("CarrierID");
entity.Property(e => e.CarrierLoginId).HasColumnName("CarrierLoginID");
entity.Property(e => e.CarrierLoginName)
.IsRequired()
.HasColumnType("varchar(50)");
entity.Property(e => e.CarrierLoginPassword)
.IsRequired()
.HasColumnType("varchar(50)");
entity.Property(e => e.ChildMid)
.HasColumnName("ChildMID")
.HasColumnType("varchar(50)");
entity.Property(e => e.CityStateOfPo)
.HasColumnName("CityStateOfPO")
.HasColumnType("varchar(50)");
entity.Property(e => e.Crid)
.HasColumnName("CRID")
.HasColumnType("varchar(50)");
entity.Property(e => e.IndiciaText).HasColumnType("varchar(50)");
entity.Property(e => e.LoginId).HasColumnType("varchar(50)");
entity.Property(e => e.LoginNickname).HasColumnType("varchar(50)");
entity.Property(e => e.MasterMid)
.HasColumnName("MasterMID")
.HasColumnType("varchar(50)");
entity.Property(e => e.McdPrimaryId).HasColumnName("MCDPrimaryID");
entity.Property(e => e.PermitName).HasColumnType("varchar(50)");
entity.Property(e => e.PermitNumber).HasColumnType("varchar(50)");
entity.Property(e => e.PermitType).HasColumnType("varchar(50)");
entity.Property(e => e.PoOfAccountZip)
.HasColumnName("PoOfAccountZip")
.HasColumnType("varchar(50)");
entity.Property(e => e.PostageType).HasColumnType("varchar(50)");
entity.Property(e => e.SiteId).HasColumnName("SiteID");
});
}
public virtual DbSet<UserFeaturesEvs> UserFeaturesEvs { get; set; }
.
.
.
Я не могу увидеть что-нибудь, что является причиной этой проблемы и, как я уже говорил ранее, я использовал этот такой же метод класса класса/вида класса объектов с двумя другими таблицами базы данных без проблем.
Весь код, о котором я говорю выше, находится в проекте API ASP.Net Core.
Я попытался удалить?из объявлений типа данных в свойствах класса UserFeaturesEvs, и когда я это сделал, отладчик просто пропустил все назначения свойств и вернул все нулевые данные из метода сопоставления.
EDIT: Дальнейший анализ показывает, что проблема связана с UserFeaturesEvsViewModel. Я могу статически присваивать значения экземпляру объекта UserFeaturesEvs в методе MapUserFeaturesEvsViewModelToUserFeaturesEvs и он не пропускает присваивания свойств, которые не имеют? после их объявления типа данных. Поскольку это API, UserFeatruesEvsViewModel исходит из метода Create в контроллере API.
[HttpPost("")]
public IActionResult Create([FromBody]UserFeaturesEvsViewModel a_vm)
{
try
{
//Test assignment of vm to local variables
int SiteId = a_vm.SiteId; // This gets skipped
bool Active = a_vm.Active; // This gets skipped
int UserId = a_vm.UserId; // This gets skipped
int CarrierId = a_vm.CarrierId; // This gets skipped
string LoginNickname = a_vm.LoginNickname; // This gets skipped
if (ModelState.IsValid)
{
UserFeaturesEvs model = MapUserFeaturesEvsViewModelToUserFeaturesEvs(a_vm);
//UserFeaturesEvs model = Mapper.Map<UserFeaturesEvs>(a_vm);
.
.
.
Это образец JSON я отправляю в качестве приложения/JSON к контроллеру API из приложения Google Chrome Почтальон
{
"active": true,
"userId": 1,
"carrierId": 1,
"siteId": 1,
"loginNickname": "testNickname",
"carrierLoginName": "testLoginName",
"carrierLoginPassword": "testLoginPassword",
"carrierLoginId": 0,
"mcdPrimaryId": 0,
"permitNumber": "123456",
"permitType": "",
"permitName": "UserID1-123456",
"crid": "11",
"evsCapsId": "112233",
"evsGovernmentPermit": false,
"evsCityStateOfPo": "Somewhere, NY",
"evsPoOfAccountZip": "90210",
"evsMasterMid": "654321",
"evsChildMid": "654322",
"evsIndiciaText": "Test",
"evsLoginId": "",
"postageType": "P"
}
Когда я осматриваю a_vm в отладчике, я вижу данные, которые я отправляю, и он, похоже, находится в структуре класса UserVeaturesEvsViewModel. Однако, когда я пытаюсь просто присваивать свойства переменной a_vm локальным переменным в начале метода Create, как показано выше, эти назначения также просто пропускаются отладчиком (даже если я поставил точку останова на назначения) как это происходит в методе MapUserFeaturesEvsViewModelToUserFeaturesEvs.
В других контроллерах API, где у меня нет этой проблемы, я передаю объект a_vm в свой репозиторий Entity Framework. Например, код, приведенный ниже в другом контроллере этого же API, отлично работает.
[HttpPost("")]
public IActionResult Create([FromBody]MerSettingsViewModel a_vm)
{
try
{
if (ModelState.IsValid)
{
MailEventsRetrieverSettings settings = Mapper.Map<MailEventsRetrieverSettings>(a_vm);
Task<MailEventsRetrieverSettings> task = m_cdiMppsRepository.AddMailEventsRetrieverSettingsAsync(settings);
MailEventsRetrieverSettings response = task.Result;
if (response != null)
{
return Ok(response);
}
}
return BadRequest(ModelState);
}
catch (Exception ex)
{
m_logger.LogError(1, ex, "Could not create new MailEventsRetrieverSettings record for the following object [{@VM}] to the database", a_vm);
return Json(new { Message = ex.Message });
}
}
Таким образом, проблема, кажется, идет от того, как объект автоматически десериализованное из тела HttpPost в методе Create. Несмотря на то, что в отладчике я вижу значения в a_vm и, похоже, он структурирован правильно, я не могу прямо присваивать значения этих свойств другому свойству класса или локальной переменной, если свойство класса или локальная переменная не определены как обнуляемый.
Любые идеи?
Значит, он работает только для свойств с нулевым значением? – CodingYoshi
Они должны удалить всю вашу папку bin и выполнить перестройку и повторить попытку. – CodingYoshi
Почему ваш класс модели частично? Не могли бы вы показать другие части этого класса? –