2

ASP.Net Web API プロジェクトがあります。このプロジェクトでは NHibernate を使用しています。具体的には流暢な NHibernate です。カスタムActionFilterAttributeを使用してNHibセッション管理を処理しています。次のようになります。

public class SessionManagement : ActionFilterAttribute
{
    public SessionManagement()
    {
        SessionFactory = WebApiApplication.SessionFactory;
    }

    private ISessionFactory SessionFactory { get; set; }

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var session = SessionFactory.OpenSession();
        CurrentSessionContext.Bind(session);
        session.BeginTransaction();
    }

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        var session = SessionFactory.GetCurrentSession();
        var transaction = session.Transaction;
        if (transaction != null && transaction.IsActive)
        {
            transaction.Commit();
        }
        session = CurrentSessionContext.Unbind(SessionFactory);
        session.Close();
    }

これは私のニーズにうまく機能していました。ただし、最近、カスタム JSON.NET MediaTypeFormatter を追加して、アクションの結果の JSON をフォーマットしました。私が抱えている問題は、MediaTypeFormatter の WriteToStreamAsync がその仕事を行う前に、私の ActionFilter OnActionExecuted() メソッドが呼び出されることです。その結果、セッションが閉じられているため、遅延ロードされた (問題の) コレクションが使用できなくなります。これを処理する最善の方法は何ですか? ActionFilter の OnActionExecuted メソッドを削除して、MediaTypeFormatter でセッションを閉じる必要がありますか?

ありがとう!!

4

1 に答える 1

1

MediaTypeFormatter は、使用している特定のフォーマッタとは実際には関係がないため、セッションを閉じるには不適切なレイヤーです。これが私がすることをお勧めすることです:

  1. HttpContent から派生し、ObjectContent から派生するクラスを作成します。SerializeToStreamAsync 実装をオーバーライドして、基本実装の SerializeToStreamAsync を待機し、セッションを閉じます。

    public class SessionClosingObjectContent : ObjectContent
    {
        private Session _session;
    
        public SessionClosingObjectContent(Type type, object value, MediaTypeFormatter formatter, Session session)
            : base(type, value, formatter)
        {
            _session = session;
        }
    
        protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context)
        {
            await base.SerializeToStreamAsync(stream, context);
            // Close the session and anything else you need to do
            _session.Close();
        }
    }
    
  2. アクション フィルターで、セッションを閉じる代わりに、レスポンス Content を、セッションを閉じる新しいクラスに置き換えます。

    public class SessionManagement : ActionFilterAttribute
    {
        public SessionManagement()
        {
            SessionFactory = WebApiApplication.SessionFactory;
        }
    
        private ISessionFactory SessionFactory { get; set; }
    
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            var session = SessionFactory.OpenSession();
            CurrentSessionContext.Bind(session);
            session.BeginTransaction();
        }
    
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            var session = SessionFactory.GetCurrentSession();
            var response = actionExecutedContext.Response;
            if (response.Content != null)
            {
                ObjectContent objectContent = response.Content as ObjectContent;
                if (objectContent != null)
                {
                    response.Content = new SessionClosingObjectContent(objectContent.ObjectType, objectContent.Value, objectContent.Formatter, session);
                    foreach (KeyValuePair<string, IEnumerable<string>> header in objectContent.Headers)
                    {
                        response.Content.Headers.TryAddWithoutValidation(header.Key, header.Value);
                    }
                }
            }
        }
    }
    

代わりに、必要な場所にコントローラー コードから直接、新しいコンテンツを含む HttpResponseMessage を返すことも選択できます。

于 2013-06-10T00:43:53.867 に答える