2017-07-09 2 views
2

J'essaie d'implémenter un modèle de passerelle de service selon le tutoriel Service Gateway pour prendre en charge le traitement en cours via InProcessServiceGateway et les appels externes via JsonServiceClient dans le cas où le service ServiceStack est déployé de manière autonome. J'utilise la version ServiceStack 4.5.8.ServiceStack InProcessServiceGateway throws ValidationException

La fonctionnalité de validation fonctionne correctement, mais avec InProcessServiceGateway, la validation échouée lève ValidationException, ce qui entraîne directement une exception ServiceStack.FluentValidation.ValidationException dans le client plutôt que le remplissage de la propriété ResponseStatus de MyResponseDto. Et j'ai également essayé GlobalRequestFilters et ServiceExceptionHandlers, les deux semblent fonctionner correctement pour capturer ValidationException seulement avec JsonHttpClient mais InProcessServiceGateway.

Y at-il un moyen de rendre ValidationException levée par InProcessServiceGateway capturé et traduit dans ResponseStatus de Dto? Merci.

Mon 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) => 
    { 
    ... 
    }); 

Mon 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; 
    } 
} 

Mon contrôleur de base client (ASP.NET Web API):

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

Mon action du contrôleur client (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); 
    } 

Ma demande de 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; } 
} 

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

Mon 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 code source InProcessServiceGateway de 4.5.8:

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

Répondre

1

Les passerelles de service de ServiceStack convertissent désormais les exceptions de validation en WebServiceExceptions de this commit qui est disponible à partir de la version 4.5.13 et qui est maintenant available on MyGet.

+0

Merci, @mythz, :), vous donnez toujours une réponse rapide et sensée. J'ai hâte d'essayer votre solution. Merci. –