【问题标题】:Best way to convert Asp.Net MVC controllers to Web API将 Asp.Net MVC 控制器转换为 Web API 的最佳方法
【发布时间】:2016-03-05 00:24:25
【问题描述】:

我有这个 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 并返回 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")

【问题讨论】:

  • 请发布您的路由配置?
  • @lrb - 我在帖子底部发布了我的RouteConfig.cs。

标签: asp.net-mvc asp.net-web-api asp.net-web-api2


【解决方案1】:

这是你的整个 ApiController 吗?您收到的错误消息是因为您的 ApiController 具有多个相同类型的方法,并且无法确定路由到哪一个。要对此进行测试:注释掉除您正在调用的控制器之外的所有控制器方法。您不应再收到该错误。

这是一个简单的解决方法,只需告诉 web 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/web-api/overview/web-api-routing-and-actions/…,我相信我用 [HttpPost, Route("WhatIfController/GetSummaryPortfolios")] 装饰了我的 SummaryPortfolios(0 方法。看起来正确吗?
  • @bob 如果它是一个 GET 方法,那么你不应该用 HttpPost 来装饰它。只需删除 HttpPost 属性即可。
  • 我希望大部分内容都是 POST。我还看到 WebApi 2 在命名路由方面具有更大的灵活性。这非常有用。我将有很多方法可以调用,因为我正在从 Asp.Net MVC“网页”转换为 AngularJS/WebApi。
  • 真正的答案是从一个新的Web Api 项目开始,而不是关心从 MVC 的“转换”。 Web Api 项目允许我设置我的 REST 端点,并从 JavaScript 中清除 $http 发布请求。
  • 旧的,但我也会从路由中删除 Controller (WhatIf/SummaryPortfolios)
猜你喜欢
  • 1970-01-01
  • 2010-09-17
  • 2015-05-30
  • 2016-08-30
  • 2013-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多