2

我正在尝试根据服务网关教程实现服务网关模式,以支持通过 InProcessServiceGateway 进行进程内处理,并通过 JsonServiceClient 进行外部调用,以防 ServiceStack 服务独立部署。我使用 ServiceStack 4.5.8 版本。

验证功能可以正常工作,但使用 InProcessServiceGateway,失败的验证会引发 ValidationException,这会直接导致客户端中的 ServiceStack.FluentValidation.ValidationException,而不是填充 MyResponseDto 的 ResponseStatus 属性。而且我还尝试了 GlobalRequestFilters 和 ServiceExceptionHandlers,它们似乎都可以很好地仅使用 JsonHttpClient 但 InProcessServiceGateway 捕获 ValidationException。

有什么办法可以让 InProcessServiceGateway 抛出的 ValidationException 被捕获并转换成 Dto 的 ResponseStatus?谢谢。

我的应用主机:

   //Register CustomServiceGatewayFactory
   container.Register<IServiceGatewayFactory>(x => new CustomServiceGatewayFactory()).ReusedWithin(ReuseScope.None);

   //Validation feature
   Plugins.Add(new ValidationFeature());

   //Note: InProcessServiceGateway cannot reach here.
   GlobalRequestFilters.Add((httpReq, httpRes, requestDto) =>
   {
     ...
   });

   //Note: InProcessServiceGateway cannot reach here.
   ServiceExceptionHandlers.Add((httpReq, request, ex) =>
   {
     ...
   });

我的 CustomServiceGatewayFactory:

public class CustomServiceGatewayFactory : ServiceGatewayFactoryBase
{
    private IRequest _req;

    public override IServiceGateway GetServiceGateway(IRequest request)
    {
        _req = request;

        return base.GetServiceGateway(request);
    }

    public override IServiceGateway GetGateway(Type requestType)
    {
        var standaloneHosted = false;
        var apiBaseUrl = string.Empty;

        var apiSettings = _req.TryResolve<ApiSettings>();
        if (apiSettings != null)
        {
            apiBaseUrl = apiSettings.ApiBaseUrl;
            standaloneHosted = apiSettings.StandaloneHosted;
        }

        var gateway = !standaloneHosted
            ? (IServiceGateway)base.localGateway
            : new JsonServiceClient(apiBaseUrl)
            {
                BearerToken = _req.GetBearerToken()
            };
        return gateway;
    }
}

我的客户端控制器(ASP.NET Web API):

    public virtual IServiceGateway ApiGateway
    {
        get
        {
            var serviceGatewayFactory = HostContext.AppHost.TryResolve<IServiceGatewayFactory>();
            var serviceGateway = serviceGatewayFactory.GetServiceGateway(HttpContext.Request.ToRequest());
            return serviceGateway;
        }
    }

我的客户端控制器操作(ASP.NET Web API):

    var response = ApiGateway.Send<UpdateCustomerResponse>(new UpdateCustomer
    {
        CustomerGuid = customerGuid,
        MobilePhoneNumber = mobilePhoneNumber 
        ValidationCode = validationCode
    });

    if (!response.Success)
    {
        return this.Error(response, response.ResponseStatus.Message);
    }

我的 UpdateCustomer 请求 DTO:

[Route("/customers/{CustomerGuid}", "PUT")]
public class UpdateCustomer : IPut, IReturn<UpdateCustomerResponse>
{
    public Guid CustomerGuid { get; set; }

    public string MobilePhoneNumber { get; set; }

    public string ValidationCode { get; set; }
}

我的 UpdateCustomerValidator:

public class UpdateCustomerValidator : AbstractValidator<UpdateCustomer>
{
    public UpdateCustomerValidator(ILocalizationService localizationService)
    {
        ValidatorOptions.CascadeMode = CascadeMode.StopOnFirstFailure;

        RuleFor(x => x.ValidationCode)
            .NotEmpty()
            .When(x => !string.IsNullOrWhiteSpace(x.MobilePhoneNumber))
            .WithErrorCode(((int)ErrorCode.CUSTOMER_VALIDATIONCODE_EMPTY).ToString())
            .WithMessage(ErrorCode.CUSTOMER_VALIDATIONCODE_EMPTY.GetLocalizedEnum(localizationService, Constants.LANGUAGE_ID));
    }
}

我的 UpdateCustomerResponse DTO:

public class UpdateCustomerResponse
{
    /// <summary>
    /// Return true if successful; return false, if any error occurs.
    /// </summary>
    public bool Success { get; set; }

    /// <summary>
    /// Represents error details, populated only when any error occurs.
    /// </summary>
    public ResponseStatus ResponseStatus { get; set; }
}

ServiceStack 4.5.8 的 InProcessServiceGateway 源代码:

private TResponse ExecSync<TResponse>(object request)
{
    foreach (var filter in HostContext.AppHost.GatewayRequestFilters)
    {
        filter(req, request);
        if (req.Response.IsClosed)
            return default(TResponse);
    }

    if (HostContext.HasPlugin<ValidationFeature>())
    {
        var validator = ValidatorCache.GetValidator(req, request.GetType());
        if (validator != null)
        {
            var ruleSet = (string)(req.GetItem(Keywords.InvokeVerb) ?? req.Verb);
            var result = validator.Validate(new ValidationContext(
                request, null, new MultiRuleSetValidatorSelector(ruleSet)) {
                Request = req
            });
            if (!result.IsValid)
                throw new ValidationException(result.Errors);
        }
    }

    var response = HostContext.ServiceController.Execute(request, req);
    var responseTask = response as Task;
    if (responseTask != null)
        response = responseTask.GetResult();

    return ConvertToResponse<TResponse>(response);
}
4

1 回答 1

1

ServiceStack 的服务网关现在将验证异常转换为来自此提交的 WebServiceExceptions,该提交可从 v4.5.13 获得,现在可在 MyGet 上获得

于 2017-07-10T19:55:57.133 回答