【问题标题】:sending an object array to a get function将对象数组发送到 get 函数
【发布时间】:2019-06-06 18:22:37
【问题描述】:

我正在使用 .NET Core 和 WebApi,我正在尝试弄清楚发送对象数组的 url 是什么样的。

例如

public class DataObject
{
  public int id { get; set;}
  public string name { get; set }
}

[HttpGet()]
public <ActionResult<string>> GetSomething(DataObject[] data))
{
  //do something and return a string
}

执行此操作的 url 会是什么样子?我应该对数据使用 FromQuery 还是 FromRoute?在 HttpGet() 上,括号中应该是什么? “{data}”还是别的什么?

到目前为止,我能找到的所有内容都是整数数组或字符串数​​组,而不是 get 调用的复杂数组。

更新

即使我确定我得到的回复应该有效,但仍然无法使其正常工作。这里还有一些代码。

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

 [HttpGet()]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType(typeof(GridResult), (int)HttpStatusCode.OK)]
    public async Task<ActionResult<GridResult>> GetGridData<TFilter1, TFilter2, TItem1>
        ([FromQuery]string sessionID, [FromQuery] GridDetails details, [FromQuery] TFilter1[] TFilters1, [FromQuery] TFilter2[] TFilters2, [FromQuery] TItem1[] TSorts)

最后是我生成的引发 404 的 url。

https://localhost:44366/api/grid/GetGridData/sessionID=598357390&amp;details?NUMBER_OF_ROWS_FIRST_RETURNED=100&amp;CURSOR_POSITION=0&amp;RESULT_IN_SAXORDER=false&amp;TERSERESPONSE=true&amp;IsStaticList=true&amp;GRID_TYPE=list&amp;REQUEST_TYPE=LIST.DATA_ONLY.STORED&amp;GRID_NAME=WUWP09&amp;TFilters1[0].AliasName=PRO_CODE&amp;TFilters1[0].Operator=%3D&amp;TFilters1[0].SEQNUM=1&amp;TFilters1[1].AliasName=APR_CLASS&amp;TFilters1[1].Operator=%3D&amp;Tsorts[1].SEQNUM=2&amp;Tsorts[0].ALIAS_NAME=pvd_value&amp;Tsorts[0].TYPE=ASC

更新 2

https://localhost:44366/api/grid/GetGridData?sessionID=598357390&amp;details.NUMBER_OF_ROWS_FIRST_RETURNED=100&amp;details.CURSOR_POSITION=0&amp;details.RESULT_IN_SAXORDER=false&amp;details.TERSERESPONSE=true&amp;details.IsStaticList=true&amp;details.GRID_TYPE=list&amp;details.REQUEST_TYPE=LIST.DATA_ONLY.STORED&amp;details.GRID_NAME=WUWP09&amp;details.TAB_NAME&amp;details.LOCALIZE_RESULT&amp;details.USER_FUNCTION_NAME&amp;details.TOTALRECORDS&amp;details.RES_IsMoreRecords&amp;details.RES_CURRENT_CURSOR_POSITION&amp;TFilters1[0].AliasName=PRO_CODE&amp;TFilters1[0].Operator=%3D&amp;TFilters1[0].SEQNUM=1&amp;TFilters1[1].AliasName=APR_CLASS&amp;TFilters1[1].Operator=%3D&amp;Tsorts[1].SEQNUM=2&amp;Tsorts[0].ALIAS_NAME=pvd_value&amp;Tsorts[0].TYPE=ASC

更新 3

启动.cs 公共类启动 { 公共启动(IConfiguration 配置) { 配置=配置; }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        var _accessor = services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        var config = new GridServices.Models.config();
        Configuration.Bind("Connections", config);
        services.AddSingleton(config);
        services.AddSingleton(new Controllers.GridController(config));
    }

    // 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();
        }
        else
        {
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseMvc();
    }
}

网格控制器

namespace EAMWebApi.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class GridController : ControllerBase
{
    config Config { get; }
    //private readonly LinkGenerator _linkGenerator;

    public GridController(config config)
    {
        config = Config;
        //_linkGenerator = linkGenerator;
    }

    [HttpGet()]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType(typeof(GridResult), (int)HttpStatusCode.OK)]
    public async Task<ActionResult<GridResult>> GetGridData<TFilter1, TFilter2, TItem1>
        ([FromQuery]string sessionID, [FromQuery] GridDetails details, [FromQuery] TFilter1[] TFilters1 = null, [FromQuery] TFilter2[] TFilters2 = null, [FromQuery] TItem1[] TSorts = null)
    {//Do something}
}

网格详细信息

namespace GridServices.Models
{
    public class GridDetails
    {
        public string GRID_NAME { get; set; }
        public string NUMBER_OF_ROWS_FIRST_RETURNED { get; set; }        
        public string CURSOR_POSITION { get; set; }        
        public string TAB_NAME { get; set; }        
        public string RESULT_IN_SAXORDER { get; set; }        
        public string TERSERESPONSE { get; set; }        
        public string LOCALIZE_RESULT { get; set; }        
        public string USER_FUNCTION_NAME { get; set; }        
        public string TOTALRECORDS { get; set; }        
        public bool RES_IsMoreRecords { get; set; }        
        public bool IsStaticList { get; set; }        
        public string GRID_TYPE { get; set; }        
        public string REQUEST_TYPE { get; set; }        
        public string RES_CURRENT_CURSOR_POSITION { get; set; }
    }
}

MultiAddOnFilter

