【问题标题】:IFormFile gets disposed while doing async operationIFormFile 在执行异步操作时被释放
【发布时间】:2018-06-08 00:07:22
【问题描述】:

我有一个 ASP.Net Core 2.0 webapi 代码,如下所示

public class TestController : Controller
{
    private readonly ISampleRepository _sampleRepository = new SampleRepository();

    [HttpPost("{id}")]
    public async void Post([FromRoute]int id, IEnumerable<IFormFile> files, [FromForm] NotifyViewModel model)
    {
        // get data from DB using async
        var dbData = await _sampleRepository.GetAsync(id);

        //check if email alert is enabled 
        if(dbData.IsEmailEnabled)
        {
            //create MailMessage
            var mailMessage = new MailMessage() { 
                //options here 
                };

            foreach (var formFile in files)
            {
                mailMessage.Attachments.Add(new Attachment(formFile.OpenReadStream(), formFile.FileName, formFile.ContentType));
            }

            // send email
            _emailHelper.SendEmail(mailMessage);
        }
    }
}

public class SampleRepository 
{
    public async Task<SampleData> GetAsync(int id)
    {
        //get data using Dapper & return
        var result = await con.QuerySingleAsync<SampleData>(sql, new {id = id}, null, null, CommandType.Text);

        return result;
    }
}


当我将数据发布到此端点时,我收到异常消息'Cannot access disposed object.'(请参阅屏幕截图)

但是,当我通过执行以下代码更改使数据库操作同步时,它以某种方式工作而没有任何错误。

// Removed
// var dbData = await _sampleRepository.GetAsync(id);

// Newly added. Made DB operations synchronous
var dbData = _sampleRepository.GetAsync(id).Result; 


有人可以帮我理解这种行为吗?为什么在涉及异步操作时会释放 HTTP 发布的文件?

【问题讨论】:

  • MailMessage的类型是什么?同样在您的列表中,变量是message,但在屏幕截图中是mailMessage
  • 感谢您的指出。我在为 SO 帖子编写虚拟代码时错过了这一点。我正在使用来自命名空间 System.Net.MailMailMessage
  • 你发布什么实现IFormFile
  • 保持await在原地,你能在去db之前和之后打印出System.Threading.Thread.CurrentThread.ManagedThreadId吗?

标签: c# asp.net-web-api asp.net-core async-await


【解决方案1】:

因为您的方法是async void,所以它会在遇到第一个await 时立即返回。当代码访问请求数据时,请求已经结束。

Post 的签名从async void Post 更改为async Task Post,因为async Task 是同步void 的异步模拟。

【讨论】:

  • FWIW,尽管如此,void/Task 将导致 200 状态代码没有内容主体总是。如果这是一个 API 端点,你应该显式返回 NoContent() 如果它实际上应该这样做。如果这是一个 MVC 操作(即您从浏览器选项卡发布),那么您应该始终返回一些 HTML 文档,否则您将把用户困在一个空白页面上。一般来说,除了IActionResult/Task&lt;IActionResult&gt;之外,几乎没有理由让任何操作方法返回任何内容。
猜你喜欢
  • 2022-11-02
  • 2011-03-20
  • 2019-05-27
  • 2017-03-27
  • 2017-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-13
相关资源
最近更新 更多