Всегда получать нулевые исключения при использовании API POST для контроллера Entity Framework из интерфейса React - PullRequest
3 голосов
/ 09 марта 2020

Я использую .NetCore 3.1 Entity Framework для создания игровой онлайн-системы.

У меня есть набор настроек моделей и контроллеров, и каждая модель представляет собой таблицу в моей базе данных MS SQL, и каждая модель имеет контроллер.

Контроллеры для этих моделей работают нормально.

Но теперь у меня есть форма, в которой пользователь будет создавать новый объект, состоящий из двух разных моделей.

Поэтому, когда пользователь отправляет форму, ему нужно будет создать новый элемент в обеих моделях / таблицах.

Поэтому я создал отдельный класс модели именно для этого, например:

namespace My_Game.Models
{
    public partial class CreateGame
    {
        public virtual StarSystem StarSystem { get; set; }
        public virtual Ship Ship { get; set; }
    }
}

Вот две модели, которые использует вышеуказанная модель:

public partial class StarSystem
{
    public string Name { get; set; }
    public long Location { get; set; }
}

public partial class Ship
{
    public string Name { get; set; }
    public string Type { get; set; }
    public long MaxCrew { get; set; }
}

А вот мой контроллер, который должен обрабатывать вызов API:

[HttpPost]
public async Task<ActionResult> ProcessForm([FromBody] CreateGame newGameEntry)
{
    // Read StarSystem data from form and add to DB via EF
    _context.StarSystem.Add(newGameEntry.StarSystem);
    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateException)
    {
        if (StarSystemExists(newGameEntry.StarSystem.Id))
        {
            return Conflict();
        }
        else
        {
            throw;
        }
    }

    // Read mentor data from form and add to DB via EF
    _context.Ship.Add(newGameEntry.Ship);
    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateException)
    {
        if (ShipExists(newGameEntry.Ship.Id))
        {
            return Conflict();
        }
        else
        {
            throw;
        }
    }

    return Ok();
}
private bool ShipExists(long id)
{
    return _context.Ship.Any(e => e.Id == id);
}

private bool StarSystemExists(long id)
{
    return _context.StarSystem.Any(e => e.Id == id);
}

Вот компонент React внешнего интерфейса, который используется для отправки формы в API:

import React, { useState } from 'react';
import axios from 'axios';

const App = () => {

    const handleSubmit = (e) => {
        e.preventDefault()
        const { myForm } = e.target.elements.myForm
        axios.post('https://localhost:44376/api/formprocessor', { form: myForm })
    }

    return (
        <div id="newGameForm">
            <form id="myForm" onSubmit={handleSubmit}>
                <input type="text" name="starSystemName" placeholder="Enter star system name:" />
                <input type="text" name="starSystemLocation" placeholder="Enter star system location:" />
                <input type="text" name="shipName" placeholder="Enter ship name:" />
                <input type="text" name="shipType" placeholder="Enter ship type:" />
                <input type="text" name="shipMaxCrew" placeholder="Enter max crew:" />                  
                <button type="submit">Submit</button>
            </form>
        </div >
    )
}

Но всякий раз, когда я пытаюсь поразить контроллер со страницы реакции, я просто получаю эту ошибку в режиме отладки:

Система. ArgumentNullException: Val ты не можешь быть нулем. (Параметр 'entity')

Я также пытался провести тестирование с помощью Postman и поместил фиктивные значения теста в тело, и я получил ту же ошибку.

Чего мне не хватает?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 09 марта 2020

Наиболее вероятная проблема заключается в том, что формат отправляемых данных не соответствует модели, используемой в действии. Привязка модели не может быть заполнена на основе того, что отправляется.

После отправки данных формы обновите действие, чтобы ожидать данные из формы

[HttpPost]
public async Task<ActionResult> ProcessForm([FromForm] CreateGame newGameEntry) {
    //...
}

Затем обновите клиентскую часть для отправки. соответствующие данные формы.

const qs = require('querystring')

//...

