将 Asp.Net MVC 控制器转换为 Web API 的最佳方式
Best way to convert Asp.Net MVC controllers to Web API
我有这个 ASP.NET MVC 5
项目,我正在使用 MS Web Api.
将其转换为 AngularJS
现在在旧项目中,我有这些 Controller
类型的 c# 控制器,但是在我的新项目中,我创建了一些 ApiController
类型的新 Web Api 控制器。
现在我想在我的新项目中重用旧的控制器代码。这就是我的困惑。
当我尝试将旧的控制器代码移植到我的 Web Api 控制器时,我遇到了一些前端 $http
请求错误。
这是我的 Angular dataService
工厂的一个函数,它使一个 http 请求下降到 'api/Whatif/SummaryPortfolios'
:
function getCurrPortfoliosLIst() {
var deferred = $q.defer();
var url = 'api/Whatif/SummaryPortfolios';
var req={
method: 'POST',
url: url,
headers: {
'Content-Type': 'application/json',
},
data:{}
};
$http(req).then(function (resp){
deferred.resolve(resp.data);
}, function(err){
console.log('Error from dataService: ' + resp);
});
}
但是 $http
错误部分返回了这个异常:
data: Object
ExceptionMessage: "Multiple actions were found that match the request:
↵SummaryPortfolios on type MarginWorkbenchNG.Controllers.WhatifController
↵Post on type MarginWorkbenchNG.Controllers.WhatifController"
ExceptionType: "System.InvalidOperationException"
Message: "An error has occurred."
StackTrace: " at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)
↵ at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)
↵ at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
↵ at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
这是我正在调用的 c# API 控制器,但我需要弄清楚如何创建除直接 Get() 和 Post() 方法之外的方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using Microsoft.AspNet.Identity;
using NLog;
using Microsoft.AspNet.Identity.Owin;
using MarginWorkbenchNG.Models;
using Rz.DAL;
using Rz.DAL.Integration;
using Rz.DAL.Models;
using Rz.DAL.Models.Rz;
namespace MarginWorkbenchNG.Controllers
{
public class WhatifController : ApiController
{
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
[HttpPost]
public List<WhatifSummaryViewModel> SummaryPortfolios(string filterValue = "", int? whatIfBatchNumber = null, bool includeBaseline = true)
{
// Get portfolios from Rz
IEnumerable<Portfolio> portfolios = GetPortfolios(filterValue, whatIfBatchNumber, includeBaseline)
.Where(x => x.PortfolioKeys.Any(k => k.Type == Settings.Whatif.SidebarPortfolioKey && k.DisplayValue == filterValue));
// View Model
List<WhatifSummaryViewModel> model = new List<WhatifSummaryViewModel> { };
/// additional code here...
return model;
}
}
}
旧控制器(来自 MVC5 项目)当然看起来略有不同,因为 _Summary
方法是 ActionResult
和 returns 类型 Partial
:
public class WhatifController : Controller
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult _Summary(string filterValue = "", int? whatIfBatchNumber = null, bool includeBaseline = true)
{
// Get portfolios from Razor
IEnumerable<Portfolio> portfolios = GetPortfolios(filterValue, whatIfBatchNumber, includeBaseline)
.Where(x => x.PortfolioKeys.Any(k => k.Type == Settings.Whatif.SidebarPortfolioKey && k.DisplayValue == filterValue));
// View Model
List<WhatifSummaryViewModel> model = new List<WhatifSummaryViewModel> { };
// additional code removed for brevity...
return PartialView(model.OrderBy(x => x.Title).ThenBy(x => x.SubTitle));
}
我的 RouteConfig.cs
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace MarginWorkbenchNG
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
老项目也是用Html形式拉取URL,例如:
<form id="whatif-summary-form" action="@Url.Action("_Summary", "WhatIf")" method="POST"></form>
然后在 JavaScript(非 Angular)中构建 ajax 请求时拉取 action
属性以获取 URL :
url: form.prop("action")
这是你的整个 ApiController 吗?您收到的错误消息是因为您的 ApiController 有几种相同类型的方法,它无法判断要路由到哪一种。要对此进行测试:注释掉控制器的所有方法,但您正在调用的方法除外。您不应再收到该错误。
这很容易解决,只需告诉网络 api 如何映射您的路线。将属性 '[Route("yourroute')]' 添加到你的方法中,它应该可以工作。
public class WhatifController : ApiController
{
[HttpPost, Route("Your Route Goes here 'SummaryPortfolios'")]
public IHttpActionResult SummaryPortfolios(string filterValue = "", int? whatIfBatchNumber = null, bool includeBaseline = true)
{
// Get portfolios from Rz
IEnumerable<Portfolio> portfolios = GetPortfolios(filterValue, whatIfBatchNumber, includeBaseline)
.Where(x => x.PortfolioKeys.Any(k => k.Type == Settings.Whatif.SidebarPortfolioKey && k.DisplayValue == filterValue));
// View Model
List<WhatifSummaryViewModel> model = new List<WhatifSummaryViewModel> { };
/// additional code here...
return Ok(model);
}
}
我有这个 ASP.NET MVC 5
项目,我正在使用 MS Web Api.
现在在旧项目中,我有这些 Controller
类型的 c# 控制器,但是在我的新项目中,我创建了一些 ApiController
类型的新 Web Api 控制器。
现在我想在我的新项目中重用旧的控制器代码。这就是我的困惑。
当我尝试将旧的控制器代码移植到我的 Web Api 控制器时,我遇到了一些前端 $http
请求错误。
这是我的 Angular dataService
工厂的一个函数,它使一个 http 请求下降到 'api/Whatif/SummaryPortfolios'
:
function getCurrPortfoliosLIst() {
var deferred = $q.defer();
var url = 'api/Whatif/SummaryPortfolios';
var req={
method: 'POST',
url: url,
headers: {
'Content-Type': 'application/json',
},
data:{}
};
$http(req).then(function (resp){
deferred.resolve(resp.data);
}, function(err){
console.log('Error from dataService: ' + resp);
});
}
但是 $http
错误部分返回了这个异常:
data: Object
ExceptionMessage: "Multiple actions were found that match the request:
↵SummaryPortfolios on type MarginWorkbenchNG.Controllers.WhatifController
↵Post on type MarginWorkbenchNG.Controllers.WhatifController"
ExceptionType: "System.InvalidOperationException"
Message: "An error has occurred."
StackTrace: " at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)
↵ at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)
↵ at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
↵ at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
这是我正在调用的 c# API 控制器,但我需要弄清楚如何创建除直接 Get() 和 Post() 方法之外的方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using Microsoft.AspNet.Identity;
using NLog;
using Microsoft.AspNet.Identity.Owin;
using MarginWorkbenchNG.Models;
using Rz.DAL;
using Rz.DAL.Integration;
using Rz.DAL.Models;
using Rz.DAL.Models.Rz;
namespace MarginWorkbenchNG.Controllers
{
public class WhatifController : ApiController
{
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
[HttpPost]
public List<WhatifSummaryViewModel> SummaryPortfolios(string filterValue = "", int? whatIfBatchNumber = null, bool includeBaseline = true)
{
// Get portfolios from Rz
IEnumerable<Portfolio> portfolios = GetPortfolios(filterValue, whatIfBatchNumber, includeBaseline)
.Where(x => x.PortfolioKeys.Any(k => k.Type == Settings.Whatif.SidebarPortfolioKey && k.DisplayValue == filterValue));
// View Model
List<WhatifSummaryViewModel> model = new List<WhatifSummaryViewModel> { };
/// additional code here...
return model;
}
}
}
旧控制器(来自 MVC5 项目)当然看起来略有不同,因为 _Summary
方法是 ActionResult
和 returns 类型 Partial
:
public class WhatifController : Controller
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult _Summary(string filterValue = "", int? whatIfBatchNumber = null, bool includeBaseline = true)
{
// Get portfolios from Razor
IEnumerable<Portfolio> portfolios = GetPortfolios(filterValue, whatIfBatchNumber, includeBaseline)
.Where(x => x.PortfolioKeys.Any(k => k.Type == Settings.Whatif.SidebarPortfolioKey && k.DisplayValue == filterValue));
// View Model
List<WhatifSummaryViewModel> model = new List<WhatifSummaryViewModel> { };
// additional code removed for brevity...
return PartialView(model.OrderBy(x => x.Title).ThenBy(x => x.SubTitle));
}
我的 RouteConfig.cs
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace MarginWorkbenchNG
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
老项目也是用Html形式拉取URL,例如:
<form id="whatif-summary-form" action="@Url.Action("_Summary", "WhatIf")" method="POST"></form>
然后在 JavaScript(非 Angular)中构建 ajax 请求时拉取 action
属性以获取 URL :
url: form.prop("action")
这是你的整个 ApiController 吗?您收到的错误消息是因为您的 ApiController 有几种相同类型的方法,它无法判断要路由到哪一种。要对此进行测试:注释掉控制器的所有方法,但您正在调用的方法除外。您不应再收到该错误。
这很容易解决,只需告诉网络 api 如何映射您的路线。将属性 '[Route("yourroute')]' 添加到你的方法中,它应该可以工作。
public class WhatifController : ApiController
{
[HttpPost, Route("Your Route Goes here 'SummaryPortfolios'")]
public IHttpActionResult SummaryPortfolios(string filterValue = "", int? whatIfBatchNumber = null, bool includeBaseline = true)
{
// Get portfolios from Rz
IEnumerable<Portfolio> portfolios = GetPortfolios(filterValue, whatIfBatchNumber, includeBaseline)
.Where(x => x.PortfolioKeys.Any(k => k.Type == Settings.Whatif.SidebarPortfolioKey && k.DisplayValue == filterValue));
// View Model
List<WhatifSummaryViewModel> model = new List<WhatifSummaryViewModel> { };
/// additional code here...
return Ok(model);
}
}