Переход от ASP.NET Web API 2 в MVC 6

Steve Smith

ASP.NET Web API 2 был отделен от ASP.NET MVC 5, и каждый использовал свои собственные библиотеки для работы с зависимостями, не считая других отличий. В MVC 6 Web API объединился с MVC, что предоставило простой, последовательный способ построения веб приложения. В этой статье мы покажем вам этапы, требуемые для перехода от ASP.NET Web API 2 к MVC 6.

В этой статье:

Вы можете просмотреть исходный код проекта для данной статьи на GitHub.

Изучение Web API 2 проекта

В этой статье мы используем проект ProductsApp, созданный для статьи Getting Started with ASP.NET Web API 2 (C#). Здесь простой Web API 2 проект настроен следующим образом.

В Global.asax.cs вызывается WebApiConfig.Register:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Routing;

namespace ProductsApp
{
    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            GlobalConfiguration.Configure(WebApiConfig.Register);
        }
    }
}

В WebApiConfig определен App_Start, у которого есть один статический метод Register:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

namespace ProductsApp
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}

Этот класс настраивает роутинг атрибутов, хотя он на самом деле не используется в проекте, также как и таблица маршрутизации, которую использует Web API 2. В данном случае Web API ожидает URL, которые соответствуют формату /api/{controller}/{id}, где {id} является дополнительным параметром.

Проект ProductsApp включает в себя один простой контроллер, который наследуется от ApiController и имеет два метода:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using ProductsApp.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Http;

namespace ProductsApp.Controllers
{
    public class ProductsController : ApiController
    {
        Product[] products = new Product[] 
        { 
            new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, 
            new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, 
            new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } 
        };

        public IEnumerable<Product> GetAllProducts()
        {
            return products;
        }

        public IHttpActionResult GetProduct(int id)
        {
            var product = products.FirstOrDefault((p) => p.Id == id);
            if (product == null)
            {
                return NotFound();
            }
            return Ok(product);
        }
    }
}

Наконец, есть модель, Product, используемая ProductsApp, является простым классом:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
namespace ProductsApp.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Category { get; set; }
        public decimal Price { get; set; }
    }
}

У нас есть простой проект, и я покажу вам, как перенести проект Web API 2 в ASP.NET MVC 6.

Создание целевого проекта

С помощью Visual Studio 2015 создайте новое “empty” решение и добавьте в него существующий проект ProductsApp. Далее, добавьте в решение новый Web Project. Назовите его ‘ProductsDnx’.

../_images/add-web-project.png

Далее, выберите шаблон ASP.NET 5 Web API. Мы перенесем контекст ProductsApp в этот новый проект.

../_images/aspnet-5-webapi.png

Удалите файл Project_Readme.html из нового проекта. Теперь ваше решение должно выглядеть вот так:

../_images/webapimigration-solution.png

Перенос конфигурации

ASP.NET 5 больше не использует папки global.asax, web.config или App_Start. Вместо этого все задачи по запуску решаются в классе Startup.cs корневой директории проекта, а статические конфигурационные файлы при надобности могут быть получены отсюда (См. Запуск приложения ASP.NET 5). Поскольку Web API сейчас встроен в MVC 6, у нас нет необходимости его настраивать. Атрибутивный роутинг сейчас включается по умолчанию при вызове UseMvc(), и я рекомендую использовать данный подход для настройки Web API роутов.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace ProductsDnx
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            // Set up configuration sources.
            var builder = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json")
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        public IConfigurationRoot Configuration { get; set; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();

            app.UseIISPlatformHandler();

            app.UseStaticFiles();

            app.UseMvc();
        }

        // Entry point for the application.
        public static void Main(string[] args) => WebApplication.Run<Startup>(args);
    }
}

Если вы хотите в проекте и дальше использовать атрибутивный роутинг, вам не нужно дальше настраивать конфигурацию. Вы можете просто использовать атрибуты, которые нужны вашим контроллерам и методам действия, как сделано в примере класса ValuesController.cs, который включен в начальный проект Web API:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Mvc;