const handleSubmit = (e) => {
    e.preventDefault()
    const { myForm } = e.target.elements.myForm
    const form = new FormData();
    for ( const key in myForm) {
        form.append(key, myForm[key]);
    }

    axios({
        method: 'post',
        url: 'https://localhost:44376/api/formprocessor',
        data: qs.stringify(form),
        headers: {'Content-Type': 'application/x-www-form-urlencoded' }
    });
}

return (
    <div id="newGameForm">
        <form id="myForm" onSubmit={handleSubmit}>
            <input type="text" name="starSystem.Name" placeholder="Enter star system name:" />
            <input type="text" name="starSystem.Location" placeholder="Enter star system location:" />
            <input type="text" name="ship.Name" placeholder="Enter ship name:" />
            <input type="text" name="ship.Type" placeholder="Enter ship type:" />
            <input type="text" name="ship.MaxCrew" placeholder="Enter max crew:" />
            <button type="submit">Submit</button>
        </form>
    </div >
)

Обратите внимание на изменение имени в соответствии со структурой отправляемых моделей. Таким образом, механизм связывания моделей будет знать, как сопоставить отправленные данные с намеченными моделями.

Ссылка Привязка модели в ASP. NET Ядро

0 голосов
/ 11 марта 2020

На основе React Forms Обратитесь к моей демонстрации ниже, чтобы отправить данные формы на контроллер:

import React, { Component } from 'react';
import axios from 'axios';

export class FormTest extends Component {
    constructor(props) {
        super(props);

        this.state = {
            starSystemName: "",
            starSystemLocation:"",         
            shipName: "",
            shipType: "",
            shipMaxCrew:""
        };

        this.handleStarSystemName = this.handleStarSystemName.bind(this);
        this.handleStarSystemLocation = this.handleStarSystemLocation.bind(this);
        this.handleShipName = this.handleShipName.bind(this);
        this.handleShipType = this.handleShipType.bind(this);
        this.handleShipMaxCrew = this.handleShipMaxCrew.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleStarSystemName(event) {
        this.setState({              
                starSystemName: event.target.value 
        });

    }
    handleStarSystemLocation(event) {
        this.setState({
                starSystemLocation: event.target.value
        });
    }
    handleShipName(event) {
        this.setState({
                shipName: event.target.value
        });
    }  
    handleShipType(event) {
        this.setState({
                shipType: event.target.value
        });
    }
    handleShipMaxCrew(event) {
        this.setState({
                shipMaxCrew: event.target.value
        });
    }
    handleSubmit = (e) => {

        e.preventDefault();       
        const data = new FormData();
        data.append("starSystem.Name", this.state.starSystemName);
        data.append("starSystem.Location", this.state.starSystemLocation);
        data.append("ship.Name", this.state.shipName);
        data.append("ship.Type", this.state.shipType);
        data.append("ship.MaxCrew", this.state.shipMaxCrew);


        axios({
            method: 'post',
            url: 'https://localhost:44301/WeatherForecast',
            data: data,
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
        });
    }
    render() {
        return (
            <div id="newGameForm" >
                <form id="myForm" onSubmit={this.handleSubmit}>
                    <input type="text" value={this.state.starSystemName} placeholder="Enter star system name:" onChange={this.handleStarSystemName} />
                    <input type="text" value={this.state.starSystemLocation} placeholder="Enter star system location:" onChange={this.handleStarSystemLocation} />
                    <input type="text" value={this.state.shipName} placeholder="Enter ship name:" onChange={this.handleShipName} />
                    <input type="text" value={this.state.shipType} placeholder="Enter ship type:" onChange={this.handleShipType} />
                    <input type="text" value={this.state.shipMaxCrew} placeholder="Enter max crew:" onChange={this.handleShipMaxCrew}/>  
                    <button type="submit">Submit</button>
                </form>
            </div >
        )
    }
}

Контроллер:

[HttpPost]
public async Task<ActionResult> ProcessForm([FromForm] CreateGame newGameEntry)
...