我可以让ApiController操作返回ViewModel选项吗?

时间:2014-04-09 12:43:24

标签: f# asp.net-mvc-5

我正在努力将单页应用程序的“新项目”模板从C#转换为F#,我有一个问题:控制器可以返回SomeViewModel option(或Task<SomeViewModel option>)吗?

这是我的视图模型声明:

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 :(得分: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 / values / 1 - 200 - &#34; value2&#34;
  • / api2 / values / 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 / values / 1 - 200 - {&#34; Case&#34;:&#34; Some&#34;,&#34; Fields&#34;:[&#34; value2&#34;] }
  • / api2 / values / 3 - 200 - null

如此有效,这是处理响应的两种不同方法。某些案例的开箱即用序列化有点冗长,但它确实有效。