2015-01-26 14 views
13

Tôi đã chuyển đổi dự án C# webapi thành F # bằng cách sử dụng mẫu F # ASP.NET. Mọi thứ đều hoạt động tốt ngoại trừ các tham số truy vấn tùy chọn. Tôi cứ bị lỗi nàySử dụng tham số truy vấn tùy chọn trong dự án F # Web Api

{ 
    "message": "The request is invalid.", 
    "messageDetail": "The parameters dictionary contains an invalid entry for parameter 'start' for method 'System.Threading.Tasks.Task`1[System.Net.Http.HttpResponseMessage] GetVendorFiles(Int32, System.Nullable`1[System.DateTime])' in 'Thor.WebApi.VendorFilesController'. The dictionary contains a value of type 'System.Reflection.Missing', but the parameter requires a value of type 'System.Nullable`1[System.DateTime]'." 
} 

F # chức năng chữ ký:

[<HttpGet; Route("")>] 
member x.GetVendorFiles([<Optional; DefaultParameterValue(100)>] count, [<Optional; DefaultParameterValue(null)>] start : Nullable<DateTime>) = 

C# chức năng chữ ký:

[HttpGet] 
[Route("")] 
public async Task<HttpResponseMessage> GetVendorFiles(int count = 100,DateTime? start = null) 

Có ai biết về bất kỳ cách giải quyết?

Đã cập nhật: Tôi đã tìm ra nguyên nhân của vấn đề này. ASP.NET trích xuất các giá trị mặc định cho các hoạt động của bộ điều khiển using ParameterInfo. Rõ ràng trình biên dịch F # không biên dịch các giá trị mặc định giống như C# (ngay cả với DefaultParameterValueAttribute)

Cách tốt nhất hoặc làm việc xung quanh điều này là gì? Nó có phải là một số bộ lọc mà tôi cần phải tiêm hoặc thực hiện của riêng tôi ParameterBinding?

+0

bạn có thể chỉ định tham số mặc định trong một tuyến đường cụ thể cho phương pháp điều khiển không? 'routes.MapRoute (tên:" Mặc định ", url:" MyController/GetVendorFiles/{count}/{start} ", mặc định: new {count = 100, start = (DateTime?) null});' – DLeh

+0

@DLeh Not thực sự vì ứng dụng giao diện người dùng hiện tại đang sử dụng tính và bắt đầu làm tham số truy vấn (không phải thông số tuyến đường) nên tôi muốn nó tương thích với mã hiện có. Trường hợp xấu nhất tôi có thể thay đổi nó thành rằng – Pavel

+1

Chỉ cần nhận thấy rằng @Pavel đã nêu lên điều này như là một [vấn đề Mvc] (https://github.com/aspnet/Mvc/issues/1923). Vấn đề này có thêm thảo luận và cách giải quyết khác. – bentayloruk

Trả lời

1

Bạn có khá nhiều giới hạn đối với cách giải quyết, có vẻ như vậy.

gì về việc sử dụng:

[<HttpGet; Route("")>] 
member x.GetVendorFiles(count: Nullable<int>, start : Nullable<DateTime>) = 
    let count' = 
     if obj.ReferenceEquals(count,null) 
      then 100 
      else count.Value 

    // continue with action logic, using count' instead of count 
+0

Đó là hợp lệ và tôi đã thử điều đó, nhưng vấn đề là nếu bạn không chỉ định tham số truy vấn bắt đầu, tôi nhận được lỗi ở trên, tức là nó tìm thấy tuyến đường nhưng vì phản ánh gây ra lỗi đó trước khi xử lý mã. – Pavel

2

Bạn có thể làm việc xung quanh điều này với một tùy chỉnh ActionFilterAttribute thực hiện. Mã sau đây hỗ trợ việc sử dụng các giá trị DefaultParameterValue khi đối số hành động bị thiếu và khi đối số hành động có giá trị loại System.Reflection.Missing.

Mã cũng nằm trong Gist ActionFilter for ASP.NET Web API DefaultParameterValue support in F#.

namespace System.Web.Http 

open System.Reflection 
open System.Web.Http.Filters 
open System.Web.Http.Controllers 
open System.Runtime.InteropServices 

/// Responsible for populating missing action arguments from DefaultParameterValueAttribute values. 
/// Created to handle this issue https://github.com/aspnet/Mvc/issues/1923 
/// Note: This is for later version of System.Web.Http but could be back-ported. 
type DefaultParameterValueFixupFilter() = 
    inherit ActionFilterAttribute() 
    /// Get list of (paramInfo, defValue) tuples for params where DefaultParameterValueAttribute is present. 
    let getDefParamVals (parameters:ParameterInfo array) = 
    [ for param in parameters do 
     let defParamValAttrs = param.GetCustomAttributes<DefaultParameterValueAttribute>() |> List.ofSeq 
     match defParamValAttrs with 
     // Review: we are ignoring null defaults. Is this correct? 
     | [x] -> if x.Value = null then() else yield param, x.Value 
     | [] ->() 
     | _ -> failwith "Multiple DefaultParameterValueAttribute on param '%s'!" param.Name 
    ] 
    /// Add action arg default values where specified in DefaultParameterValueAttribute attrs. 
    let addActionArgDefsFromDefParamValAttrs (context:HttpActionContext) = 
    match context.ActionDescriptor with 
    | :? ReflectedHttpActionDescriptor as ad -> 
     let defParamVals = getDefParamVals (ad.MethodInfo.GetParameters()) 
     for (param, value) in defParamVals do 
     match context.ActionArguments.TryGetValue(param.Name) with 
     | true, :? System.Reflection.Missing 
     | false, _ -> 
      // Remove is null-op if key not found, so we handle both match cases OK. 
      let _ = context.ActionArguments.Remove(param.Name) 
      context.ActionArguments.Add(param.Name, value) 
     | _, _ ->() 
    | _ ->() 
    /// Override adding suport for DefaultParameterValueAttribute values. 
    override x.OnActionExecuting(context) = 
    addActionArgDefsFromDefParamValAttrs context 
    base.OnActionExecuting(context) 
    /// Override adding suport for DefaultParameterValueAttribute values. 
    override x.OnActionExecutingAsync(context, cancellationToken) = 
    addActionArgDefsFromDefParamValAttrs context 
    base.OnActionExecutingAsync(context, cancellationToken) 
2

Bạn có thể sử dụng HttpRequestMessage và phân tích từ điển chuỗi truy vấn.

EDITED ...

Để sử dụng HttpRequestMessage, giả sử bạn có một trang chuỗi truy vấn:

[<Route("api/Applications")>] 
[<HttpGet()>] 
member x.Get (message:HttpRequestMessage) = 
    let page = GetQueryStringParameter(message, "page") 

tôi có lẽ sẽ sử dụng một phương pháp helper để phân tích chuỗi truy vấn ra khỏi HttpRequestMessage, một cái gì đó như thế này:

let GetQueryStringParameter (message:HttpRequestMessage, value) = 
    let value = List.ofSeq (message.GetQueryNameValuePairs()) 
       |> List.tryFind (fun item -> item.Key = value) 
    match value with 
    | Some x -> x.Value 
    | None -> "" 
+0

Bạn có thể làm ví dụ không? – slfan

Các vấn đề liên quan