在控制器中使用[FromBody]属性时,Blazor服务器端应用程序(Razor组件)中的InputFormatters为空

时间:2019-02-10 19:14:32

标签: asp.net-core-webapi blazor blazor-server-side

我正在使用Asp.Net Core 3.0预览版中的服务器端火焰(剃刀组件)来开发一款网络游戏。我有一个用于将游戏数据保存到服务器的控制器类,但是每当我使用有效的JSON主体发出发布请求时,控制器都无法格式化请求主体,因为它无法从上下文中找到任何IInputFormatter。 / p>

我已经能够执行简单的GET请求和POST,而无需使用[FromBody]属性,因此我知道我的控制器路由正在工作。但是任何时候我尝试使用HttpClient SendJsonAsync或PostJsonAsync方法并尝试使用[FromBody]属性读取JSON时,都会出现以下错误:

System.InvalidOperationException:'Microsoft.AspNetCore.Mvc.MvcOptions.InputFormatters'不能为空。 从主体绑定至少需要一个“ Microsoft.AspNetCore.Mvc.Formatters.IInputFormatter”。

我也直接将Microsoft.AspNetCore.Mvc.Formatters.Json安装到我的项目中,以防万一,但是没有运气。

我在Server.Startup类中注册mvc并将其添加到我的服务中

// This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorComponents<App.Startup>();
        services.AddMvc();

        //Register httpclient service
        if (!services.Any(x => x.ServiceType == typeof(HttpClient)))
        {
            // Setup HttpClient for server side in a client side compatible fashion
            services.AddScoped<HttpClient>(s =>
            {
                // Creating the URI helper needs to wait until the JS Runtime is initialized, so defer it.
                var uriHelper = s.GetRequiredService<IUriHelper>();
                return new HttpClient
                {
                    BaseAddress = new Uri(uriHelper.GetBaseUri())
                };
            });
        }
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseMvc(routes => { routes.MapRoute(name: "default", template: "{controller}/{action}"); });
        app.UseRazorComponents<App.Startup>();
    }

我的控制器类和方法:

public class GameController : Controller
{        
    [HttpPost]
    [Route("api/Game/SaveGame")]
    public string SaveGame([FromBody]GameInfoBody gameInfo)
    {
         //save the game to database
    }
}

我的Game.cshtml页面中的客户呼叫:

public async Task<string> SaveGameToDatabase(GameEngine game)
{
    var request = new GameInfoPostModel()
    {
        gameInfo = new GameInfoBody
        {
            ID = game.ID,
            GameEngine = game,
            Players = game.Teams.SelectMany(x => x.Players).Select(x => new PlayerGameMapping() { PlayerID = x.ID }).ToList()
        }
    };

    try
    {
        var result = await Client.SendJsonAsync<string>(HttpMethod.Post, "/api/Game/SaveGame", request);
        return result;
    }
    catch (Exception e)
    {
        return "Failed to save" + e.Message;
    }
}

完整堆栈跟踪:

System.InvalidOperationException: 'Microsoft.AspNetCore.Mvc.MvcOptions.InputFormatters' must not be empty. At least one 'Microsoft.AspNetCore.Mvc.Formatters.IInputFormatter' is required to bind from the body.
   at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinderProvider.GetBinder(ModelBinderProviderContext context)
   at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory.CreateBinderCoreUncached(DefaultModelBinderProviderContext providerContext, Object token)
   at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory.CreateBinder(ModelBinderFactoryContext context)
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.GetParameterBindingInfo(IModelBinderFactory modelBinderFactory, IModelMetadataProvider modelMetadataProvider, ControllerActionDescriptor actionDescriptor, MvcOptions mvcOptions)
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.CreateBinderDelegate(ParameterBinder parameterBinder, IModelBinderFactory modelBinderFactory, IModelMetadataProvider modelMetadataProvider, ControllerActionDescriptor actionDescriptor, MvcOptions mvcOptions)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerCache.GetCachedResult(ControllerContext controllerContext)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerProvider.OnProvidersExecuting(ActionInvokerProviderContext context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionInvokerFactory.CreateInvoker(ActionContext actionContext)
   at Microsoft.AspNetCore.Mvc.Routing.MvcEndpointDataSource.<>c__DisplayClass22_0.<CreateEndpoint>b__0(HttpContext context)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

阅读文档告诉我,默认情况下包含JsonFormatters。我已经使用Fiddler验证了我的调用具有正确的内容类型和有效的JSON。我想如果不能从上下文中找到任何InputFormatters,就一定不能正确配置服务,但是我没有找到其他有此问题的人,也不知道下一步该怎么做。任何帮助将不胜感激,谢谢

1 个答案:

答案 0 :(得分:0)

尝试一下: (按照此顺序...)

services.AddMvc().AddNewtonsoftJson();

services.AddRazorComponents<App.Startup>();