public class MultiAddOnFilter
{        
    public string ALIAS_NAME { get; set; }
    public string OPERATOR { get; set; }
    public string OPERATORSpecified { get; set; }
    public string VALUE { get; set; }
    public string LPAREN { get; set; }
    public string RPAREN { get; set; }        
    public string JOINER { get; set; }        
    public string JOINERSpecified { get; set; }        
    public string SEQNUM { get; set; }

    public MultiAddOnFilter(string _ALIAS_NAME, string _OPERATOR, string _VALUE)
    {
        ALIAS_NAME = _ALIAS_NAME;
        OPERATOR = _OPERATOR;
        OPERATORSpecified = "true";
        VALUE = _VALUE;
    }
}

排序 命名空间 GridServices.Models { 公共类排序 { 公共字符串 ALIAS_NAME { 获取;放; } 公共字符串类型 { 获取;放; } 公共字符串 TYPESpecified { 获取;放; }

    public Sort(string _ALIAS_NAME, string _TYPE)
    {
        ALIAS_NAME = _ALIAS_NAME;
        TYPE = _TYPE;
        TYPESpecified = "true";
    }
}

}

【问题讨论】:

    标签: asp.net-core-webapi


    【解决方案1】:

    url 会是什么样子?

    应该是这样的:

    GET /Somecontroller/GetSomething?data[0].id=1&data[0].name=nameA&data[1].id=2&data[1].name=nameB&data[2].id=3&data[2].name=nameC
    

    此有效负载与您以application/x-www-form-urlencoded 格式发布的内容几乎相同,只是您将其作为查询字符串发送。


    [编辑]

    如果其中一项为空,我是否必须将 %00 传递给它以指示空值?

    1. 假设您有这样一个对象数组:
    data = [
      {
        "id": 1,
        "name": "nameA"
      },
      {
        "id": 2,
        "name": null            
      },
      {
        "id": 3,
        "name": "nameC"
      }
    ]
    

    注意data[1].name==null。你不必指定data[1].name

    ?data[0].id=1&data[0].name=nameA&data[1].id=2&data[2].id=3&data[2].name=nameC
    
    1. 如果整个data[1]项是null,只需将data[2]的索引调整为data[1]
    data[0].id=1&data[0].name=nameA&data[1].id=3&data[1].name=name
    

    或者您可以为此项目添加一个空字段:

    ?data[0].id=1&data[0].name=nameA&data[1].id=&data[2].id=3&data[2].name=nameC
    

    如果整个 DataObject 为空怎么办? /GetSomething?data=%00 ?

    您不必指定/GetSomething?data=%00,只需向/GetSomething? 发送请求,然后您将得到一个空数组。


    [编辑2]

    总是将您路由到 404 结果的原因有两个:

    1. 您将GridController 注册为单身人士。 MVC 将自动注册控制器(作为作用域服务)。只需删除该行:
    services.AddSingleton(new Controllers.GridController(config));
    1. GetGridData&lt;TFilter1, TFilter2, TItem1&gt; 的控制器操作是一个通用方法。默认情况下它不会工作。已经有a thread on SO 谈论这个。我还建议您为每种方法使用特定的 GridFilter 类型。如果您发现自己在重复相同的逻辑,您可以将您的泛型方法放入父类 MySupperGridBaseController&lt;TFilter1, TFilter2, TItem1&gt; 中,如下所示:
    public class MySupperGridBaseController<TFilter1, TFilter2, TItem1> : ControllerBase
    {
        public async Task<ActionResult<GridResult>> GetGridData
                ([FromQuery]string sessionID, [FromQuery] GridDetails details, [FromQuery] TFilter1[] TFilters1 = null, [FromQuery] TFilter2[] TFilters2 = null, [FromQuery] TItem1[] TSorts = null)
        {
             ...
        }
    }
    
    
    // now we could reuse the same logic inherited from parent 
    public class GridController : MySupperGridBaseController<MultiAddOnFilter, MultiAddOnFilter, Sort>
    {
    
    }
    

    【讨论】:

    • 如果其中一项为空,我是否必须将 %00 传递给它以指示空值?如果整个 DataObject 为空怎么办? /GetSomething?data=%00 ?
    • 我被另一个工作中的项目分心了一段时间。我仍在努力使网址正常工作。我试图创建一个 LinkGenerator 来为我做这件事,但是没有很好的例子来说明如何在任何地方使用它。我在将 LinkGenerator 传递给我正在注入的控制器的构造函数时遇到了困难。
    • 请查看我更新的问题。我想将您的答案标记为答案,但我仍然无法正常工作。
    • @TheOriginalCole 你更新的控制器有一个[Route],它需要一个像api/[controller]/[action] 这样的url,但是你发送到服务器的是/api/grid/GetGridData/sessionID=598357390&amp;details?....。你能试试/api/grid/GetGridData?sessionID=598357390&amp;details&amp;....吗?
    • @TheOriginalCole 你的方式 ` var config = new GridServices.Models.config(); Configuration.Bind("Connections", config);` 有效,但我建议我们应该始终使用 DI。具体来说,我建议我们应该尽可能使用 IOptions 模式。当您想要创建一个依赖于其他服务而其中一些可能依赖于其他服务的实例时,DI 让生活变得轻松。手动配置(或新配置)是可行的,但是当我们的代码增长时会相当复杂。
    猜你喜欢
    • 2018-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-04
    • 1970-01-01
    • 2013-12-25
    • 2016-02-14
    • 1970-01-01
    相关资源
    最近更新 更多