using RavenDB with ServiceStack

前端 未结 4 1067
梦毁少年i
梦毁少年i 2021-02-06 13:14

I read this post by Phillip Haydon about how to use NHibernate/RavenDB with ServiceStack.
I don\'t see the point about getting the IDocumentStore and open new session every

相关标签:
4条回答
  • 2021-02-06 13:38

    I tried the answer given by Felipe Leusin but it has not worked for me. The main thing that I want to achieve is having a single DocumentSession.SaveChanges call per request. After looking at the RacoonBlog DocumentSession lifecycle management and at ServiceStack request lifecycle events I put together a configuration that works for me:

        public override void Configure(Funq.Container container)
        {
            RequestFilters.Add((httpReq, httpRes, requestDto) =>
                {
    
                    IDocumentSession documentSession = Container.Resolve<IDocumentStore>().OpenSession();
                    Container.Register<IDocumentSession>(documentSession);
                });
    
            ResponseFilters.Add((httpReq, httpRes, requestDto) =>
                {
                    using (var documentSession = Container.Resolve<IDocumentSession>())
                    {
                        if (documentSession == null)
                            return;
    
                        if (httpRes.StatusCode >= 400 && httpRes.StatusCode < 600)
                            return;
    
                        documentSession.SaveChanges();
                    }
                });
            var documentStore = new DocumentStore
                {
                    ConnectionStringName = "RavenDBServer",
                    DefaultDatabase = "MyDatabase",
                }.Initialize();
    
            container.Register(documentStore);
    
    0 讨论(0)
  • 2021-02-06 13:38

    I am using funq with RequestScope for my RavenSession, and now i update it to:

    public class RavenSession : IRavenSession, IDisposable
    {
        #region Data Members
    
        private readonly IDocumentStore _store;
        private readonly IRequestContext _context;
        private IDocumentSession _innerSession;
    
        #endregion
    
        #region Properties
    
        public IDocumentSession InnerSession
        {
            get { return _innerSession ?? (_innerSession = _store.OpenSession()); }
        }
    
        #endregion
    
        #region Ctor
    
        public RavenSession(IDocumentStore store, IRequestContext context)
        {
            _store = store;
            _context = context;
        }
    
        #endregion
    
        #region IDocumentSession Delegation
    
        public ISyncAdvancedSessionOperation Advanced
        {
            get { return InnerSession.Advanced; }
        }
    
        public void Delete<T>(T entity)
        {
            InnerSession.Delete(entity);
        }
    
        public ILoaderWithInclude<object> Include(string path)
        {
            return InnerSession.Include(path);
        }
    
        public ILoaderWithInclude<T> Include<T, TInclude>(Expression<Func<T, object>> path)
        {
            return InnerSession.Include<T, TInclude>(path);
        }
    
        public ILoaderWithInclude<T> Include<T>(Expression<Func<T, object>> path)
        {
            return InnerSession.Include(path);
        }
    
        public T Load<T>(string id)
        {
            return InnerSession.Load<T>(id);
        }
    
        public T[] Load<T>(params string[] ids)
        {
            return InnerSession.Load<T>(ids);
        }
    
        public T Load<T>(ValueType id)
        {
            return InnerSession.Load<T>(id);
        }
    
        public T[] Load<T>(IEnumerable<string> ids)
        {
            return InnerSession.Load<T>(ids);
        }
    
        public IRavenQueryable<T> Query<T, TIndexCreator>() where TIndexCreator : AbstractIndexCreationTask, new()
        {
            return InnerSession.Query<T, TIndexCreator>();
        }
    
        public IRavenQueryable<T> Query<T>()
        {
            return InnerSession.Query<T>();
        }
    
        public IRavenQueryable<T> Query<T>(string indexName)
        {
            return InnerSession.Query<T>(indexName);
        }
    
        public void Store(dynamic entity, string id)
        {
            InnerSession.Store(entity, id);
        }
    
        public void Store(object entity, Guid etag, string id)
        {
            InnerSession.Store(entity, etag, id);
        }
    
        public void Store(object entity, Guid etag)
        {
            InnerSession.Store(entity, etag);
        }
    
        public void Store(dynamic entity)
        {
            InnerSession.Store(entity);
        }
    
        #endregion
    
        #region Implementation of IDisposable
    
        public void Dispose()
        {
            if (_innerSession != null)
            {
                var httpResponse = _context.Get<IHttpResponse>();
    
                try
                {
                    if (!httpResponse.IsErrorResponse())
                    {
                        _innerSession.SaveChanges();
                    }
                }
                finally
                {
                    _innerSession.Dispose();
                }
            }
        }
    
        #endregion
    }
    

    but this would not work because:
    1) although i am using RequestScope, no one is register the IRequestContext of the request so funq cant resolve my RavenSession.
    2) funq does not run the Dispose method after the request is done, which is odd.

    0 讨论(0)
  • 2021-02-06 13:55

    Filtering the response in ServiceStack

    The ways to introspect the Response in ServiceStack is with either:

    • The Response Filter or Response Filter Attributes or other custom hooks
    • Overriding AppHost.ServiceExceptionHandler or custom OnAfterExecute() hook

    Some other notes that might be helpful:

    ServiceStack's built-in IOC (Funq) now supports RequestScope

    You can add IDisposable to a base class which gets called immediately after the service has finished executing, e.g. if you were to use an RDBMS:

    public class FooServiceBase : IService, IDisposable
    {
        public IDbConnectionFactory DbFactory { get; set; }
    
        private IDbConnection db;
        public IDbConnection Db
        {
            get { return db ?? (db = DbFactory.OpenDbConnection()); }
        }
    
        public object Any(ProductFind request)
        {
            return new FooResponse {
                Result = Db.Id<Product>(request.Id)
            };
        }
    
        public void Dispose()
        {
            if (db != null) db.Dispose();
        }
    }
    
    0 讨论(0)
  • 2021-02-06 13:56

    I just included this on the Configure method for the AppHost

    var store = new DocumentStore()
    {
        Url = "http://127.0.0.1:8080",
        DefaultDatabase = "Test"
    }.Initialize();
    
    container.Register(store);
    
    container.Register(c => c.Resolve<IDocumentStore>().OpenSession()).ReusedWithin(ReuseScope.Request);
    

    You can put it aside on module and initialize it.

    Then in your services just add a constructor that accepts IDocumentSession

    public HelloService : Service {
        private readonly IDocumentSession session;
        public HelloService(IDocumentSession session) {
            this.session = session;
        }
    }
    

    And you're good to go.

    0 讨论(0)
提交回复
热议问题