Похоже, что маршрутизация DevExpress прерывается с ядром dotnet 3.1

#.net-core #devexpress-gridcontrol

#.net-core #devexpress-gridcontrol

Вопрос:

На моей странице есть следующий DxDatagrid блок dotnet core webapp index.cshtml :

 @(Html.DevExtreme().DataGrid<UserModel>()
    .ID("grid-container")
    .ShowBorders(true)
    .DataSource(d => d.Mvc().Controller("UserSearch").LoadAction("Get").Key("UserId"))
    .Selection(s => s
        .Mode(SelectionMode.Multiple)
        .SelectAllMode(SelectAllMode.Page)
        )
  

С этим кодом на месте и использованием dotnet core 2.2 источника данных выполняется вызов:

 http://localhost:5000/api/UserSearch/Get?skip=0amp;take=10amp;requireTotalCount=trueamp;_=1600859370033
  

После обновления до dotnet core 3.1 и обновления ссылок DevExpress в csproj файлах _Layout.cshtml и маршрутизация теперь пытается вызвать:

 http://localhost:5000/?skip=0amp;take=10amp;requireTotalCount=trueamp;_=1600859693687
  

startup.cs Это:

 using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using AccessUsers.Middleware;
using AccessUsers.Models;
using Microsoft.AspNetCore.HttpOverrides;

namespace WebAppTest
{
    public class Startup
    {
        private readonly IConfiguration _config;
        private readonly AppSettings _appSettings;

        public Startup(IConfiguration config)
        {
            _config = config;
            _appSettings = _config.Get<AppSettings>();
        }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => false;
                // options.MinimumSameSitePolicy = SameSiteMode.None;

                options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
                options.OnAppendCookie = cookieContext => cookieContext.CookieOptions.SameSite = SameSiteMode.Unspecified;
                options.OnDeleteCookie = cookieContext => cookieContext.CookieOptions.SameSite = SameSiteMode.Unspecified;
            });

            services.Configure<AppSettings>(_config);

            services.AddSingleton<APIService>();
            services.AddSingleton<UserService>();
            services.AddSingleton<ShipToService>();

            services.AddApplicationInsightsTelemetry();

            services.AddLocalization(options => options.ResourcesPath = "Resources");
            services.AddSession();
            services.AddMemoryCache();
            
            services.AddRazorPages().AddNewtonsoftJson(options => {
                options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
                options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
            }).AddXmlSerializerFormatters();

            services.UseOpenIDConnectMiddleware(new OpenIDConnectMiddlewareOptions
            {
                BaseUrl = _appSettings.API.BaseUrl,
                AppName = _appSettings.AppName,
                ClientId = _appSettings.API.ClientId,
                ClientSecret = _appSettings.API.ClientSecret,
                Secure = !_appSettings.Local
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = ForwardedHeaders.XForwardedProto
            });

            if (_appSettings.Local)
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
                app.UseGlobalLoginMiddleware();
                app.UseHttpsRedirection();
            }

            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();

            app.UseSession();

            app.UseEndpoints(endpoints => {
                endpoints.MapRazorPages();
            });

            CultureInfo[] allCultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
            string location = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
            var supportedCultures = allCultures.Where(c => Directory.Exists(Path.Combine(location, c.Name)) amp;amp; c.LCID != 127).ToList();

            app.UseRequestLocalization(new RequestLocalizationOptions
            {
                DefaultRequestCulture = new RequestCulture("en-US"),
                SupportedCultures = supportedCultures,
                SupportedUICultures = supportedCultures
            });
        }
    }
}
  

csproj Содержит это:

 <Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
  </PropertyGroup>


  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="3.1.6" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.7" />
    <PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="6.7.1" />

    <PackageReference Include="DevExtreme.AspNet.Data" Version="2.7.1" />
    <PackageReference Include="DevExtreme.AspNet.Core" Version="20.1.7" />

    <PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.7.1" />
    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.7.1" />

    <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.14.0" />

    <PackageReference Include="Amazon.Lambda.AspNetCoreServer" Version="5.0.0" />
  </ItemGroup>

</Project>
  

controller.cs Содержит это:

 using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using AccessUsers.Models;
using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;

