61

イントラネット上でasp.netWebサイトを数週間ライブで実行しています。未処理の例外を除いて、application_erroremailerメソッドからメールを受け取りました。

これが(表示を改善するためにいくつかのパスをクリーンアップしました)です。

例外:オブジェクト参照がオブジェクトのインスタンスに設定されていません。スタックトレース:System.Collections.Generic.Dictionary`2.Insert(TKey key、TValue value、Boolean add)at System.Collections.Generic.Dictionary`2.Add(TKey key、TValue value)at TimesheetDomain.DataMappers.StaffMemberData TimesheetDomain \ DataMappers \ StaffMemberData.cs:line 362の.ReadStaff(SqlDataReaderリーダー)

TimesheetDomain \ DataMappers \ StaffMemberData.cs:line 401のTimesheetDomain.DataMappers.StaffMemberData.GetStaffMember(String name)で

TimesheetDomain \ ServiceLayer \ TimesheetManager.cs:line199のTimesheetDomain.ServiceLayer.TimesheetManager.GetUserFromName(String name)で

\ App_Code \ UserVerification.cs:line 29のUserVerification.GetCurrentUser()で\ WebTimesheets \ WebTimesheets.master.cs:line159のWebTimesheets.OnInit(EventArgs e)で

System.Web.UI.Control.InitRecursive(ControlnamingContainer)でSystem.Web.UI.Control.InitRecursive(ControlnamingContainer)でSystem.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint、Boolean includeStagesAfterAsyncPoint)

基本的に、データリーダーを読み取ってスタッフメンバーオブジェクトを構築するReadStaffメソッドでエラーが発生しているように見えます。コードは次のとおりです。

while (reader != null && reader.Read())
{
    StaffMember newMember = null;
    string firstName = reader["FirstName"].ToString();
    string lastName = reader["LastName"].ToString();
    int staffID = (int)reader["StaffID"];
    int employSection = (int)reader["EmploySection"];
    StaffType employType = (StaffType)employSection;
    string emailAddress = reader["EmailInt"].ToString();
    int employCode = (int)reader["ibbwid"];

    //check if they are an admin staff member 
    if (IsAdminStaff(employType))
    {
        newMember = new AdminOfficer(firstName, lastName, employType, staffID, emailAddress, employCode);
    }
    else
    {
        //check if they are a supervisor
        if (IsASupervisor(staffID))
            newMember = new Supervisor(firstName, lastName, employType, staffID, emailAddress, employCode);
        else
            newMember = new StaffMember(firstName, lastName, employType, staffID, emailAddress, employCode);
    }

    //add to identity map
    if (!_staffMembers.ContainsKey(staffID))
        _staffMembers.Add(staffID, newMember); //****THIS IS LINE 362*****
    else
        _staffMembers[staffID] = newMember;
}

(362行目は最後の3行目です)私はアイデンティティマップを使用しています(パターンに関するファウラーの本を読んで、それは良い考えだと思いました-間違っていたかもしれません、コメントを喜んでいます)が、後で使用するので、それはあまり関連性がありません他の場所にあるnewMemberオブジェクトなので、そのブロックを削除するNullReferenceExceptionと発生します。

newMemberそこにある最後の3行目(エラーが発生した行)で、いったいどのようにnullであるかを確認するのに苦労しています。

Resharper / VSは、その可能性があるという警告を表示しませんnull。これは、私が選択した3つのコンストラクターがあるためです。

このエラーを修正するためにどこを探すことができるかを誰かが提案できますか?これは1回だけ発生し、サイトが公開されてからそのメソッドは何千回も呼び出されています。

ありがとう

[編集]ご要望に応じて、こちらがスタッフ向けのIComparerです

/// <summary>
/// Comparer for staff members - compares on name
/// </summary>
public class StaffMemberComparer : IComparer
{
    public int Compare(object x, object y)
    {
        //check they are staff members
        if (x is StaffMember && y is StaffMember)
        {
            //do a simple string comparison on names
            StaffMember staffX = x as StaffMember;
            StaffMember staffY = y as StaffMember;

            return String.Compare(staffX.FirstName, staffY.FirstName);
        }

        throw new Exception("This is for comparing Staff Members");
    }
}

IComparableの実装で使用されます

