2

У меня есть проект ASP.Net Web API. Я использую NHibernate в этом проекте; Свободный NHibernate должен быть конкретным. Я обрабатываю управление сеансом NHib с помощью пользовательского ActionFilterAttribute. Это выглядит так:ASP.NET Web API - Как сохранить сеанс до тех пор, пока пользовательский MediaTypeFormatter не будет завершен?

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 моего действия. Проблема, с которой я сталкиваюсь, заключается в том, что мой метод ActionFilter OnActionExecuted() вызывается до того, как WriteToStreamAsync MediaTypeFormatter сможет выполнить эту работу. В результате получается, что лениво загруженные (проблемные) коллекции недоступны, так как сеанс закрыт. Каков наилучший способ справиться с этим? Должен ли я удалить метод OnActionExecuted ActionFilter и просто закрыть сеанс в MediaTypeFormatter?

Спасибо!

ответ

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. Теперь в фильтре действия, вместо того, чтобы закрыть сессию, вы хотите заменить содержание ответа с вашим новым классом, который закрывает сессию :

    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 с новым содержанием прямо из вашего кода контроллера, где вам это нужно.

+0

Я согласен, что добавление кода управления сеансом в MediaTypeFormatter просто неверно. Если у вас есть псевдо-код, я могу его использовать. Я не очень хорошо разбираюсь в стеке Web Api. – Nick

+0

Сообщение обновлено, надеюсь, что это поможет. –

+0

Ты потрясающий. Спасибо за это. – Nick

Смежные вопросы