【问题标题】:ServiceStack: Accessing the session in InsertFilter and UpdateFilterServiceStack:在 InsertFilter 和 UpdateFilter 中访问会话
【发布时间】:2016-02-25 13:45:50
【问题描述】:

我有一个 C#.net 应用程序,我在其中写入一个 sql server 数据库。 SQL Server 表都有公共记录管理列(DateCreated、DateLastUpdated、CreatedUserId 等...),我希望将这些字段的填充抽象为 InsertFilter 和 UpdateFilter。

这是 AppHost 的 Configure 方法的简化版本..

public override void Configure(Container container)
{
    ICacheClient CacheClient = new MemoryCacheClient();
    container.Register(CacheClient);

    var connectionString = ConfigurationManager.ConnectionStrings["mydb"].ConnectionString;

    container.Register<IDbConnectionFactory>(c => new OrmLiteConnectionFactory(connectionString, SqlServerDialect.Provider));

    container.Register<IUserAuthRepository>(c => new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>()));
    var authRepo = (OrmLiteAuthRepository)container.Resolve<IUserAuthRepository>();


    OrmLiteConfig.InsertFilter = (dbCmd, row) =>
    {
        var userSession = SessionFeature.GetOrCreateSession<AuthUserSession>(CacheClient);
        var recordManagementRow = row as IRecordManagement;
        if (recordManagementRow != null)
        {
            recordManagementRow.DateCreated = recordManagementRow.DateLastUpdated = DateTime.UtcNow;
            if (userSession != null)
                recordManagementRow.CreatedUserId = recordManagementRow.LastUpdatedUserId = userSession.Id.ToInt();
        }
    };
}

执行时,OrmLiteConfig.InsertFilter 委托的第一行出现以下异常。有没有人对如何检索当前用户会话 ID 以插入数据库有更好的想法?

ServiceStack.dll 中出现“System.NotImplementedException”类型的异常,但未在用户代码中处理

补充信息:此 AppHost 不支持通过 Singleton 访问当前请求

【问题讨论】:

    标签: c# servicestack ormlite-servicestack


    【解决方案1】:

    User Session 只能在请求的上下文中访问,因为它依赖于当前请求的 Session Cookies

    只有 ASP.NET 主机可以访问 HttpContext.Current 单例来访问当前请求。在尝试访问 HTTP 侦听器自身主机中的用户会话而不注入当前 HTTP Request 时,您将收到此异常,例如:

    var userSession = SessionFeature
        .GetOrCreateSession<AuthUserSession>(CacheClient, Request);
    

    我建议不要尝试像这样访问用户会话,而是在 IRecordManagement 上创建一个扩展方法,以填充类似于您的 InsertFilter 正在执行的 POCO,例如:

    db.Insert(new Record { ... }.WithAudit(Request));
    
    //Extension Method Example:
    public static class RecordManagementExtensions
    {
        public static T WithAudit<T>(this T row, IRequest req) where T : IRecordManagement => 
            row.WithAudit(Request.GetSession().UserAuthId);
    
        public static T WithAudit<T>(this T row, string userId) where T : IRecordManagement
        {
            row.UserId = userId;
            row.DateCreated = DateTime.UtcNow;
            return row;
        }
    }
    

    虽然我不建议依赖 RequestContext 单例,但您可以在这种情况下使用它来为请求过滤器中的请求设置当前 UserId,例如:

    GlobalRequestFilters.Add((req, res, requestDto) => {
        RequestContext.Instance.Items["userId"] = req.GetSession().UserAuthId;
    });
    

    然后您可以从过滤器中访问,例如:

    OrmLiteConfig.InsertFilter = (dbCmd, row) => {
        ...
        recordMgt.CreatedUserId = RequestContext.Instance.Items["userId"];
    }
    

    【讨论】:

    • 感谢 Demis,我相信您已经提供了两种解决方法 - 您建议通过 POCO 上的扩展方法进行填充,并且在此示例中还可以使用 RequestFilter 将 UserId 填充到 RequestContext 中。我不明白我怎么能接受这个建议,你介意把语法充实一下吗?
    • 仅供参考:我已经使用 RequestContext 解决方法,但我更愿意使用推荐的方法,因为它对我来说感觉更干净。
    • @Drammy 我已经更新了 Extension 方法以传入 UserSession UserId,因为这就是您所需要的。扩展方法旨在使调用站点代码更小(通过在 ext 方法中检索 UserId),因此此更改使其更加明确,但代价是每个调用站点需要更多代码。
    • 对不起,我还是不明白 - 如何向接口添加扩展方法?以为只能给静态类添加扩展方法??
    • @Drammy 扩展在静态类中定义,但this 目标可以引用任何东西,即大多数 OrmLite API 是 ADO.NET 接口上的扩展方法。我已经用一个例子更新了我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多