2013-10-09 27 views
30

ASP.NET Web API'sini kullanma. Bir parametre boşsa, durum kodu 400'ü otomatik olarak döndürmenin bir yolu var mı? Bu question'u buldum, ancak bu, tüm yöntemlere uygulanan genel bir çözümdür, bunu her bir parametrede bir yöntem temelinde yapmak istiyorum.Web Api Gerekli Parametre

public HttpResponseMessage SomeMethod([Required] SomeNullableParameter parameter) 
{ 
    // Do stuff. 
} 
+0

Bir filtre kabul edilebilir mi? –

+0

Evet, bence beyan edici bir çözümün iyi olacağını düşünüyorum. –

cevap

15

Ben global olarak kayıtlı özel bir filtre yaratmaktı kullanarak sona erdi yaklaşımı @ "Altı Gönderme" bölümüne bakın. Filtre, 'RequiredAttribute' için tüm istek parametrelerini kontrol eder. Öznitelik bulunursa, parametrenin istekle (boş değil) geçirilip geçirilmediğini denetler ve boş durumdaysa durum kodu 400'ü döndürür. Ayrıca, gelecekteki çağrılarda yansıma isabetini önlemek için her bir istek için gerekli parametreleri saklamak amacıyla filtreye bir önbellek ekledim. Eylem bağlamı parametreleri nesneler olarak kaydettiğinden, bunun değer türleri için de çalıştığını bulmak beni şaşırttı.

DÜZENLEME - Güncelleme çözüm tecfield yorumuna dayalı

public class RequiredParametersFilter : ActionFilterAttribute 
{ 
    // Cache used to store the required parameters for each request based on the 
    // request's http method and local path. 
    private readonly ConcurrentDictionary<Tuple<HttpMethod, string>, List<string>> _Cache = 
     new ConcurrentDictionary<Tuple<HttpMethod, string>, List<string>>(); 

    public override void OnActionExecuting(HttpActionContext actionContext) 
    { 
     // Get the request's required parameters. 
     List<string> requiredParameters = this.GetRequiredParameters(actionContext);  

     // If the required parameters are valid then continue with the request. 
     // Otherwise, return status code 400. 
     if(this.ValidateParameters(actionContext, requiredParameters)) 
     { 
      base.OnActionExecuting(actionContext); 
     } 
     else 
     { 
      throw new HttpResponseException(HttpStatusCode.BadRequest); 
     } 
    } 

    private bool ValidateParameters(HttpActionContext actionContext, List<string> requiredParameters) 
    { 
     // If the list of required parameters is null or containst no parameters 
     // then there is nothing to validate. 
     // Return true. 
     if (requiredParameters == null || requiredParameters.Count == 0) 
     { 
      return true; 
     } 

     // Attempt to find at least one required parameter that is null. 
     bool hasNullParameter = 
      actionContext 
      .ActionArguments 
      .Any(a => requiredParameters.Contains(a.Key) && a.Value == null); 

     // If a null required paramter was found then return false. 
     // Otherwise, return true. 
     return !hasNullParameter; 
    } 

    private List<string> GetRequiredParameters(HttpActionContext actionContext) 
    { 
     // Instantiate a list of strings to store the required parameters. 
     List<string> result = null; 

     // Instantiate a tuple using the request's http method and the local path. 
     // This will be used to add/lookup the required parameters in the cache. 
     Tuple<HttpMethod, string> request = 
      new Tuple<HttpMethod, string>(
       actionContext.Request.Method, 
       actionContext.Request.RequestUri.LocalPath); 

     // Attempt to find the required parameters in the cache. 
     if (!this._Cache.TryGetValue(request, out result)) 
     { 
      // If the required parameters were not found in the cache then get all 
      // parameters decorated with the 'RequiredAttribute' from the action context. 
      result = 
       actionContext 
       .ActionDescriptor 
       .GetParameters() 
       .Where(p => p.GetCustomAttributes<RequiredAttribute>().Any()) 
       .Select(p => p.ParameterName) 
       .ToList(); 

      // Add the required parameters to the cache. 
      this._Cache.TryAdd(request, result); 
     } 

     // Return the required parameters. 
     return result; 
    } 

} 
+6

Önbelleğinize dikkat edin. iş parçacığı güvenli olmayan bir '' '' 'ın' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' – tecfield

+0

Bu, iç içe geçmiş alanlar/"POST" modelleri için işe yarar mı? YaniBurada parametre, [Zorunlu] 'olan alanlara sahip bir tür sınıftır. – Zero3

4

