【解決方法】null 参照エラーが発生するのはなぜですか?


現在、古いブログを .NET 7 にアップグレードしようとしています。アップグレード中に、ハードコードされたものをすべて削除できるので、誰もが使用できると思いました。

次の Program.cs があります。

C#
public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        builder.Configuration.AddJsonFile("appsettings.json");

        builder.Configuration.AddUserSecrets("845be935-7d32-419f-9734-f9458e0be851");

        builder.Services.Configure<AppSettings>(builder.Configuration);        

        builder.Services.AddTransient<SeedData>();

        SeedData.UserAsync();
        ....
    }

SeedData は次のとおりです。

C#
public class SeedData
    {
        private static MannsContext? _ctx;
        private static UserManager<MannsUser>? _userMgr;
        private static ILogger<SeedData>? _logger;
        private static IConfiguration? _config;

        public SeedData(MannsContext ctx, UserManager<MannsUser> userMgr, ILogger<SeedData> logger, IConfiguration config)
        {
            _ctx = ctx;
            _userMgr = userMgr;
            _logger = logger;
            _config = config;
        }
        
        public static async Task UserAsync()
        {
            // Seed User
       (X)  string email = _config.GetValue<string>("Blog:Email");
            string username = _config.GetValue<string>("Blog:Username");
            string password = _config.GetValue<string>("Blog:Password");

            if (await userMgr.FindByNameAsync(username) == null)
            {
                var user = new MannsUser()
                {
                    Email = email,
                    UserName = username,
                    EmailConfirmed = true,
                };

                var result = await userMgr.CreateAsync(user, password);
                if (!result.Succeeded)
                {
                    throw new InvalidProgramException("Failed to create seed user");
                }
            }
        }
    }

実行後、電子メールを取得しようとしているときに、マークされた行で「System.NullReferenceException: “オブジェクト参照がオブジェクトのインスタンスに設定されていません。”」に遭遇しました。

現在、なぜこのエラーが発生するのかわかりません。 多分私は何かを逃した?

私が試したこと:

それを読んで 6.0 の新しい最小ホスティング モデルに移行されたコード サンプル | マイクロソフト ラーン[^]

解決策 1

これは、私たちが最もよく聞かれる問題の 1 つであり、私たちが最も答えられない問題でもありますが、あなた自身が最も答えられる問題です。

エラーの意味を説明しましょう。変数、プロパティ、またはメソッドの戻り値を使用しようとしましたが、null が含まれています。これは、変数にクラスのインスタンスがないことを意味します。
ポケットのようなものです。シャツにポケットがあり、ペンを入れるのに使用します。 ポケットに手を入れてペンがないことに気づいたら、紙に自分の名前を書くことはできません。 空のポケットはヌル値 (ここにはペンがありません!) を与えているので、ペンを取り出したら通常行うことは何もできません。 なぜそれは空ですか? それが問題です – 今朝家を出るときにペンを手に取るのを忘れたのかもしれませんし、昨夜脱いだときに昨日のシャツのポケットにペンを忘れたのかもしれません.

私たちはそこにいなかったのでわかりません。さらに重要なことに、あなたのシャツも見えず、ましてやポケットに何が入っているかもわかりません!

コンピューターに戻ると、あなたは同じことを何らかの形で行っています。そして、あなたのコードを見ることはできません。
しかし、それは可能です。ここでは、Visual Studio が役に立ちます。 デバッガーでプログラムを実行し、失敗すると、問題が見つかった行が表示されます。 次に、そのさまざまな部分を調べて、どの値が null であるかを確認し、コードを振り返ってその理由を見つけることができます。 したがって、エラー行を含むメソッドの先頭にブレークポイントを置き、プログラムを最初からもう一度実行します。 今回は、デバッガーはエラーが発生する前に停止し、コードをステップ実行して値を確認することで、何が起こっているかを調べることができます。

しかし、それはできません – 私たちはあなたのコードを持っていません。コードを持っていたとしても、それをどのように使用するかわかりません。あなたのデータもありません。 試してみて、どれだけの情報が得られるか見てみましょう!

解決策 2

ええ、あなたは何かを逃しました。 呼び出される前に初期化されるクラスのフィールドに依存している場合、UserAsync (ちなみに悪い名前) が静的なのはなぜですか? SeedData クラスのインスタンスを作成しないため、_config のようにインスタンス変数が初期化されることはありません。

メソッド名は、「動詞」または「動詞名詞」の形式にする必要があります。 プロパティ名は通常「名詞」です。

解決策 3

表示されているエラーは、null であるオブジェクトのメンバーにアクセスしようとしたときに発生する NullReferenceException です。 この場合、UserAsync メソッドがアクセスしようとすると、SeedData クラスの _config フィールドが null のように見えます。

考えられる理由の 1 つは、SeedData クラスが静的であるため、_config フィールドも静的になることです。 つまり、使用する前に IConfiguration のインスタンスに明示的に設定しない限り、null になります。

SeedData クラスを非静的に変更してから、クラスのインスタンスを作成するときに必要な依存関係 (IConfiguration など) を渡すことができます。 このようにして、使用する前に _config フィールドが有効なインスタンスで初期化されることを確認できます。

これを行う方法の例を次に示します。

C#
public class SeedData
{
    private MannsContext? _ctx;
    private UserManager<MannsUser>? _userMgr;
    private ILogger<SeedData>? _logger;
    private IConfiguration? _config;

    public SeedData(MannsContext ctx, UserManager<MannsUser> userMgr, ILogger<SeedData> logger, IConfiguration config)
    {
        _ctx = ctx;
        _userMgr = userMgr;
        _logger = logger;
        _config = config;
    }

    public async Task UserAsync()
    {
        // Seed User
        string email = _config.GetValue<string>("Blog:Email");
        string username = _config.GetValue<string>("Blog:Username");
        string password = _config.GetValue<string>("Blog:Password");

        if (await userMgr.FindByNameAsync(username) == null)
        {
            var user = new MannsUser()
            {
                Email = email,
                UserName = username,
                EmailConfirmed = true,
            };

            var result = await userMgr.CreateAsync(user, password);
            if (!result.Succeeded)
            {
                throw new InvalidProgramException("Failed to create seed user");
            }
        }
    }
}

次に、 Main メソッドを更新して SeedData のインスタンスを作成し、そのインスタンスで UserAsync メソッドを呼び出す必要があります。次のようにします。

C#
public static void Main(string[] args)
{
    var builder = WebApplication.CreateBuilder(args);

    builder.Configuration.AddJsonFile("appsettings.json");

    builder.Configuration.AddUserSecrets("845be935-7d32-419f-9734-f9458e0be851");

    builder.Services.Configure<AppSettings>(builder.Configuration);        

    builder.Services.AddTransient<SeedData>();

    // Create an instance of SeedData and call UserAsync on it
    var seedData = new SeedData(...);
    seedData.UserAsync();
    ....
}

これが役立つことを願っています!

コメント

タイトルとURLをコピーしました