2014-04-09 30 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。 –

相关问题