首页 > 解决方案 > 发布包含 jpg 和 json 的多部分请求会导致内部服务器错误和 IIS 上的 win32 状态 64

问题描述

我的 winforms 应用程序将 PUT/POST 请求发送到 asp.net web api 服务。大多数情况下,它将 json 对象作为请求的内容发送,并且这些请求运行良好。有时,当它需要将 jpg 与 json 对象一起发送时,它会创建 multiPart 请求,其中 jpg 是内容,json 在 url 中传递,如下所示:

example.com/EditPart?id=193&PartJson=<serialized json object>

以下是发送请求的方法的完整定义:

public async void Edit(string attachmentPath)
        {

            using (var client = new HttpClient())
            {
                var serializedProduct = JsonConvert.SerializeObject(this, new JsonSerializerSettings { DateFormatString = "yyyy-MM-ddTHH:mm:ss.fff" });
                string url = Secrets.ApiAddress + $"Edit{typeof(T).Name}?token=" + Secrets.TenantToken + $"&id={this.Id}&UserId={RuntimeSettings.UserId}" + $"&{typeof(T).Name}Json={serializedProduct}";
                MultipartFormDataContent content = new MultipartFormDataContent();
                try
                {
                    using (var fileStream = System.IO.File.OpenRead(attachmentPath))
                    {
                        var fileInfo = new FileInfo(attachmentPath);
                        StreamContent fcontent = new StreamContent(fileStream);
                        fcontent.Headers.Add("Content-Type", "application/octet-stream");
                        fcontent.Headers.Add("Content-Disposition", "form-data; name=\"file\"; filename=\"" + fileInfo.Name + "\"");
                        content.Add(fcontent, "file", fileInfo.Name);
                        System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
                        var result = await client.PutAsync(url, content);//<--stops here
                        if (result.IsSuccessStatusCode)
                        {
                            MessageBox.Show("Edycja zakończona powodzeniem!");
                        }
                        else
                        {
                            MessageBox.Show("Serwer zwrócił błąd przy próbie edycji. Wiadomość: " + result.ReasonPhrase);
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Problem z wysyłką żądania do serwera. Wiadomość: " + ex.Message + ". " + ex.InnerException.Message, "Błąd żądania", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

它进入await client.PutAsync(url, content);然后直接进入异常状态:发送请求时发生错误。底层连接已关闭。接收时发生意外错误。

当我检查 IIS 日志时,我看到请求正确地到达服务器,但以状态 500 和 win32 状态 64 结束。我什至将使用 NLog 的日志记录到 EditPart 方法,但它从不触发。看起来该方法是根本没有调用,但当然从 IIS 日志中我知道它是。

这是 asp.net web api 上的完整 EditPart 定义:

[HttpPut]
        [Route("EditPart")]
        [ResponseType(typeof(void))]

        public HttpResponseMessage EditPart(string token, int id, int UserId, string PartJson)
        {
            try
            {
                JavaScriptSerializer jss = new JavaScriptSerializer();
                JDE_Parts item = jss.Deserialize<JDE_Parts>(PartJson);

                try
                {
                    var items = db.JDE_Parts.Where(u => u.PartId == id);
                    if (items.Any())
                    {
                        Logger.Info("EditPart: Znalazłem odpowiednią część. Przystępuję do edycji Id={id}, UserId={UserId}", id, UserId);
                        JDE_Parts orgItem = items.FirstOrDefault();

                        //handle image

                        var httpRequest = HttpContext.Current.Request;
                        if (httpRequest.ContentLength > 0)
                        {
                            //there's a new content
                            if (httpRequest.ContentLength > Static.RuntimeSettings.MaxFileContentLength)
                            {
                                return Request.CreateResponse(HttpStatusCode.BadRequest, $"{item.Name} przekracza dopuszczalną wielość pliku ({Static.RuntimeSettings.MaxFileContentLength} MB) i został odrzucony");
                            }

                            var postedFile = httpRequest.Files[0];
                            string filePath = "";
                            if (postedFile != null && postedFile.ContentLength > 0)
                            {
                                Logger.Info("EditPart: Znaleziono nowe pliki. Przystępuję do zapisu na dysku. Id={id}, UserId={UserId}", id, UserId);
                                var ext = postedFile.FileName.Substring(postedFile.FileName.LastIndexOf('.'));

                                filePath = $"{Static.RuntimeSettings.Path2Files}{item.Token + ext.ToLower()}";

                                string oFileName = db.JDE_Parts.Where(p => p.PartId == id).FirstOrDefault().Image;
                                if (!string.IsNullOrEmpty(oFileName))
                                {
                                    // There was a file, must delete it first
                                    Logger.Info("EditPart: Istnieją poprzednie pliki pod tą nazwą. Przystępuję do usuwania. Id={id}, UserId={UserId}", id, UserId);
                                    System.IO.File.Delete(Path.Combine(RuntimeSettings.Path2Files, oFileName));
                                    System.IO.File.Delete(Path.Combine(RuntimeSettings.Path2Thumbs, oFileName));
                                }
                                postedFile.SaveAs(filePath);
                                Logger.Info("EditPart: Zapisano pliki. Przystępuję do utworzenia miniatury.. Id={id}, UserId={UserId}", id, UserId);
                                Static.Utilities.ProduceThumbnail(filePath);
                                item.Image = item.Token + ext.ToLower();
                            }

                        }

                        try
                        {
                            Logger.Info("EditPart: Przystępuję do zapisu zmian w bazie danych. Id={id}, UserId={UserId}", id, UserId);
                            db.Entry(orgItem).CurrentValues.SetValues(item);
                            db.Entry(orgItem).State = EntityState.Modified;
                            db.SaveChanges();
                            Logger.Info("EditPart: Zapisano zmiany w bazie. Id={id}, UserId={UserId}", id, UserId);
                        }
                        catch (Exception ex)
                        {
                            Logger.Error("Błąd w EditPart. Id={id}, UserId={UserId}. Szczegóły: {Message}, nowa wartość: {item}", id, UserId, ex.ToString(), item);
                            return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
                        }
                    }
                }
                catch (Exception ex)
                {

                    Logger.Error("Błąd w EditPart. Id={id}, UserId={UserId}. Szczegóły: {Message}, nowa wartość: {item}", id, UserId, ex.ToString(), item);
                    return Request.CreateResponse(HttpStatusCode.NoContent);
                }
            }
            catch (Exception ex)
            {
                Logger.Error("Błąd w EditPart. Id={id}, UserId={UserId}. Szczegóły: {Message}", id, UserId, ex.ToString());
                return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
            }

            return Request.CreateResponse(HttpStatusCode.NoContent);
        }

奇怪的是,这一切都运行了好几个月,直到前一段时间它停止了。另外,当我在我的机器上调试 asp.net 应用程序时,请求运行没有任何问题。我还能做些什么来跟踪这个问题?

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

解决方案


事实证明,问题出在客户端应用程序中我的 Edit 方法中的单行。更改fcontent.Headers.Add("Content-Type", "application/octet-stream")为它后,fcontent.Headers.ContentType = new MediaTypeHeaderValue(MimeMapping.GetMimeMapping(fileInfo.Name))它可以完美运行。换句话说,我的请求甚至没有发送到服务器。然而,令人费解的是,相同的代码已经运行了几个月然后停止了。

public async void Edit(string attachmentPath)
    {

        using (var client = new HttpClient())
        {
            var serializedProduct = JsonConvert.SerializeObject(this, new JsonSerializerSettings { DateFormatString = "yyyy-MM-ddTHH:mm:ss.fff" });
            string url = Secrets.ApiAddress + $"Edit{typeof(T).Name}?token=" + Secrets.TenantToken + $"&id={this.Id}&UserId={RuntimeSettings.UserId}" + $"&{typeof(T).Name}Json={serializedProduct}";
            MultipartFormDataContent content = new MultipartFormDataContent();
            try
            {
                using (var fileStream = System.IO.File.OpenRead(attachmentPath))
                {
                    var fileInfo = new FileInfo(attachmentPath);
                    StreamContent fcontent = new StreamContent(fileStream);
                    fcontent.Headers.ContentType = new MediaTypeHeaderValue(MimeMapping.GetMimeMapping(fileInfo.Name)); //fcontent.Headers.Add("Content-Type", "application/octet-stream");
                    fcontent.Headers.Add("Content-Disposition", "form-data; name=\"file\"; filename=\"" + fileInfo.Name + "\"");
                    content.Add(fcontent, "file", fileInfo.Name);
                    System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
                    var result = await client.PutAsync(url, content);//<--stops here
                    if (result.IsSuccessStatusCode)
                    {
                        MessageBox.Show("Edycja zakończona powodzeniem!");
                    }
                    else
                    {
                        MessageBox.Show("Serwer zwrócił błąd przy próbie edycji. Wiadomość: " + result.ReasonPhrase);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Problem z wysyłką żądania do serwera. Wiadomość: " + ex.Message + ". " + ex.InnerException.Message, "Błąd żądania", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }

推荐阅读