簡體   English   中英

具有資源 model PUT 的 WebAPI 項目中 System.Type 的序列化/反序列化

[英]Serialization/Deserialization of System.Type in WebAPI Project with resource model PUT

我正在嘗試使用我的 EFCore 實體 class 上的自動映射資源 model 通過 WebAPI 修改數據。 我已經設法讓 GET、GET(by id)、DELETE 和 POST 使用這種方法正常工作。

現在我面臨的問題是我在嘗試使用此資源執行 PUT 時收到的“System.Type”錯誤消息的 Automapper 序列化和反序列化 我設法將這個錯誤縮小到我的 ID 字段,這是 SQL 服務器中的主鍵身份字段。 在資源 model 中省略此 ID 可使 PUT 工作。

但是,我需要其他GETS 和DELETE 的ID 字段,因此不能從資源model 中省略它。

這是我的實體:

  [Table("BlazorWebApiDemo")]
    public partial class BlazorEntity
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        [Column("First Name")]
        [StringLength(50)]
        public string FirstName { get; set; } = string.Empty;
        [Column("Last Name")]
        [StringLength(50)]
        public string LastName { get; set; } = string.Empty;
        [StringLength(50)]
        public string Address { get; set; } = string.Empty;
    }

這是我的 API 資源 Model:

    public class BlazorEntityModel
    {    
        public int Id { get; set; } // Commenting this out makes PUT work.
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Address { get; set; }
    }

自動映射器簡介:

    public class BlazorEntityProfile : Profile
    {
        public BlazorEntityProfile()
        {
            this.CreateMap<BlazorEntity, BlazorEntityModel>()

                .ForMember(dest => dest.FirstName, opt => opt.NullSubstitute(""))
                .ForMember(dest => dest.LastName, opt => opt.NullSubstitute(""))
                .ForMember(dest => dest.Address, opt => opt.NullSubstitute(""))
                //.ForMember(src => src.Id, opts => opts.Ignore())
                .ReverseMap();
        }
    }

Controller PUT 方法:

        [HttpPut("{id:int}")]
        public async Task<ActionResult<BlazorEntityModel>> UpdateBlazorItem(int id, BlazorEntityModel blazorEntityModel)
        {
            try
            {
                var oldBlazorEntity = await blazorRepository.GetBlazorById(id);
                if (oldBlazorEntity == null) return NotFound($"LetItem with the ID: {id} not found");

                mapper.Map(blazorEntityModel, oldBlazorEntity);

                if(await blazorRepository.SaveChangesAsync())
                {
                    return mapper.Map<BlazorEntityModel>(oldBlazorEntity);
                }

            }
            catch (Exception e)
            {
                return StatusCode(StatusCodes.Status500InternalServerError,
                                  e);
            }

            return BadRequest(); //Error getting caught here.
        }

這是我在 swagger 中得到的錯誤截圖: 在此處輸入圖像描述

有任何想法嗎?

代碼看起來不錯,這個問題可能出在客戶端; 即在調用/發送backend API時如何Front end/Client對其進行序列化。

仔細檢查您正在使用contentType:"application/json"並在發送時使用JSON.stringify方法將其轉換為 JSON 字符串。

這里這里類似的問題


更新 2:在您的 blazor 實體中嘗試添加key attribute

public class BlazorEntityModel
{    
    [Key]  // add this to force it to recognize it as key
    public int Id { get; set; } // Commenting this out makes PUT work.
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }
}

更新 3:配置/覆蓋序列化處理

您可以嘗試在global.asax中添加以下內容嗎

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;  
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

如果這可行,請告訴我我們可能必須轉移到 DTO 或 VM,以便我們跟蹤和循環/循環引用。

一種處理方法是使用 inheritance 的兩個類。

public class MyObject {
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public string Address { get; set; }
}

public class CreatedVersionOfMyObject : MyObject  {
    public int Id { get; set; }
}

然后您的 controller 可以輕松地使用這些實體公開多個端點

    [Route("objects")]
    public class MyObjectControLler : Controller
    {
        [Route("{id}")]
        [HttpGet]
        [ProducesResponseType((int)HttpStatusCode.NotFound)]
        [ProducesResponseType((int)HttpStatusCode.InternalServerError)]
        [ProducesResponseType(typeof(CreatedVersionOfMyObject), (int)HttpStatusCode.OK)]
        public Task<IActionResult> GetByIdAsync(Guid id)
        {
            // Do what you have to do to retrieve the object by id
        }

        [Route("{id}")]
        [HttpDelete]
        [ProducesResponseType((int)HttpStatusCode.NotFound)]
        [ProducesResponseType((int)HttpStatusCode.InternalServerError)]
        [ProducesResponseType((int)HttpStatusCode.NoContent)]
        public Task<IActionResult> DeleteByidAsync(Guid id)
        {
            // Do what you have to do to delete the object by id
        }

        [Route("{id}")]
        [HttpPut]
        [ProducesResponseType((int)HttpStatusCode.NotFound)]
        [ProducesResponseType((int)HttpStatusCode.InternalServerError)]
        [ProducesResponseType(typeof(MyObject), (int)HttpStatusCode.OK)]
        public Task<IActionResult> PutAsync([FromRoute]Guid id, [FromBody]MyObject theModifiedObject)
        {
            // Do what you have to do to retrieve the object by id
        }

        [Route("")]
        [HttpPost]
        [ProducesResponseType((int)HttpStatusCode.NotFound)]
        [ProducesResponseType((int)HttpStatusCode.InternalServerError)]
        [ProducesResponseType(typeof(CreatedVersionOfMyObject), (int)HttpStatusCode.Created)]
        public Task<IActionResult> PostAsync(MyObject theModifiedObject)
        {
            // Do what you have to do to create the object and return the version with the id
        }
    }

最后,關於映射,您也可以輕松處理(參見原始文檔https://docs.automapper.org/en/stable/Mapping-inheritance.html

CreateMap<BaseEntity, BaseDto>()
   .ForMember(dest => dest.SomeMember, opt => opt.MapFrom(src => src.OtherMember));

CreateMap<DerivedEntity, DerivedDto>()
    .IncludeBase<BaseEntity, BaseDto>();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM