ServiceStack InProcessServiceGateway抛出ValidationException

时间:2017-07-09 18:11:57

标签: servicestack validationexception

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

验证功能正常,但使用InProcessServiceGateway时,失败的验证会抛出ValidationException,它会在客户端中直接导致ServiceStack.FluentValidation.ValidationException,而不是填充MyResponseDto的ResponseStatus属性。我还尝试了GlobalRequestFilters和ServiceExceptionHandlers,它们似乎只能用JsonHttpClient但InProcessServiceGateway捕获ValidationException。

有没有办法让InProcessServiceGateway抛出ValidationException并将其转换为Dto的ResponseStatus?感谢。

我的AppHost:

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

1 个答案:

答案 0 :(得分:1)

ServiceStack的服务网关现在将验证例外转换为来自this commit的WebServiceExceptions,该版本可从现在available on MyGet的v4.5.13获得。