UserManager не инициализирует свойство при создании пользователя - PullRequest
2 голосов
/ 30 июня 2019

У меня проблема, когда я создаю пользователя, он не инициализирует свойство типа list <> - я получаю следующую ошибку:

An unhandled exception occurred while processing the request.
NullReferenceException: Object reference not set to an instance of an object.
AspNetCore.Views_Home_Index.ExecuteAsync() in Index.cshtml, line 53

Ошибка появляется только тогда, когда я зарегистрирован и авторизован! Я думаю, что это важно.

Как вы можете ожидать, строка с ошибкой будет

foreach (var currencyUser in favoriteCurrency)

так что это значит, что favourCurrency имеет значение null, но это не должно быть.

РЕДАКТИРОВАТЬ: Вот полный контекст:

@using X.PagedList.Mvc.Core;
@using X.PagedList;
@using X.PagedList.Mvc.Common
@using Microsoft.AspNetCore.Identity
@using WalutyBusinessLogic.Models
@inject SignInManager<User> SignInManager
@inject UserManager<User> UserManager
@{
ViewData["Title"] = "Home Page";
}

@{
User applicationUser = null;
List<UserCurrency> favoriteCurrency = null;

if (SignInManager.IsSignedIn(User))
{
    applicationUser = await UserManager.GetUserAsync(User);
    favoriteCurrency = applicationUser.UserFavoriteCurrencies;
}

}

<div class="text-center">
<h1 class="display-4">Welcome</h1>
</div>


<form asp-controller="Home" asp-action="Index" method="get">
<div class="md-form mt-0">
    <input name="searchString" class="form-control" type="text" value="@ViewBag.searchFilter" placeholder="Search by code" aria-label="Search">
</div>
</form>
<table class="table">

<thead>
    <tr>
        <th scope="col">Currency code</th>
        <th scope="col">Full name</th>
    </tr>
    <tr></tr>
</thead>
<tbody>
    @foreach (var currencyInfo in ViewBag.SinglePageOfCurrencyInfo)
    {
        <tr>
            <td>@currencyInfo.Code</td>
            <td>@currencyInfo.Name</td>
            @if (SignInManager.IsSignedIn(User))
            {
                bool isAlreadyIn = false;

                foreach (var currencyUser in favoriteCurrency)
                {
                    if (currencyInfo.Id == currencyUser.CurrencyId && !isAlreadyIn)
                    {
                        isAlreadyIn = true;
                        break;
                    }
                }
                if (isAlreadyIn)
                {
                    <td><a asp-controller="Favorites" asp-action="delete" asp-route-id="@currencyInfo.Id">Remove from Favorites</a></td>
                }
                else
                {
                    <td><a asp-controller="Favorites" asp-action="add" asp-route-id="@currencyInfo.Id">Add to Favorites</a></td>
                }
            }
        </tr>
    }
</tbody>
</table>

@Html.PagedListPager((IPagedList)ViewBag.SinglePageOfCurrencyInfo,
page => Url.Action("Index", new { page = page, searchString = ViewBag.searchFilter }),
new PagedListRenderOptions
{
    LiElementClasses = new string[] { "page-item" },
    PageClasses = new string[] { "page-link" },
    MaximumPageNumbersToDisplay = 5,
    EllipsesFormat = ""
})

Вот мой метод регистрации - от удостоверения личности, но немного измененный

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");
    if (ModelState.IsValid)
    {
        var user = new User { UserName = Input.Email, Email = Input.Email, UserFavoriteCurrencies = new List<UserCurrency>()};

        var result = await _userManager.CreateAsync(user, Input.Password);

        if (result.Succeeded)
        {
            Log.Logger.Information($"User {Input.Email} has been created.");

            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            var callbackUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { userId = user.Id, code = code },
                protocol: Request.Scheme);

            await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

            await _signInManager.SignInAsync(user, isPersistent: false);
            return LocalRedirect(returnUrl);
        }
        foreach (var error in result.Errors)
        {
            ModelState.AddModelError(string.Empty, error.Description);
        }
    }

    // If we got this far, something failed, redisplay form
    return Page();
}

как вы можете видеть в этой части, я указываю на создание:

var user = new User { UserName = Input.Email, Email = Input.Email, UserFavoriteCurrencies = new List<UserCurrency>()};

но это не проходит.

Вот мои занятия:

Пользователь:

public class User : IdentityUser
{
    public virtual List<UserCurrency> UserFavoriteCurrencies { get; set; }
}

UserCurrency:

public class UserCurrency
{
    public int UserId { get; set; }
    public User User { get; set; }
    public int CurrencyId { get; set; }
    public Currency Currency { get; set; }
}

Валюта при необходимости:

 public class Currency
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<CurrencyRecord> ListOfRecords { get; set; }
    public List<UserCurrency> FavoritedByUsers { get; set; }
}

Если пользователь вошел в систему, я получаю указанную ошибку. Что я делаю не так?

1 Ответ

1 голос
/ 30 июня 2019

Можете ли вы изменить логику инициализации, чтобы создать пользователя, а затем установить коллекцию?

var user = new User { 
    UserName = Input.Email, 
    Email = Input.Email
};
user.UserFavoriteCurrencies = new List<UserCurrency>()

Ваш код выглядит так, как будто все должно работать, но приведенная выше логика позволяет отлаживать после создания экземпляра User ипреднамеренно устанавливает значение свойства.

Обычно я изменяю свойства коллекции на auto-init, это упрощает сериализацию и логику инициализации, как у вас, что также может решить вашу проблему.

public class User : IdentityUser
{
    public virtual List<UserCurrency> UserFavoriteCurrencies { get; set; } = new List<UserCurrency>();
}

В подобных сценариях инициализации трудно следовать дома, особенно с указанием номеров строк в сообщениях об ошибках и без номеров строк в опубликованном вами коде.

Я подозреваю в вашемUserManager.CreateAsync(?unknownType? user, string password) что ваше пользовательское свойство игнорируется, как правило, потому что в этой реализации CreateAsync будет использовать интерфейс или IdentityUser, или в любом случае шаблон CreateAsync внутри usermanager имеет тенденцию быть «Возьмите общие свойства, переданные и создайте действительную идентификацию пользователя какновый объект.

Если этоВ этом случае вам следует переопределить метод CreateAsync для управления пользовательским вводом, или после вызова CreateAsync затем инициализировать созданный возвращенный пользовательский объект.

Чтобы проиллюстрировать точку, созданный вами объект userи переданный методу CreateAsync обычно не будет тем же экземпляром объекта пользователя в ответе от CreateAsync.

Все это основано на предположениях, основанных на небольшом предоставленном вами коде.Если этой информации недостаточно, выделите строку кода для использования там, где вы впервые обнаружите, что UserFavoriteCurrencies является нулевым в вашем пользовательском объекте, а также укажите последнюю строку кода, где у него есть ожидаемые значения.Эту информацию трудно было узнать из вашего поста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...