#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
она существует в API2. Вы использовали
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
?