namespace WebAppTest.Pages
{
    [Route("api/[controller]/[action]")]
    public class UserSearchController : Controller
    {
        private readonly UserService _userService;

        public UserSearchController(UserService userService)
        {
            _userService = userService;
        }

        [HttpGet]
        public object Get(DataSourceLoadOptions loadOptions)
        {
            var result =  DataSourceLoader.Load(GetProfiles(user:new UserModel(),useDummyData: true), loadOptions);

            return resu<
        }
  

_Layout.cshtml Содержит это:

 <script src="https://cdn3.devexpress.com/jslib/20.1.7/js/dx.all.js" integrity="sha384-LAn t9UxSqkm8biNuoUbJcohKoYmbiFRfVLERIJ4I3RyEpAIBizEcIztuXPG9Cqg sha512-OAjfsw eXv345AD9H6kDJLChXetpJD6ChGgDvjVIEumiHYulOLXIO/Do5gxljW2GUgpObic42JyS8a0wZqb1Fw==" crossorigin="anonymous"></script>
<script src="https://cdn3.devexpress.com/jslib/20.1.7/js/dx.aspnet.mvc.js" integrity="sha384-5rtF4jUX5Hez5YwkW7PHC/0XplJQS26qVUCfec8fBX0IkoR1y35EXHkZDbgeMh3x sha512-0eJebJTnN45FCtUOrVqxk5p73OMWsx94vLQpnlRtDp/CKbssiUR0j0os 0y01fvzDtdtnEKSeau32g30fgtrYQ==" crossorigin="anonymous"></script>
  

Как указано здесь:
https://js.devexpress.com/Documentation/Guide/Common/Distribution_Channels/CDN /

Я уверен, что это изменение dotnet core 3.1 привело к прерыванию маршрутизации, потому что функциональность приложения не изменилась, но я не вижу, что конкретно ее нарушает.

Комментарии:

1. Какую версию DxDatagrid вы используете? .NET Core 3.x является основной версией. Ожидается , что в нем будут серьезные изменения. У сторонних библиотек, созданных для более старых версий, могут возникнуть проблемы, или вы, возможно, больше не используете контроллер MVC. Кстати, вы не опубликовали самую важную часть кода, контроллер. Речь идет не о маршрутизации, а о том, как помощники grid генерируют URL-адреса

2. d.Mvc().Controller("UserSearch").LoadAction("Get") отвечает за генерацию /api/UserSearch/Get? с использованием отражения и имен, указанных в виде строк. Если имена неверны, в неожиданном пространстве имен или с использованием неожиданного базового класса, эта цепочка вызовов может легко завершиться сбоем. AddMvc() В вашей конфигурации нет, поэтому d.Mvc() может произойти сбой с самого начала

3. Я обновил свой пост фрагментом контроллера.

4. Как мне найти номер версии используемой мной сетки данных? Я предположил, что это будет 20.1.7, поскольку это версия пакета DevExpress.

5. Можете ли вы вызвать этот контроллер напрямую в первую очередь? AddMvc() В AddControllers() вашем запуске нет или, только AddRazorPages()

Ответ №1:

Startup.ConfigureServices не добавляет поддержки контроллеров, только для страниц Razor с :

 services.AddRazorPages().AddNewtonsoftJson(options => {
        ...
        }).AddXmlSerializerFormatters();
  

Из замечаний в документации метода

Этот метод настраивает службы MVC для часто используемых функций для страниц.

Чтобы добавить службы для контроллеров для API, вызовите AddControllers(IServiceCollection).

Контроллер никогда не регистрируется прямо сейчас, поэтому код, который пытается сгенерировать URL-адрес действия

 .DataSource(d => d.Mvc().Controller("UserSearch").LoadAction("Get")
  

ничего не удается найти и возвращает пустую строку.

Чтобы исправить это, добавьте поддержку контроллера :

 services.AddControllers().AddNewtonsoftJson(options => {
        ...
        }).AddXmlSerializerFormatters();
services.AddRazorPages();
  

Контроллеры также должны быть добавлены в код маршрутизации конечной Configure точки с помощью MapControllers :

 app.UseEndpoints(endpoints => {
    endpoints.MapRazorPages();
    endpoints.MapControllers();
});