2014-04-09 31 views
1

我正致力於將單頁應用程序的「新項目」模板從C#轉換爲F#,並且我有一個問題:can控制器是否可以返回SomeViewModel option(或Task<SomeViewModel option>)?我可以使用ApiController操作返回ViewModel選項嗎?

這裏是我的視圖模型聲明:

module ViewModels = 
    [<CLIMutable>]   
    type ExternalLoginViewModel = 
     { Name:string; 
      Url: string; 
      State:string } 

    [<CLIMutable>] 
    type UserInfoViewModel = 
     { UserName : string; 
      HasRegistered : bool; 
      LoginProvider : string} 

    [<CLIMutable>] 
    type UserLoginInfoViewModel = 
     { LoginProvider : string; 
      ProviderKey : string } 

    [<CLIMutable>] 
    type ManageInfoViewModel = 
     { LocalLoginProvider : string; 
      UserName : string; 
      Logins : seq<UserLoginInfoViewModel>; 
      ExternalLoginProviders : seq<ExternalLoginViewModel>} 

而這裏的相關操作(在AccountController.fs)

// GET api/Account/ManageInfo?returnUrl=%2F&generateState=true 
[<Route("ManageInfo")>] 
member x.GetManageInfo (returnUrl: string, generateState: bool) = 
    async { 
     let! user = userManager.FindByIdAsync(x.User.Identity.GetUserId()) 
        |> Async.AwaitTask 
     if user = null 
     then return None 
     else 
      let logins = 
       seq { 
        for linkedAccount in user.Logins 
         do yield 
          { LoginProvider = linkedAccount.LoginProvider; 
           ProviderKey = linkedAccount.ProviderKey } 
        if user.PasswordHash <> null 
         then yield 
          { LoginProvider = localLoginProvider; 
           ProviderKey = user.UserName } 
       } 
      return Some 
       { LocalLoginProvider = localLoginProvider; 
        UserName = user.UserName; 
        Logins = logins; 
        ExternalLoginProviders = 
         x.GetExternalLogins(returnUrl, generateState)} 
    } |> Async.StartAsTask 

僅供參考,這裏的C#實現:

public class ExternalLoginViewModel 
{ 
    public string Name { get; set; } 

    public string Url { get; set; } 

    public string State { get; set; } 
} 

public class ManageInfoViewModel 
{ 
    public string LocalLoginProvider { get; set; } 

    public string UserName { get; set; } 

    public IEnumerable<UserLoginInfoViewModel> Logins { get; set; } 

    public IEnumerable<ExternalLoginViewModel> ExternalLoginProviders { get; set; } 
} 

public class UserInfoViewModel 
{ 
    public string UserName { get; set; } 

    public bool HasRegistered { get; set; } 

    public string LoginProvider { get; set; } 
} 

public class UserLoginInfoViewModel 
{ 
    public string LoginProvider { get; set; } 

    public string ProviderKey { get; set; } 
} 
// GET api/Account/ManageInfo?returnUrl=%2F&generateState=true 
[Route("ManageInfo")] 
public async Task<ManageInfoViewModel> GetManageInfo(string returnUrl, bool generateState = false) 
{ 
    IdentityUser user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 

    if (user == null) 
    { 
     return null; 
    } 

    List<UserLoginInfoViewModel> logins = new List<UserLoginInfoViewModel>(); 

    foreach (IdentityUserLogin linkedAccount in user.Logins) 
    { 
     logins.Add(new UserLoginInfoViewModel 
     { 
      LoginProvider = linkedAccount.LoginProvider, 
      ProviderKey = linkedAccount.ProviderKey 
     }); 
    } 

    if (user.PasswordHash != null) 
    { 
     logins.Add(new UserLoginInfoViewModel 
     { 
      LoginProvider = LocalLoginProvider, 
      ProviderKey = user.UserName, 
     }); 
    } 

    return new ManageInfoViewModel 
    { 
     LocalLoginProvider = LocalLoginProvider, 
     UserName = user.UserName, 
     Logins = logins, 
     ExternalLoginProviders = GetExternalLogins(returnUrl, generateState) 
    }; 
} 
+1

你試過了嗎? –

+0

我添加了一個簡單實驗的響應。 –

+0

是MVC 5嗎?它看起來像Web API ... –

回答

1

好吧,我嘗試了一個簡單的測試:兩個情況從默認ValuesController。

首先情況下,使用BadResult和Ok方法:

[<RoutePrefix("api2/values")>] 
type ValuesController() = 
    inherit ApiController() 
    let values = [|"value1";"value2"|] 

    /// Gets all values. 
    [<Route("")>] 
    member x.Get() = values 

    /// Gets the value with index id. 
    [<Route("{id:int}")>] 
    member x.Get(id) : IHttpActionResult = 
     if id > values.Length - 1 then 
      x.BadRequest() :> _ 
     else x.Ok(values.[id]) :> _ 

輸出:

  • /API2 /值/ 1 - 200 - 「VALUE2」
  • /API2 /值/ 3 - 400

第二種情況,使用字符串選項

[<RoutePrefix("api2/values")>] 
type ValuesController() = 
    inherit ApiController() 
    let values = [|"value1";"value2"|] 

    /// Gets all values. 
    [<Route("")>] 
    member x.Get() = values 

    /// Gets the value with index id. 
    [<Route("{id:int}")>] 
    member x.Get(id) = 
     if id > values.Length - 1 then 
      None 
     else Some(values.[id]) 

輸出:

  • /API2 /值/ 1 - 200 - { 「情況」: 「一些」, 「字段」:[ 「值2」]}
  • /API2 /值/ 3 - 200 - null

如此有效,這裏有兩種不同的方法來處理響應。 Some Case的開箱序列化有點冗長,但是它可以工作。

+1

儘管它使用選項,但我不會走這條路線,因爲從HTTP角度看,輸出是非慣用的。第一個選項要好得多,雖然正確的答案是404。 –

相關問題