namespace ProductsDnx.Controllers
{
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        // GET: api/values
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public string Get(int id)
        {
            return "value";
        }

        // POST api/values
        [HttpPost]
        public void Post([FromBody]string value)
        {
        }

        // PUT api/values/5
        [HttpPut("{id}")]
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }
}

Обратите внимание на присутствие [controller] на строке 8. Атрибутивный роутинг теперь поддерживает конкретные токены, например, [controller] и [action], которые во время рантайма заменятся на имя контроллера или действия к которым применяется атрибут. Это уменьшает число магических строк в проекте, и роуты будут синхронизированы с соответствующими контроллерами и методами действий при применении автоматического рефакторинга именований.

Чтобы перенести контроллер Products API, мы сперва должны скопировать ProductsController в новый проект, а затем просто добавить в контроллер атрибут роута:

[Route("api/[controller]")]

Также нам нужно добавить атрибут [HttpGet] в два метода, поскольку они оба будут вызываться через HTTP Get. Добавьте заменитель для параметра “id” в атрибут для GetProduct():

// /api/products
[HttpGet]
...

// /api/products/1
[HttpGet("{id}")]

Теперь маршрутизация настроена корректно, но мы не можем это протестировать, поскольку мы должны внести некоторые изменения, прежде чем скомпилируется ProductsController.

Перенос моделей и контроллеров

Теперь мы должны скопировать в Web API проект нужные контроллеры и модели. В данном случае просто скопируйте Controllers/ProductsController.cs из оригинального проекта в новый. Далее скопируйте всю папку Models из оригинального проекта в новый. Пространства имен должны соответствовать имени нового проекта (ProductsDnx). Теперь мы можем собрать приложение, и у вас появятся несколько ошибок компиляции. Они подпадают под три категории:

  • ApiController не существует
  • System.Web.Http не существует
  • IHttpActionResult не существует
  • NotFound не существует
  • Ok не существует

К счастью, это легко исправить:

  • Измените ApiController на Controller (вам нужно добавить using Microsoft.AspNet.Mvc)
  • Уберите все выражения using, касающиеся System.Web.Http
  • Измените все методы, возвращающие IHttpActionResult, чтобы они возвращали IActionResult
  • Измените NotFound на HttpNotFound
  • Измените Ok(product) на new ObjectResult(product)

После этих изменений класс ProductsController выглядит вот так:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using Microsoft.AspNet.Mvc;
using ProductsDnx.Models;
using System.Collections.Generic;
using System.Linq;

namespace ProductsDnx.Controllers
{
    [Route("api/[controller]")]
    public class ProductsController : Controller
    {
        Product[] products = new Product[] 
        { 
            new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, 
            new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, 
            new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } 
        };

        // /api/products
        [HttpGet]
        public IEnumerable<Product> GetAllProducts()
        {
            return products;
        }

        // /api/products/1
        [HttpGet("{id}")]
        public IActionResult GetProduct(int id)
        {
            var product = products.FirstOrDefault((p) => p.Id == id);
            if (product == null)
            {
                return HttpNotFound();
            }
            return new ObjectResult(product);
        }
    }
}

Теперь вы можете запустить проект и перейти к /api/products, и вы увидите полный список из 3 продуктов. Перейдите к /api/products/1, и вы увидите первый продукт.

Резюме

Перенос простого Web API 2 проекта на MVC 6 - довольно простое дело, благодаря тому, что Web API был объединен с MVC 6 в ASP.NET 5. Основные части Web API 2, которые нужно переносить, - это роуты, контроллеры и модели, наряду с обновлениями типов, используемых MVC 6 контроллерами и действиями.

Связанные ресурсы

Создание Web API в MVC 6

Поделись хорошей новостью с друзьями!
Следи за новостями!