【问题标题】:HTTP Post with FormData is not reached in WebAPIWebAPI 中未达到带有 FormData 的 HTTP Post
【发布时间】:2015-01-29 03:15:03
【问题描述】:

我有一个如下定义的 Web API 控制器:

[HttpPost]
public class EmailActivitiesController : ApiController
{
    public HttpResponseMessage EmailAClientWithNewMailMessage(FormDataCollection aFormData)
    {
    }
}

使用以下 jQuery 调用:

    var aFormData =  {};
    $.support.cors = true;
    $.ajax({
        cache: false,
        url: '/api/EmailActivities/EmailAClientWithNewMailMessage',
        type: "POST",
        dataType: "json",
        data: aFormData,
        success: function (callback) {
            //Platform.LoadingPanelHide();
            alert("Successfully sent the email.");
        },
        error: function (data) {
            var errorObject = JSON.parse(data);

            //Platform.LoadingPanelHide();
            alert('There was a problem sending the email message to the individual selected.\n\n' + errorObject.responseText.message);
        }
    });

一切正常,并达到 API 方法。但是,只要我按如下方式填充 aFormData:

    var aFormData =  {};

    aFormData['aMessageInfo'] = "test";

    //And sending via form data
    $.support.cors = true;
    $.ajax({
        cache: false,
        url: '/api/EmailActivities/EmailAClientWithNewMailMessage',
        type: "POST",
        dataType: "json",
        data: aFormData,
        success: function (callback) {
            //Platform.LoadingPanelHide();
            alert("Successfully sent the email.");
        },
        error: function (data) {
            var errorObject = JSON.parse(data);

            //Platform.LoadingPanelHide();
            alert('There was a problem sending the email message to the individual selected.\n\n' + errorObject.responseText.message);
        }
    });

然后没有达到该方法,而是收到带有以下 JSON 响应的 HttpResonseCode.OK:

{
"result": null,
"success": false,
"error": {
"code": 0,
"message": "An internal error occured during your request!",
"details": null,
"validationErrors": null
},
"unAuthorizedRequest": false
}

对于我的一生,我无法弄清楚为什么会发生这种情况。有没有人有任何见解。

更新

这是 POST 请求。

还有异常日志:

    ERROR 2015-01-29 15:51:08,250 [17   ] Default                                  - Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.
System.Web.Http.HttpResponseException: Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.
   at System.Web.Http.ModelBinding.FormatterParameterBinding.ReadContentAsync(HttpRequestMessage request, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)
   at System.Web.Http.ModelBinding.FormatterParameterBinding.ReadContentAsync(HttpRequestMessage request, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger)
   at System.Web.Http.ModelBinding.FormatterParameterBinding.<ExecuteBindingAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at System.Web.Http.Controllers.HttpActionBinding.<ExecuteBindingAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()

更新 #2

我现在采用了使用 DTO 的建议方法,如下所示:

var aMessageInfo = {
            subject: Base64.encode($("#txtSendEmailSubject").val()),
            body: Base64.encode($("#txtSendEmailBody").val())
        };

 $.support.cors = true;
        $.ajax({
            cache: false,
            url: '/api/EmailActivities/Dono2',
            type: "POST",
            dataType: "json",
            contentType: "application/json; charset=utf-8",
            data: JSON.stringify(aMessageInfo),
            success: function (callback) {
                //Platform.LoadingPanelHide();
                alert("Successfully sent the email.");
            },
            error: function (data) {
                var errorObject = JSON.parse(data);

                //Platform.LoadingPanelHide();
                alert('There was a problem sending the email message to the individual selected.\n\n' + errorObject.responseText.message);
            }
        });

然后在 WebAPI 中,如果我只有:

   public class EmailActivitiesController : ApiController
    {
    [HttpPost]
        public HttpResponseMessage Dono2(MessageInfo aMessageInfo)
        {
        }
    }

