`Модель.планы.Счетчик` выдал исключение типа » System.NullReferenceException`

#c# #asp.net #asp.net-mvc #asp.net-core-mvc #asp.net-core-webapi

Вопрос:

Я пытаюсь отобразить список строковых объектов в виде флажков. У меня есть два проекта, ASP.NET Основной проект приложения MVC и ASP.NET Основной веб-API, оба работают на 5.0 NET Core. В проекте MVC я вызываю проект web API, в котором он создаст новый список объектов. Затем в моем проекте MVC я сделал ссылку на проект, чтобы вызвать контроллер в представлении. Когда я запускаю приложение, MVC попадет в строку, где он вызывает проект API. После сохранения новых созданных объектов в GetPlan() методе в моем контроллере API я пытаюсь отобразить эти созданные объекты в виде флажков в моем представлении MVC. Однако, когда я это делаю, он говорит Model.plans.Count , что выдал исключение типа System.NullReferenceException . Затем, заглянув в него глубже, он скажет мне только:

Исключение System.NullReferenceException: «Ссылка на объект не установлена на экземпляр объекта».

Майкрософт.AspNetCore.Mvc.Razor.Страница бритвы.Модель.получите возвращенное значение null.

Я не понимаю, почему я возвращаю null, если новые объекты уже были созданы.

Проект MVC:

Controller где я вызываю свой API:

  public IActionResult SecIndex()
    {
        // call planapi
        var result = _planServiceClient.RetrievePlans().Resu<
        _logger.Log(LogLevel.Information, "Reached the Second Page View....");
        return View();
    }
 

затем мой проект API:

Model class for ViewPhoneNumberInput :

   public class ViewPhoneNumberInput
    {
        [Required(ErrorMessage = "You did not enter your phone number! Please enter your phone number!")]
        public String PhoneNumber { get; set; }
        public List<Plans> plans { get; set; }
    }
 

Мои планы модельный класс:

     public class Plans
    {
        public int PlanId { get; set; }
        public string PlanName { get; set; }
    }
 

Controller для api:

         [HttpGet]
        [Route("AvailablePlans")]
        public ActionResult GetPlan()
        {

            var _model = new ViewPhoneNumberInput();
            _model.plans = new List<Plans>();

            _model.plans.Add(new Plans { PlanId = 1, PlanName = "Internet" });
            _model.plans.Add(new Plans { PlanId = 2, PlanName = "TV amp; Streaming" });
            _model.plans.Add(new Plans { PlanId = 3, PlanName = "Mobile" });
            _model.plans.Add(new Plans { PlanId = 4, PlanName = "Home Security" });
            _model.plans.Add(new Plans { PlanId = 5, PlanName = "Home Phone" });


            var plansAvailable = JsonSerializer.Serialize(_model.plans);
            _logger.Log(LogLevel.Information, "Response-Body: {@Response-Body}", plansAvailable);


            return Ok(_model.plans);
        }
 

Above _model.plans will hold the values of the new objects created, so then I go to my MVC view project to call it so I can have it displayed but that is where it says that Model.plans.Count threw an exception of type ‘System.NullReferenceException`.

View for MVC project:

 @model Plan.API.Models.ViewPhoneNumberInput


<h2>Second page</h2>




@using (Html.BeginForm())
{

    for (int i = 0; i < Model.plans.Count; i  )
    {
        <input type="checkbox" id="@Model.plans[i].PlanId" name="Model.plans[i].PlanId" />
        <label for="Model.plans[i].PlanId"> @Model.plans[i].PlanName </label> <br />
    }


    @Html.TextBoxFor(r => r.PhoneNumber)
    <input id="Button" type="submit" value="Next" />

    <p>  @Html.ValidationMessageFor(r => r.PhoneNumber) </p>

}
 

Is there a reason why it is telling me that and not actually holding the newly created values from the API controller?


When implementing the suggestion below, I am able to see a value for PhoneNumber but for Plans it shows null (when hovering over phoneNumberInput in the post SecIndex).

My RetrievePlans():

         public async Task<List<Plan.API.Models.Plans>> RetrievePlans()
        {
            var response = await _httpClient.GetAsync("api/plans/AvailablePlans");
            response.EnsureSuccessStatusCode();

            var result = await response.Content.ReadAsStringAsync();

           var json = JsonConvert.DeserializeObject<List<Plan.API.Models.Plans>>(result);

            return json;
        }
 