/// <summary>
/// IComparable implementaiton
/// </summary>
/// <param name="obj">object to compare to</param>
/// <returns></returns>
public int CompareTo(object obj)
{
    StaffMemberComparer comparer = new StaffMemberComparer();
    return comparer.Compare(this, obj);
}
4

6 に答える 6

139

これはほぼ間違いなくスレッドの問題です。この質問とその受け入れられた回答を参照してください。

Dictionary<>.Insert()NullReferenceException挿入操作中にディクショナリインスタンスが別のスレッドから変更された場合、内部的にスローされます。

于 2010-02-03T20:41:40.110 に答える
22

.NET 4.0以降では、ConcurrentDictionaryを使用して、複数のスレッドから同じディクショナリを同時に操作することに関連するスレッドの問題を回避できます。

于 2013-01-17T16:44:48.020 に答える
1

明らかなものは何も見えません。SQLを実行して、データベースに不良データがないかどうかを確認します。問題は、関連する入力フォームの異常なバグである可能性があります。これまで何千回も問題なくコードが実行された場合は、問題のコードブロックの周りに追加の例外処理/レポートをラップして、次に発生した場合に少なくともstaffIdを取得できるようにします。

あなたはこのようなものに多くの時間を費やすことができます。最も便利なアプローチは、上記の/制御された条件下で再び失敗させることです.....それが引き起こす混乱のレベルが許容可能/管理可能/マイナーであると仮定します。

すぐに知る必要性を満たしていないことを感謝しますが、特にこのような低い故障率で問題を管理するための最良の方法かもしれません。

于 2009-08-24T05:26:38.050 に答える
1

これは1回だけ発生し、サイトが公開されてからそのメソッドは何千回も呼び出されています。

これを読んだ後、.NETがメモリを使い果たし、それ以上辞書キーを作成できなかった可能性があり、実際にはどこにも問題がない可能性があると結論付けることができます。しかし、はい、セッション/アプリケーション変数に多くの情報を格納しようとすると、この種のエラーが発生し、Webアプリケーションのメモリフットプリントが増加しました。しかし、辞書やリストに10,000個のアイテムを保存するなど、数が非常に多くなると、このようなエラーが発生しました。

パターンは良好ですが、データベースを使用して情報をリレーショナル形式で格納していることも理解する必要があります。メモリを使用して同様のものを格納し始めると、強力なデータベースを無視します。データベースは値をキャッシュすることもできます。

ばかげているように聞こえるかもしれませんが、トラフィックがない深夜に、24時間ごとにWindowsサーバーを再起動します。それは私たちがそのようなエラーを取り除くのに役立ちました。すべてのキャッシュ/ログをクリアするために、定期的にサーバーを修正スケジュールで再起動します。

于 2009-08-24T09:46:21.007 に答える
0

他の人が言っているように、比較が問題を引き起こしている可能性があります。
比較の基準のいずれかにnull値が含まれていますか?具体的には、文字列のプロパティ?

つまり、firstname、lastname、またはemailIdがnullであり、それを比較に使用すると、比較のために辞書内で使用すると失敗する可能性があります。

編集:SupervisorとStaffMemberおよびAdminStaffクラスはどのように関連していますか?
コードでは、両方のインスタンスをStaffMemberにキャストしています。私の推測では、SupervisorクラスとStaffMemberクラスが関連していない場合は問題になる可能性があります。

EDIT2:辞書インスタンスのスロープは何ですか?アプリケーションレベル/セッションレベルで共有されていますか?複数のスレッドがそこから読み取り/書き込みを試みる可能性はありますか?

于 2009-08-24T03:45:49.160 に答える
0

スレッド化とは関係のないこの例外を見たもう1つの方法は、ディクショナリをシリアル化するときです。この場合、それは空でしたが、逆シリアル化されたインスタンスのInsert()メソッドでNullReferenceExceptionが発生しました。

私の場合の単純な変更は、逆シリアル化後に新しいインスタンスを作成することでした。シリアル化によってディクショナリが壊れただけなのか、それともディクショナリが定義されているタイプなのかはわかりません。

私の場合、型はシリアル化サロゲートなしではシリアル化できませんでした(そして私はこれらを提供しました)が、おそらく辞書の何かがここで問題を抱えていました。繰り返しになりますが、辞書は空でしたが、これはまだ発生していました。

于 2012-08-17T19:09:17.473 に答える