发布关系数据时无法反序列化当前的JSON对象

时间:2017-12-20 08:14:03

标签: json angular serialization asp.net-web-api2

好的,有很多问题和答案,如果你知道这个问题的确切重复,请指出我,但我太愚蠢了解如何让它工作。

我想在工作中添加一名工人,一切都很好,直到到达ModelState。以下是我正在做的步骤。

  1. 填写表格
  2. 我提交表单和控制台断点。

    Name = "test", Description = "test", 
               worker = {Id: 21, FirstName: "Will", LastName: "Smith", Job: null}
    
  3. 控制台中的角度服务

    jobs = {Name: "test", Description: "test", worker: {…}}
    
    Not sure why the dots in the brackets. 
    
  4. 达到API方法并失败了模型状态。

    if (!ModelState.IsValid)
    {
         return BadRequest(ModelState);
    }
    
  5. 在浏览器控制台中,我得到:

    Message:"The request is invalid."
    
    ModelState:job.worker.Id:["Cannot deserialize the current JSON object (e.g. {…N object. Path 'worker.Id', line 1, position 16."]
    

    ModelState的完整错误消息是:

      

    无法反序列化当前的JSON对象(例如{" name":" value"})   进入类型   ' System.Collections.Generic.ICollection`1 [TestRotaru.Models.Worker]'   因为该类型需要一个JSON数组(例如[1,2,3])来反序列化   正确。要修复此错误,请将JSON更改为JSON数组   (例如[1,2,3])或更改反序列化类型以使其正常   .NET类型(例如,不是整数的基本类型,不是集合   类似于数组或List的类型,可以从JSON反序列化   宾语。 JsonObjectAttribute也可以添加到类型中以强制它   从JSON对象反序列化。 Path' worker.Id',第1行,位置   51。

    好吧到目前为止,这就像一个重复的问题,但我尝试了一些事情,我不理解答案中的一些事情。 我尝试使用以下属性来装饰我的模型:

      These on top of the class
    //[Serializable]
    //[DataContract(IsReference = true)]
    //[JsonObject(MemberSerialization.OptIn)]
    
      On properties
    //[JsonProperty]
    

    现在我不知道什么,我不明白:

    var dict = JsonConvert.DeserializeObject
                    <Dictionary<string, Item>>(*Where this string comes from*);
    

    这只是一个例子,我担心括号中的字符串不是关于if是字典还是别的。

    这是我的方法:

        [ResponseType(typeof(Job))]
        public IHttpActionResult PostJob(Job job)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
    
            job.DueDate = DateTime.Now;
            db.Job.Add(job);
            db.SaveChanges();
    
            return CreatedAtRoute("DefaultApi", new { id = job.Id }, job);
        }
    

    在关于这一切的所有答案中,每个人都在圆括号中有随机的json字符串...从那里我应该有那个?

    以下是我的模特:

    工作模式:

    //[Serializable]
    //[DataContract(IsReference = true)]
    //[Serializable()]
    //[JsonObject(MemberSerialization.OptIn)]
    public class Job
    {
        [JsonProperty]
        public int Id { get; set; }
        [JsonProperty]
        public string Name { get; set; }
        [JsonProperty]
        public string Description { get; set; }
        [JsonProperty]
        public DateTime DueDate { get; set; }
        [JsonProperty]
        public bool IsCompleted { get; set; }
    
        //[JsonProperty]
        //[System.Runtime.Serialization.IgnoreDataMember]
        public virtual ICollection<Worker> Worker { get; set; }
    }
    

    工人模型:

    //[Serializable]
    //[DataContract(IsReference = true)]
    //[JsonObject(MemberSerialization.OptIn)]
    public class Worker
    {
        [JsonProperty]
        public int Id { get; set; }
        [JsonProperty]
        public string FirstName { get; set; }
        [JsonProperty]
        public string LastName { get; set; }
    
        //[JsonProperty]
        //[System.Runtime.Serialization.IgnoreDataMember]
        public virtual ICollection<Job> Job { get; set; }
    }
    

    Angular组件和服务:

    add(Name: string, Description: string, worker): void {
        this.jobsServices.addJob({Name, Description, worker } as Jobs)
            .subscribe(jobs => {
                this.jobs.push(jobs);
            });
    }
    
    addJob(jobs: Jobs): Observable<Jobs> {
        return this.http.post<Jobs>(this.apiURL, jobs, httpOptions);
    }
    
    div class="row">
      <div class="col-md-12">
            <label class="labelInputs">Select Worker</label><br>
            <select [(ngModel)]="worker" class="form-control">
              <option [value]="0">Select Worker</option>
              <option *ngFor="let worker of workers" [ngValue]="worker">{{worker.FirstName}} {{worker.LastName}}</option>
          </select>
      </div>
    

    <button class="brn btn-lg btn-block btn-change" (click)="add(name.value, desc.value, worker)">Add Job</button>
    

    好的是一个很长的问题,但我想证明自己,我做了我的研究,我只是没有抛出错误信息并要求解决方案,但这真的让我感到紧张。

    由于我发布了关系数据,我的控制台显示ModelState{job.worker.Id: [,…]}如何反序列化?另外我的ModelState在到达API时将worker显示为null,我可以猜测因为不是从json转换而是值得知道。

    感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

因此,问题在于您在SPA上发送worker作为单个对象,而您的API需要一个工作列表(数组)。现在我不知道你想要什么......但你可以通过改变你的API模型来预期单个工人或更改你的SPA以发送工人列表来修复它。没人能回答你......取决于你的应用程序的要求。但是,我最好的猜测是,约伯可能有几个工人。所以:

Api模型(大多数相同......只是删除了属性并将Worker更改为Workers):

public class Job
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }

    public DateTime DueDate { get; set; }

    public bool IsCompleted { get; set; }

    public virtual ICollection<Worker> Workers { get; set; }
}


public class Worker
{
    public int Id { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    // This is an "array". your spa needs to send in this format.
    public virtual ICollection<Job> Job { get; set; }
}

水疗中心代码:

export class Job {
    id: int;
    name: string;
    // other fields here..

    // Workers property that maps API model
    workers: Array<Worker>;

    constructor(id: int, name: string [other fields..]) {
        this.id = id;
        // and so on..
    }

    public addWorker(worker) {
        this.workers.push(worker);
    }
}

export class Worker {
    id: int;
    firstName: string;
    // other fields here.. No need for array of jobs here!
}

使用此模型,您可以在调用API之前执行此操作(在添加功能上):

add(Name: string, Description: string, worker: Worker): void {

    // creates a job using constructor
    const job = new Job(name, description);

    // add Job via function(can even be more complex and add validation and so on..)
    job.addWorker(worker);

    this.jobsServices.addJob(job)
        .subscribe(jobs => {
            this.jobs.push(jobs);
        });
}

这会用这样的json调用api:

{
    "id": 1,
    "name": "some name",
    [ other fields..]
    "workers": [
        { "id:" 1, "name": "some worker name" }
    ]
}