F# 我可以使用ApiController操作返回ViewModel选项吗?

F# 我可以使用ApiController操作返回ViewModel选项吗?,f#,asp.net-mvc-5,F#,Asp.net Mvc 5,我正在将单页应用程序的“新项目”模板从C#转换为F#,我有一个问题:控制器能否返回SomeViewModel选项(或任务) 以下是我的视图模型声明: 模块视图模型= [] 类型ExternalLoginViewModel= {Name:string; Url:string; 状态:string} [] 输入UserInfoViewModel= {用户名:字符串; 注册号:bool; 登录提供者:字符串} [] 输入UserLoginInfoViewModel= {LoginP

我正在将单页应用程序的“新项目”模板从C#转换为F#,我有一个问题:控制器能否返回
SomeViewModel选项
(或
任务

以下是我的视图模型声明:

模块视图模型=
[]         
类型ExternalLoginViewModel=
{Name:string;
Url:string;
状态:string}
[]
输入UserInfoViewModel=
{用户名:字符串;
注册号:bool;
登录提供者:字符串}
[]
输入UserLoginInfoViewModel=
{LoginProvider:string;
ProviderKey:string}
[]
类型ManageInfoViewModel=
{LocalLoginProvider:string;
用户名:字符串;
登录:seq;
外部登录提供者:seq}
下面是相关操作(在AccountController.fs中)

//获取api/Account/ManageInfo?返回URL=%2F&generateState=true
[]
成员x.GetManageInfo(返回URL:string,generateState:bool)=
异步的{
让!user=userManager.FindByIdAsync(x.user.Identity.GetUserId())
|>异步任务
如果user=null
然后返回None
其他的
让登录=
序号{
用于user.Logins中的linkedAccount
屈服
{LoginProvider=linkedAccount.LoginProvider;
ProviderKey=linkedAccount.ProviderKey}
如果user.PasswordHash为null
然后屈服
{LoginProvider=localLoginProvider;
ProviderKey=user.UserName}
}
还一些
{LocalLoginProvider=LocalLoginProvider;
用户名=user.UserName;
登录=登录;
外部登录提供者=
x、 GetExternalLogins(返回URL,GenerateEstate)}
}|>Async.startask
以下是C#实现,以供参考:

公共类外部LoginView模型
{
公共字符串名称{get;set;}
公共字符串Url{get;set;}
公共字符串状态{get;set;}
}
公共类ManageInfoViewModel
{
公共字符串LocalLoginProvider{get;set;}
公共字符串用户名{get;set;}
公共IEnumerable登录名{get;set;}
公共IEnumerable ExternalLoginProviders{get;set;}
}
公共类UserInfoViewModel
{
公共字符串用户名{get;set;}
公共bool已注册{get;set;}
公共字符串登录提供程序{get;set;}
}
公共类UserLoginInfoViewModel
{
公共字符串登录提供程序{get;set;}
公共字符串提供程序密钥{get;set;}
}
//获取api/Account/ManageInfo?返回URL=%2F&generateState=true
[路线(“管理信息”)]
公共异步任务GetManageInfo(字符串returnUrl,bool generateState=false)
{
IdentityUser user=wait UserManager.FindByIdAsync(user.Identity.GetUserId());
if(user==null)
{
返回null;
}
列表登录名=新列表();
foreach(user.Logins中的IdentityUserLogin linkedAccount)
{
添加(新的UserLoginInfoViewModel)
{
LoginProvider=linkedAccount.LoginProvider,
ProviderKey=linkedAccount.ProviderKey
});
}
if(user.PasswordHash!=null)
{
添加(新的UserLoginInfoViewModel)
{
LoginProvider=LocalLoginProvider,
ProviderKey=user.UserName,
});
}
返回新的ManageInfoViewModel
{
LocalLoginProvider=LocalLoginProvider,
UserName=user.UserName,
登录=登录,
ExternalLoginProviders=GetExternalLogins(返回URL,GenerateEstate)
};
}

好吧,我尝试了一个简单的测试:来自默认值控制器的两个案例

第一种情况,使用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]) :> _
[]
类型值控制器()=
继承ApiController()
让值=[|“value1”;“value2”|]
///获取所有值。
[]
成员x.Get()=值
///获取索引id为的值。
[]
成员x.Get(id):IHttpActionResult=
如果id>values.Length-1,则
x、 BadRequest():>_
else x.Ok(值。[id]):>_
输出:

  • /api2/values/1-200-“value2”
  • /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]) 
[]
类型值控制器()=
继承ApiController()
让值=[|“value1”;“value2”|]
///获取所有值。
[]
成员x.Get()=值
///获取索引id为的值。
[]
成员x.Get(id)=
如果id>values.Length-1,则
没有一个
其他一些(值。[id])
输出:

  • /api2/values/1-200-{“Case”:“Some”,“Fields”:[“value2”]}
  • /api2/values/3-200-空

因此,有效地,这里有两种不同的方法来处理响应。somecase的开箱即用序列化有点冗长,但它可以工作。

我为一个简单的实验添加了一个响应。是MVC5吗?对我来说,它看起来像Web API…好吧,你明白了,它是MVC 5附带的WebAPI 2。在这种情况下,我认为你自己提供的答案实际上很好地回答了这个问题(+1):)虽然它使用选项工作,但我不会走这条路线,因为从HTTP的角度来看,输出是非惯用的。第一个选项要好得多,尽管正确的响应应该是404。
[<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])