5

Phillip Haydon による ServiceStack で NHibernate/RavenDB を使用する方法に関するこの投稿を読みました。
次のようなデータベースから何かが必要になるたびに、 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*/};
        }
    }
}

リクエストごとに 1 つのセッションだけを使用し、リクエストが終了したら、応答ステータスに従って変更をコミットするかロールバックすることができないのはなぜですか?

私のアプローチが問題ない場合、どのように実装できますか? ここに私の試みがあります:

私はこのクラスを作成しました:

    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...
    }
}

これを行うためのより良い方法があると確信していますが、どのように?

4

4 に答える 4

10

これをAppHostのConfigureメソッドに含めました

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

そして、あなたは行ってもいいです。

于 2012-12-07T21:54:03.527 に答える
2

ServiceStack での応答のフィルタリング

ServiceStackでResponse をイントロスペクトする方法は、次のいずれかです。

役立つかもしれないその他のメモ:

ServiceStack の組み込み IOC (Funq) が RequestScope をサポートするようになりました

IDisposableRDBMS を使用する場合など、サービスの実行が終了した直後に呼び出される基本クラスに追加できます。

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();
    }
}
于 2012-08-10T16:41:51.853 に答える
1

Felipe 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);
于 2013-01-04T15:22:47.130 に答える
0

RavenSession の RequestScope で funq を使用していますが、次のように更新します。

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 メソッドを実行しません。これは奇妙です。

于 2012-08-11T00:36:52.683 に答える