创建用户时,UserManager不会初始化属性

时间:2019-06-30 09:57:27

标签: c# asp.net-core razor-pages asp.net-core-identity

我遇到一个问题,当我创建用户时,它没有初始化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)

因此它意味着favoriteCurrency为null,但不应为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 个答案:

答案 0 :(得分:1)

您可以更改初始化逻辑以创建用户然后设置集合吗?

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

您的代码看起来应该都可以工作,但是上述逻辑使您可以调试User实例之后,并故意设置属性的值。

我通常会将集合属性更改为自动初始化,这样可以简化序列化和类似您的初始化逻辑,也可以解决您的问题。

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

在这样的初始化方案中,很难在家中进行,尤其是在错误消息中引用行号并且在已发布的代码中没有行号的情况下。

我怀疑在您的UserManager.CreateAsync(?unknownType? user, string password)中,您的自定义属性被忽略了,通常是因为在此实现中,CreateAsync将采用接口或IdentityUser,或者在任何情况下,usermanager中的CreateAsync模式都倾向于“采用常规属性”。传入并创建实际的用户身份作为新对象。

如果是这种情况,那么您应该重写CreateAsync方法来管理您的自定义输入,或者在调用CreateAsync之后初始化创建的返回的用户对象。

为说明这一点,您创建并传递给user方法的CreateAsync对象通常不是CreateAsync响应中的同一用户对象实例。

  

所有这些都是基于假设,基于您提供的少量代码。如果此信息不足,请在您首先检测到用户对象中的UserFavoriteCurrencies为空的地方隔离代码行,并在最后一行包含期望值的地方指明代码行。这些信息本身很难从您的帖子中识别出来。