使用RavenDB与ServiceStack(using RavenDB with ServiceS

2019-07-30 21:57发布

我看了这个帖子由菲利普·海登有关如何使用NHibernate的/ RavenDB与ServiceStack。
我没有看到有关获取每一个我需要这样的东西分贝时IDocumentStore和开放的新会话点:

public class FooService : ServiceBase<Foo>
{
    public IDocumentStore RavenStore{ get; set; }

    protected override object Run(ProductFind request)
    {
        using (var session = RavenStore.OpenSession())
        {
            // Do Something...

            return new FooResponse{/*Object init*/};
        }
    }
}

为什么不能我只是使用每个请求,请求结束时,提交更改或根据响应状态回滚他们一个会议?

如果我的做法是好的,比我怎么能实现呢? 这里是我的尝试:

我创造了这个类:

    public class RavenSession : IRavenSession
    {
        #region Data Members

        private readonly IDocumentStore _store;
        private IDocumentSession _innerSession;

        #endregion

        #region Properties

        public IDocumentSession InnerSession
        {
            get { return _innerSession ?? (_innerSession = _store.OpenSession()); }
        }

        #endregion

        #region Ctor

        public RavenSession(IDocumentStore store)
        {
            _store = store;
        }

        #endregion

        #region Public Methods

        public void Commit()
        {
            if (_innerSession != null)
            {
                try
                {
                    InnerSession.SaveChanges();
                }
                finally
                {
                    InnerSession.Dispose();
                }
            }
        }

        public void Rollback()
        {
            if (_innerSession != null)
            {
                InnerSession.Dispose();
            }
        }

        #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

    }

现在,我的服务看起来是这样的:

public class FooService : ServiceBase<Foo>
{
    public IRavenSession RavenSession { get; set; }

    protected override object Run(ProductFind request)
    {
        // Do Something with RavenSession...

        return new FooResponse {/*Object init*/};
    }
}

但我仍然需要找到一种方法来知道什么时候该请求被结束了提交/回滚的变化。
我发现最好的方法是使用ResponseFilters:

public class AppHost : AppHostBase
{
    public AppHost()
        : base("", typeof (Foo).Assembly, typeof (FooService).Assembly)
    {
    }

    public override void Configure(Container container)
    {
        // Some Configuration...

        this.ResponseFilters.Add((httpReq, httpResp, respnseDto) =>
                                     {
                                         var currentSession = (RavenSession) this.Container.Resolve<IRavenSession>();

                                         if (!httpResp.IsErrorResponse())
                                         {
                                             currentSession.Commit();
                                         }
                                         else
                                         {
                                             currentSession.Rollback();
                                         }
                                     });

        // Some Configuration...
    }
}

我相信,有一个更好的方式来做到这一点,但怎么样?

Answer 1:

我只是包括在此的配置方法为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);

你可以把它放在一边对模块进行初始化。

然后在你的服务,只需添加一个接受IDocumentSession构造

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

你是好去。



Answer 2:

滤波ServiceStack响应

内省的响应方式ServiceStack是两种:

  • 该响应滤波器或响应滤波器属性或其他自定义挂钩
  • 重写AppHost.ServiceExceptionHandler或定制OnAfterExecute()钩

其他一些注意事项可能会有所帮助:

ServiceStack的内置IOC (Funq)现在支持RequestScope

您可以添加IDisposable基类的服务已经执行完毕后立即调用,例如,如果你在使用一个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();
    }
}


Answer 3:

我试过的答案被费利佩Leusin给出,但它并没有为我工作。 我想实现的是具有单一DocumentSession.SaveChanges每个请求调用的主要事情。 看RacoonBlog DocumentSession生命周期管理,并在ServiceStack请求生命周期的事件后,我放在一起,对我的作品的配置:

    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);


Answer 4:

我使用funq与RequestScope我RavenSession,现在我把它更新到:

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
}

但这不会因为工作:
1)虽然我使用RequestScope,没有一个是注册请求的IRequestContext所以funq着解决我RavenSession。
2)该请求完成后funq不运行Dispose方法,它为奇数。



文章来源: using RavenDB with ServiceStack