我正在努力将单页应用程序的“新项目”模板从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)
};
}
答案 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]) :> _
输出:
第二种情况,使用字符串选项
[<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])
输出:
如此有效,这是处理响应的两种不同方法。某些案例的开箱即用序列化有点冗长,但它确实有效。