My updated SecIndex() with Post SecIndex() :

         public IActionResult SecIndex()
        {
            // call planapi
            var result = _planServiceClient.RetrievePlans().Resu<
            _logger.Log(LogLevel.Information, "Reached the Second Page View....");
            return View(new Plan.API.Models.ViewPhoneNumberInput { plans = result });//So that you don't need to change the model in the view and the parameter type in the HttpPost Action.
        }

        [HttpPost]
        public IActionResult SecIndex(Plan.API.Models.ViewPhoneNumberInput phoneNumberInput)
        {
            try
            {

                if (ModelState.IsValid)
                {
                    _logger.Log(LogLevel.Information, "User successfully entered their phone number.");
                    return RedirectToAction("FinalIndex", "Final");
                }
                else
                {
                    _logger.Log(LogLevel.Error, "User missed to enter their phone number");
                    throw new Exception("User did not enter a phone number in the textfield!");
                }
             
            }
            catch(Exception ex)
            {
                _logger.LogError(ex, "Empty textfield!");
                return View(phoneNumberInput);
            }
        }
 

SecIndex.cshtml

 @model Plan.API.Models.ViewPhoneNumberInput

<h2>Second page</h2>


@using (Html.BeginForm())
{

    for (int i = 0; i < Model.plans.Count; i  )
    {
        <input type="checkbox" id="@Model.plans[i].PlanId" />
        <input hidden value="@Model.plans[i].PlanId" />
        <input hidden value="@Model.plans[i].PlanName" />

        <label for="Model.plans[i].PlanId"> @Model.plans[i].PlanName </label>
        <br />
    }


    @Html.TextBoxFor(r => r.PhoneNumber)
    <input id="Button" type="submit" value="Next" />

    <p>  @Html.ValidationMessageFor(r => r.PhoneNumber) </p>

}
<script>
    $('form').submit(function () {
        var count = 0;
        $('input[type=checkbox]').each(function () {
            if (this.checked) {
                this.nextElementSibling.name = "plans[" count "].PlanId";
                this.nextElementSibling.nextElementSibling.name = "plans["   count   "].PlanName";
                count  ;
            }
        });
    });
</script>
 

Мой контроллер API GetPlan:

         [HttpGet]
        [Route("AvailablePlans")]
        public List<Plans> GetPlan()
        {

            var _model = new ViewPhoneNumberInput();
            _model.plans = new List<Plans>();

            _model.plans.Add(new Plans { PlanId = 1, PlanName = "Internet" });
            _model.plans.Add(new Plans { PlanId = 2, PlanName = "TV amp; Streaming" });
            _model.plans.Add(new Plans { PlanId = 3, PlanName = "Mobile" });
            _model.plans.Add(new Plans { PlanId = 4, PlanName = "Home Security" });
            _model.plans.Add(new Plans { PlanId = 5, PlanName = "Home Phone" });


            var plansAvailable = JsonSerializer.Serialize(_model.plans);
            _logger.Log(LogLevel.Information, "Response-Body: {@Response-Body}", plansAvailable);


            return _model.plans;
        }
 

введите описание изображения здесь

Ответ №1:

Вот рабочая демонстрация:

метод api:

 [HttpGet]
        [Route("AvailablePlans")]
        public List<Plan.API.Models.Plans> GetPlan()
        {

            var _model = new ViewPhoneNumberInput();
            _model.plans = new List<Plans>();

            _model.plans.Add(new Plans { PlanId = 1, PlanName = "Internet" });
            _model.plans.Add(new Plans { PlanId = 2, PlanName = "TV amp; Streaming" });
            _model.plans.Add(new Plans { PlanId = 3, PlanName = "Mobile" });
            _model.plans.Add(new Plans { PlanId = 4, PlanName = "Home Security" });
            _model.plans.Add(new Plans { PlanId = 5, PlanName = "Home Phone" });


            var plansAvailable = JsonSerializer.Serialize(_model.plans);
            _logger.Log(LogLevel.Information, "Response-Body: {@Response-Body}", plansAvailable);


            return _model.plans;
        }
 

