要修改 TMVCActiveRecordMiddleware
以直接接受一个匿名函数(用于动态决定数据库连接)以及一个配置文件名,你需要对构造函数进行一些调整。这可以通过重载构造函数以接收另一个参数——匿名函数来实现。
构造函数修改步骤
假设你的目标是允许传入一个匿名函数,用于在运行时选择数据库连接名称。对于 FireDAC 的 ActiveRecord 支持,你可能需要一个逻辑,在中间件初始化时通过连接配置文件动态加载连接定义。
以下是如何修改和添加新的构造函数:
- 定义合适的匿名函数类型:假设你希望使用
TFunc<TWebContext, string>
类型的函数来动态提供数据库连接定义名称。 - 修改构造函数以接受匿名函数:添加新的构造函数。
修改后的代码
type
// 新增的匿名函数类型,用于获取连接定义名称
TConnectionDefNameResolver = reference to function(AContext: TWebContext): string;
TMVCActiveRecordMiddleware = class(TInterfacedObject, IMVCMiddleware)
private
fDefaultConnectionDefName: string;
fConnectionDefFileName: string;
fConnectionLoaded: Boolean;
fResolver: TConnectionDefNameResolver; // 新增成员
protected
procedure EnsureConnection(AContext: TWebContext);
// ...
public
// 新的构造函数,接收匿名函数
constructor Create(
const Resolver: TConnectionDefNameResolver;
const ConnectionDefFileName: string = 'FDConnectionDefs.ini'); overload;
// ...
end;
constructor TMVCActiveRecordMiddleware.Create(
const Resolver: TConnectionDefNameResolver;
const ConnectionDefFileName: string);
begin
inherited Create;
fConnectionLoaded := False;
fResolver := Resolver; // 赋值匿名函数
fConnectionDefFileName := ConnectionDefFileName;
end;
procedure TMVCActiveRecordMiddleware.EnsureConnection(AContext: TWebContext);
var
ConnectionDefName: string;
begin
if fConnectionLoaded then
begin
Exit;
end;
TMonitor.Enter(Self);
try
if fConnectionLoaded then
begin
Exit;
end;
if TInterlocked.CompareExchange(gCONNECTION_DEF_FILE_LOADED, 1, 0) = 0 then
begin
FDManager.ConnectionDefFileAutoLoad := False;
FDManager.ConnectionDefFileName := fConnectionDefFileName;
if not FDManager.ConnectionDefFileLoaded then
begin
FDManager.LoadConnectionDefFile;
end;
end;
// 使用匿名函数动态获取连接定义名称
if Assigned(fResolver) then
begin
ConnectionDefName := fResolver(AContext);
if FDManager.IsConnectionDef(ConnectionDefName) then
begin
ActiveRecordConnectionsRegistry.AddDefaultConnection(ConnectionDefName);
end
else
begin
raise EMVCConfigException.CreateFmt('ConnectionDefName "%s" not found in config file "%s"',
[ConnectionDefName, FDManager.ActualConnectionDefFileName]);
end;
end;
fConnectionLoaded := True;
finally
TMonitor.Exit(Self);
end;
end;
procedure TMVCActiveRecordMiddleware.OnBeforeRouting(AContext: TWebContext; var AHandled: Boolean);
begin
// 用于确保每次请求都动态评价连接名
EnsureConnection(AContext);
AHandled := False;
end;
在 Web Module 中的配置
使用这个新的构造函数,可以在 WebModuleCreate
中注册中间件:
procedure TMyWebModule.WebModuleCreate(Sender: TObject);
begin
FMVC := TMVCEngine.Create(Self,
procedure(Config: TMVCConfig)
begin
// 通用配置
end);
// 注册中间件并传递匿名函数
FMVC.AddMiddleware(TMVCActiveRecordMiddleware.Create(
function(AContext: TWebContext): string
var
DBIdentifier: string;
begin
// 身份认证的检查
if not AContext.LoggedUser.IsValid then
raise EMVCException.Create(HTTP_STATUS.Unauthorized, 'Unauthorized access');
// 从请求中确定数据库名称
DBIdentifier := AContext.Request.BodyParam('database_name');
if DBIdentifier = '' then
raise EMVCException.Create(HTTP_STATUS.BadRequest, 'Database name must be provided');
if not IsDatabaseAllowed(DBIdentifier) then
raise EMVCException.Create(HTTP_STATUS.Forbidden, 'Access to this database is not allowed');
Result := DBIdentifier; // 返回有效的连接定义名称
end,
'FDConnectionDefs.ini' // 连接定义文件
));
// 其他中间件注册和配置
end;
注意事项
- 错误处理:确保在匿名函数中和配置检查中有适当的错误处理机制。
- 线程安全:考虑多线程环境下对连接的访问和修改是否安全。
- 性能:确保在高并发环境下性能最佳,尽量减少锁定时间和资源占用。
通过这些修改,你可以让 TMVCActiveRecordMiddleware
更加灵活地根据请求上下文动态选择数据库连接。