Set [:

public HttpResponseMessage SomeMethod(SomeNullableParameter parameter) 
{ 
    if (parameter == null) 
     throw new HttpResponseException(HttpStatusCode.BadRequest); 

    // Otherwise do more stuff. 
} 

ben gerçekten sadece böyle bir şey (gerekli öznitelik fark) yapmak istiyorum:

Yani, örneğin, bu şu anda ne yapıyorum olduğunu Modelinizde bir özellik üzerinde] ve ardından IsValid olup olmadığını görmek için ModelState'i kontrol edin.

Bu, tüm gerekli özelliklerin aynı anda test edilmesine izin verir.

Model validation in WebAPI

+1

Bu yaklaşımla ilgili endişelerim vardı çünkü geçersiz bir parametreden farklı bir geçersiz modeli ele almak isteyebilirim. Çalışmaya çalışıp çalışmadığını görmek için bir şans verdim. Nesne boş olduğundan, modele hiçbir zaman eklenmedi, bu nedenle doğrulama asla gerçekleşmedi. –

+0

Modelinizde isteğe bağlı parametre türünü null olarak bildirdiniz mi? NULL olmayan ilkellerde [Zorunlu] varsayılan değeri döndürür. Ayrıca, parametrelerin sıralanması önemlidir. Gerekli tüm parametreler isteğe bağlı parametrelerden önce gelmelidir. Sadece merak ediyorum, çünkü bu benim için çalışıyor. Geçersiz model ve boş parametreler arasında ayrım yapmak istiyorsanız elbette, bu tamamen alakasız. Yine de bir noktada null'u kontrol etmelisin. –

+0

İsteğe bağlı türü null olarak bildirdim. İsteğe bağlı parametrelerden önce gerekli olan parametreye sahip olmadım. –

0

asp.net çekirdek için bir çözüm ...

[AttributeUsage(AttributeTargets.Method)] 
public sealed class CheckRequiredModelAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext context) 
    { 
     var requiredParameters = context.ActionDescriptor.Parameters.Where(
      p => ((ControllerParameterDescriptor)p).ParameterInfo.GetCustomAttribute<RequiredModelAttribute>() != null).Select(p => p.Name); 

     foreach (var argument in context.ActionArguments.Where(a => requiredParameters.Contains(a.Key, StringComparer.Ordinal))) 
     { 
      if (argument.Value == null) 
      { 
       context.ModelState.AddModelError(argument.Key, $"The argument '{argument.Key}' cannot be null."); 
      } 
     } 

     if (!context.ModelState.IsValid) 
     { 
      var errors = context.ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage); 
      context.Result = new BadRequestObjectResult(errors); 
      return; 
     } 

     base.OnActionExecuting(context); 
    } 
} 

[AttributeUsage(AttributeTargets.Parameter)] 
public sealed class RequiredModelAttribute : Attribute 
{ 
} 

services.AddMvc(options => 
{ 
    options.Filters.Add(typeof(CheckRequiredModelAttribute)); 
}); 

public async Task<IActionResult> CreateAsync([FromBody][RequiredModel]RequestModel request, CancellationToken cancellationToken) 
{ 
    //... 
} 
0

kabul çözüm hataları rapor etmek kendi üzerine alır .

using System.ComponentModel.DataAnnotations; 
using System.Linq; 
using System.Web.Http.Controllers; 
using System.Web.Http.Filters; 
using System.Web.Http.ModelBinding; 

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] 
public sealed class ValidateParametersAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(HttpActionContext context) 
    { 
     var descriptor = context.ActionDescriptor; 
     if (descriptor != null) 
     { 
      var modelState = context.ModelState; 
      foreach (var parameterDescriptor in descriptor.GetParameters()) 
      { 
       EvaluateValidationAttributes(
        suppliedValue: context.ActionArguments[parameterDescriptor.ParameterName], 
        modelState: modelState, 
        parameterDescriptor: parameterDescriptor 
       ); 
      } 
     } 

     base.OnActionExecuting(context); 
    } 

    static private void EvaluateValidationAttributes(HttpParameterDescriptor parameterDescriptor, object suppliedValue, ModelStateDictionary modelState) 
    { 
     var parameterName = parameterDescriptor.ParameterName; 

     parameterDescriptor 
      .GetCustomAttributes<object>() 
      .OfType<ValidationAttribute>() 
      .Where(x => !x.IsValid(suppliedValue)) 
      .ForEach(x => modelState.AddModelError(parameterName, x.FormatErrorMessage(parameterName))); 
    } 
} 

Ardından WebApiConfig.cs yoluyla evrensel takın olabilir:

MVC5 için daha uygun bir yaklaşım böyle bir şey aka (model doğrulama yoluyla) kontrolör kolu herhangi hatalarının rapor izin vermektir
config.Filters.Add(new ValidateParametersAttribute());