但只要我也有 EmailAClientWithNewMailMessage 作为方法:

   public class EmailActivitiesController : ApiController
    {
    [HttpPost]
        public HttpResponseMessage Dono2(MessageInfo aMessageInfo)
        {
        }


  [HttpPost]
        public HttpResponseMessage EmailAClientWithNewMailMessage(FormDataCollection aFormData)
        {
}

我得到错误:

{  
   "message":"An error has occurred.",
   "exceptionMessage":"Multiple actions were found that match the request: \r\nDono2 on type MakersLane.WebApi.Controllers.EmailActivitiesController\r\nEmailAClientWithNewMailMessage on type MakersLane.WebApi.Controllers.EmailActivitiesController",
   "exceptionType":"System.InvalidOperationException",
   "stackTrace":"   at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)\r\n   at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)\r\n   at Abp.WebApi.Controllers.Dynamic.Selectors.AbpApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)\r\n   at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}

现在,虽然控制器 Dono2 和 EmailClientWithNewMessage 上有两个操作,但我不明白为什么不能将它们区分开来,因为它们显然具有不同的名称,尽管它们都有一个参数,但它们的名称不同并且属于不同的类型。

谁能解释为什么会这样?

【问题讨论】:

  • 您可以发布通过网络发送的 HTTP 请求吗?
  • @JoelGregory 添加了出现在电线上的 FireBug....如果您想要其他内容,请告诉我,我会添加它,

标签: c# jquery asp.net-web-api


【解决方案1】:

我不在 Windows 机器上,因此现在无法测试此编写,但我将在下面提供替代解决方案。这是从 POST 中发送的查询字符串到FormDataCollection 的映射问题,我认为可以通过使用这样的 JSON 对象来解决:

{ aFormData : { aMessageInfo : "test" } }

但我无法确认。我相信以下解决方案会更好,因此除非您必须使用 FormDataCollection,否则请使用它。

我建议使用视图模型而不是 FormDataCollection,因为值的映射变得乏味:

public class Message
{
    public string Client { get; set; }
    public string Content { get; set; }
}

然后将您的控制器更改为:

public HttpResponseMessage EmailAClientWithNewMailMessage(Message data)
{
    // use the deserialised object here
    return data.Client;
}

你的 jquery 看起来像这样(注意添加了 content-type 参数和 JSON.stringify 调用):

var aFormData =  {};

aFormData['aMessageInfo'] = "test";

//And sending via form data
$.support.cors = true;
$.ajax({
    cache: false,
    url: '/api/EmailActivities/EmailAClientWithNewMailMessage',
    type: "POST",
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    data: JSON.stringify(aFormData),
    success: function (callback) {
        //Platform.LoadingPanelHide();
        alert("Successfully sent the email.");
    },
    error: function (data) {
        var errorObject = JSON.parse(data);

        //Platform.LoadingPanelHide();
        alert('There was a problem sending the email message to the individual selected.\n\n' + errorObject.responseText.message);
    }
});

【讨论】:

    【解决方案2】:

    https://github.com/aspnetboilerplate/aspnetboilerplate/blob/593c47050c345cfa4617e06bc7f4ac19f5b81a15/src/Abp.Web.Api/WebApi/Controllers/Dynamic/Selectors/DyanamicHttpActionDescriptor.cs

    我认为这段代码覆盖了结果。

    try
                        {
                            if (task.Result == null)
                            {
                                return new AjaxResponse();
                            }
    
                            if (task.Result is AjaxResponse)
                            {
                                return task.Result;
                            }
    
                            return new AjaxResponse(task.Result);
                        }
    

    【讨论】:

      【解决方案3】:

      您查看过 Logs/logs.txt 文件吗?它将在那里抛出异常。

      干杯 杰夫

      【讨论】:

      • 忘记 ABP 现在正在记录异常。已经发布了它的价值的日志。仍然不确定这是 ABP 还是其他什么。我意识到我正在使用旧版本的 ABP 即 0.4.1 运行,但在我知道它是 ABP 之前不想升级
      【解决方案4】:

      我认为乔尔是正确的。我在将字符串作为参数传递时遇到问题,因此将我的所有输入包装在 DTO 对象中,它工作正常。

      干杯 杰夫

      【讨论】:

        【解决方案5】:

        问题是:ABP 系统配置为仅使用 JSON 数据。当您更改这样的代码时,它可以工作:

        $.ajax({
            cache: false,
            url: '/api/EmailActivities/EmailAClientWithNewMailMessage',
            type: "POST",
            contentType: 'application/json',
            dataType: "json",
            data: JSON.stringify({ aMessageInfo: 'test' }),
            success: function (callback) {
                //Platform.LoadingPanelHide();
                alert("Successfully sent the email.");
            },
            error: function (data) {
                var errorObject = JSON.parse(data);
        
                //Platform.LoadingPanelHide();
                alert('There was a problem sending the email message to the individual selected.\n\n' + errorObject.responseText.message);
            }
        });
        

        我添加了 contentType。那样,方法被调用,但是表单数据不来方法。也许 FormDataCollection 不喜欢 JSON 帖子。

        为什么不使用简单的 DTO 类而不是 FormDataCollection?这对于 ABP 项目来说更为自然。

        在 AbpWebApiModule 中,它会清除所有格式化程序并添加 JSON 和纯文本。

                private static void InitializeFormatters()
                {
                    GlobalConfiguration.Configuration.Formatters.Clear();
                    var formatter = new JsonMediaTypeFormatter();
                    formatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                    GlobalConfiguration.Configuration.Formatters.Add(formatter);
                    GlobalConfiguration.Configuration.Formatters.Add(new PlainTextFormatter());
                }
        

        也许您可以使用 GlobalConfiguration.Configuration.Formatters.Add 添加其他格式化程序。

        我是如何发现问题的? ABP 定义了一个事件来处理异常(从 v0.3.2 开始):

        这可以帮助您查找错误。

        EventBus.Default.Register<AbpHandledExceptionData>(
            data =>
            {
                //use data.Exception to see exception details
            });
        

        【讨论】:

        • 我听取了您的建议,通过了一个简单的 DTO(没有添加额外的格式化程序)。但是,您能否查看 Update #2 并告诉我为什么 ABP 无法区分选择器时出现错误?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-05-22
        • 1970-01-01
        • 1970-01-01
        • 2016-04-02
        • 1970-01-01
        • 1970-01-01
        • 2017-09-06
        相关资源
        最近更新 更多