действие контроллера:

 public IActionResult SecIndex()
    {
        // call planapi
        var result = _planServiceClient.RetrievePlans().Resu<
        _logger.Log(LogLevel.Information, "Reached the Second Page View....");
        return View(new ViewPhoneNumberInput {  plans=result});//So that you don't need to change the model in the view and the parameter type in the HttpPost Action.
    }
 

Вид:

 @model Plan.API.Models.ViewPhoneNumberInput


<h2>Second page</h2>
@using (Html.BeginForm())
{

    for (int i = 0; i < Model.plans.Count; i  )
    {
        <input type="checkbox" id="@Model.plans[i].PlanId" />
        <input hidden value="@Model.plans[i].PlanId"/>
        <input hidden value="@Model.plans[i].PlanName" />

        <label for="Model.plans[i].PlanId"> @Model.plans[i].PlanName </label>
        <br />
    }


    @Html.TextBoxFor(r => r.PhoneNumber)
    <input id="Button" type="submit" value="Next" />

    <p>  @Html.ValidationMessageFor(r => r.PhoneNumber) </p>

}
<script>
    $('form').submit(function () {
        var count = 0;
        $('input[type=checkbox]').each(function () {
            if (this.checked) {
                this.nextElementSibling.name = "plans[" count "].PlanId";
                this.nextElementSibling.nextElementSibling.name = "plans["   count   "].PlanName";
                count  ;
            }
        });
    });
    </script>
 

Результат:
введите описание изображения здесь

Комментарии:

1. Спасибо! При попытке реализовать ваше решение я столкнулся с проблемой в строке возврата SecIndex() . Где у него есть » Представление возврата(новый план.API.Модели. ViewPhoneNumberInput { планы = результат }); «под результатом есть красная линия, в которой говорится» Не может неявно преобразовать тип » Plan.API.Models. ViewPhoneNumberInput` System.Collections.Generic.List<Plan.API.Models.Plans> кому . Я тоже точно скопировал ваше решение, но единственное отличие, которое я сделал, состояло в том, чтобы добавить ссылку в строку возврата SecIndex() и удалить ссылку на подпись GetPlan() , поскольку ViewPhoneNumberInput она существует в API

2. Вы использовали RetrievePlan() то, что было реализовано в посте, или вы изменили это?

3. Пожалуйста, дайте мне знать, правильно ли я реализовал RetrievePlan() , потому что при наведении курсора phoneNumberInput я могу видеть значение в PhoneNumber , но Plans для меня оно равно нулю. Пожалуйста, ознакомьтесь с обновленным разделом в сообщении

4. RetrievePlan() возвращает List<Plan.API.Models.Plans> ,поэтому его невозможно получить Cannot implicitly convert type 'Plan.API.Models.ViewPhoneNumberInput' to System.Collections.Generic.List<Plan.API.Models.Plans> при использовании return View(new ViewPhoneNumberInput { plans=result});

Ответ №2:

@Проблема Марко в том, что вы не передаете свой модальный

 return View(result);
 

Комментарии:

1. Я не прошел его, так как у меня нет другого представления о результате. Если я это сделаю return View(result); , SecIndex() он сообщит мне InvalidOperationException: The view '[{"planId":1,"planName":"Internet"},{"planId":2,"planName":"TV amp; Streaming"},{"planId":3,"planName":"Mobile"},{"planId":4,"planName":"Home Security"},{"planId":5,"planName":"Home Phone"}]' was not found. The following locations were searched: и даст мне места, которые он проверил

2. @MarkCo при использовании этой строки возвращает представление(результат); имя представления будет определяться именем действия, которое является SecIndex, и результатом, переданным для просмотра SecIndex.

3. Я понимаю, так почему же он возвращает то, что если бы я сделал в контроллере return Ok(_model.plans); , который содержал бы новые значения?

4. @MarkCo вернет Ok(_модель. Планы) означает возврат данных в виде открытого текста с кодом состояния 200 и в основном используется на стороне API. возвращаемое представление(результат) означает, что мы возвращаем представление и передаем результат в виде модели, которую мы будем использовать внутри нашего представления.

5. Поэтому мне пришлось бы создать новый вид специально для result ?