ServiceStack:访问 InsertFilter 和 UpdateFilter 中的会话

ServiceStack: Accessing the session in InsertFilter and UpdateFilter

我有一个 C#.net 应用程序,我在其中写入 sql 服务器数据库。 SQL 服务器表都有公共记录管理列(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 以插入数据库有更好的想法?

An exception of type 'System.NotImplementedException' occurred in ServiceStack.dll but was not handled in user code

Additional information: This AppHost does not support accessing the current Request via a Singleton

当前请求的User Session can only be accessed within the context of a request since it's dependent on the Session Cookies

只有 ASP.NET 主机有权访问 HttpContext.Current 单例来访问当前请求。在不注入当前 HTTP Request 的情况下尝试访问 HTTP Listener Self Hosts 中的用户会话时,您将遇到此异常,例如:

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

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

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