25

私は関連する質問をしていましたが、タイトルを台無しにして、誰もそれを理解しませんでした。より正確に質問できるようになったので、新しい質問に再定式化し、古い質問を閉じることにしました。そのために残念。

したがって、私がやりたいのは、データ(データベースに格納されているカスタムユーザーのニックネーム)をLoginUserControlに渡すことです。このログインはマスターページからHtml.RenderPartial()を介してレンダリングされるため、実際に行う必要があるのは、すべての呼び出しにViewData["UserNickname"]が存在することを確認することです。しかし、すべてのコントローラーのすべてのアクションにViewData ["UserNickname"]を設定したくないので、このアプローチを使用して、次のように作業を行う抽象ベースコントローラーを作成することにしました。

public abstract class ApplicationController : Controller
    {
        private IUserRepository _repUser;

        public ApplicationController()
        {
            _repUser = RepositoryFactory.getUserRepository();
            var loggedInUser = _repUser.FindById(User.Identity.Name); //Problem!
            ViewData["LoggedInUser"] = loggedInUser;
        }
    }

このように、私の派生コントローラーが何をするにしても、ユーザー情報はすでに存在します。

ここまでは順調ですね。今問題のために:

Userはすでにnullであるため、User.Identity.Nameを呼び出すことができません。これは私の派生コントローラーのすべてに当てはまるわけではないので、これは抽象ベースコントローラーに固有です。

コード内の別の場所でFormsAuthenticationを介してUser.Identity.Nameを設定していますが、これは問題ではないと思います。afaikUser.Identity.Nameはnullにすることができますが、User自体はできません。

HttpContextが利用できないように見え(null;-もあるため)、ここで単純でありながら重要なポイントが欠落しているように見えます。誰かが私にいくつかのヒントを与えることができますか?とても感謝しております。

4

10 に答える 10

25

この問題の答えは、実際には非常に簡単です。Raimond が指摘した理由により、コンストラクター内からコードを実行することはできませんが、コンストラクターの外で実行することはできます。

だから私がしたことは、ベースコントローラークラスで onActionExecuting() をオーバーライドし (カスタム属性を作成しましたが、メソッドをオーバーライドするだけでも機能するはずです)、そこからユーザールックアップを行います。

今では期待どおりに動作し、繰り返しのコードはありません。

于 2009-01-19T11:42:58.310 に答える
20

ユーザー プロパティは、コントローラーがインスタンス化されるまで割り当てられませんが、次の方法でコンストラクターから早期にアクセスできます。

System.Web.HttpContext.Current.User
于 2016-11-26T19:14:57.790 に答える
14

私の推測では、コントローラーの基本コンストラクターはユーザーに入力されていませんが、後で ControllerContext がコントローラーに設定されたときにのみ認識されます。MVC アプリケーションのライフサイクルに関するドキュメントでこれを確認するか (プレビュー バージョン用であるため、少し古くなっている可能性がありますが、ここのドキュメントで確認する必要があります)、または単に MVC のソース コードを確認する必要があります。

私が持っているMVCのコードから(これもプレビューバージョンですが、それで問題ないはずです):(コントローラー内)

 public IPrincipal User {
            get {
                return HttpContext == null ? null : HttpContext.User;
            }
        }

...

public HttpContextBase HttpContext {
        get {
            return ControllerContext == null ? null : ControllerContext.HttpContext;
        }
    }

コードにデフォルトのコンストラクターの実装が見当たりません。これは、構築時に ControllerContext が null であることを証明します。

したがって、コードを別の場所で実行する必要があります。

于 2009-01-10T09:34:38.820 に答える
5

次のようなものを使用してこれを取得できますか:

HttpContext currentContext = HttpContext.Current;
string userName = currentContext.User.Identity.Name;

それとも、HttpContext は常に空ですか??

抽象クラスのコンストラクターを介して httpContext を設定できますか? このように使用しますか?

于 2009-01-10T09:01:06.097 に答える
4

ありがとうレイモンド。私はあまりにも疲れていて、明らかなことを見ることができませんでした。@Keeney: はい、コンテキストは常に null です。レイモンドはその理由を指摘した。とにかくありがとう、私も理由がわかりませんでした:-)

私の現在の作業ソリューション (私が望んでいたものではありませんが) は、すべてのコントローラー アクションを装飾するために使用する属性です。実装は次のとおりです。

public class MasterPageDataAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
            IUserRepository _repUser = RepositoryFactory.getUserRepository();
            IPrincipal siteUser = filterContext.Controller.ControllerContext.HttpContext.User;
            User loggedInUser = null;

            if (siteUser == null || siteUser.Identity.Name == null)
            {
                //do nothing
            }
            else
            {
                loggedInUser = _repUser.findUserById(siteUser.Identity.Name);
            }
            filterContext.Controller.ViewData["LoggedInUser"] = loggedInUser ?? new User { Nickname = "Guest" };
        }
    }

DRY の原則に従う方法でそのコードを実行する方法を検討します。そのために属性を使用することは間違いなく同じことを繰り返すことを意味するからです。ある種のインターセプター (興味深いアイデア) またはフックが役立つかもしれません。

乾杯。

于 2009-01-10T15:54:16.743 に答える
1

私はベースコントローラーの実装でこれを行っており、期待どおりに機能します。

public abstract class BaseController : Controller
{
    public bool LoggedOn
    {
        get { return User.Identity.IsAuthenticated; }
    }
}

これは常に true または false を返すので、User != null

于 2009-01-11T22:23:14.383 に答える
0

マスターフへ:私はあなたの助けを借りて同様のことをしました、それが後の訪問者を助けることができることを望みます。私の場合、さまざまなユーザーのコントローラーのリポジトリを作成する必要がありますが、コントローラーのコンストラクターでは、(プリンシパル)ユーザーの準備ができていません。だから私はコントローラーの属性を作成しました:

[CreateRepositoryByUser]
public class MFCController : Controller
{
    protected MFCRepository _repository
    {
        get { return ViewData["repository"] as MFCRepository; }
    }
...

_repositoryは、実際、コントローラーのプライベート変数ではありませんが、属性によって作成されます。

public class CreateRepositoryByUser : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        CreateRepository(filterContext);
    }

    public static void CreateRepository(ActionExecutingContext filterContext)
    {
        if (filterContext.Controller.ViewData["repository"] == null)
        {
            filterContext.Controller.ViewData["repository"] =
                MFCRepository.CreateMFCRepository(filterContext.Controller.ControllerContext.HttpContext.User);
        }
    }
}

この属性がトリガーされる前に他の属性が(principal)Userを使用したい場合に備えて、リポジトリを作成するコードを別のメソッドに配置しました。

于 2013-03-17T02:55:37.610 に答える
0

コンストラクターからの呼び出しは、MVC パイプラインでは早すぎます。

コードを OnAuthorization に移動すると、パラメーターで許可されたユーザーを取得します。私のために働いた!

あなたの例から、私は次のようにします:

public abstract class ApplicationController : Controller {
    private IUserRepository _repUser;

    protected override void OnAuthorization(AuthorizationContext filterContext)
    {
        _repUser = RepositoryFactory.getUserRepository();
        var loggedInUser = _repUser.FindById(filterContext.HttpContext.User.Identity.Name); //Problem!
        ViewData["LoggedInUser"] = loggedInUser;
    }


}
于 2016-02-16T15:08:26.033 に答える