谢谢大家,最终FileContentResult
做到了。
这是它的外观:
服务
public async Task<Attachment> Download(long? id)
{
return await _repository.FirstOrDefaultAsync(x => x.Id == id);
}
控制器
[AllowAnonymous]
[HttpGet("Download/{id}")]
public async Task<IActionResult> Download(long? id)
{
var attachment = await appService.Download(id);
return new FileContentResult(attachment.File,MimeTypeMap.GetMimeType(attachment.FileExtension))
{
FileDownloadName = $"{attachment.NomeFile}.{attachment.FileExtension}"
};
}
MimeTypeMap
被发现here
,
如果要从实体框架的数据库blob中流式传输文件而不将其加载到内存中。首先将数据模型分为两部分;
public class Attachment{
public int Id { get; set; }
public string Filename { get; set; }
public string ContentType { get; set; }
public virtual AttachmentBlob Blob { get; set; }
//...
}
public class AttachmentBlob{
public int Id { get; set; }
public byte[] File { get; set; }
}
将它们映射到同一表,但不作为拥有的类型;
modelBuilder.Entity<Attachment>(e => {
e.HasOne(a => a.Blob)
.WithOne()
.HasForeignKey<AttachmentBlob>(b => b.Id);
});
modelBuilder.Entity<AttachmentBlob>(e => {
e.ToTable("Attachment");
});
然后,您可以将它们读取或写入为字节数组或流;
public static async Task Read(DbContext db,Attachment attachment,Func<Stream,Task> callback)
{
await db.Database.OpenConnectionAsync();
try {
var conn = db.Database.GetDbConnection();
var cmd = conn.CreateCommand();
var parm = cmd.CreateParameter();
cmd.Parameters.Add(parm);
parm.ParameterName = "@id";
parm.Value = attachment.Id;
cmd.CommandText = "select File from Attachment where Id = @id";
using (var reader = await cmd.ExecuteReaderAsync()){
if (await reader.ReadAsync())
await callback(reader.GetStream(0));
}
} finally {
await db.Database.CloseConnectionAsync();
}
}
public class AttachmentResult : FileStreamResult
{
private readonly DbContext db;
private readonly Attachment attachment;
public AttachmentResult(DbContext db,Attachment attachment) : base(new MemoryStream(),attachment.ContentType)
{
this.db = db;
this.attachment = attachment;
}
public override async Task ExecuteResultAsync(ActionContext context)
{
await Read(db,attachment,async s => {
FileStream = s;
await base.ExecuteResultAsync(context);
});
}
}
public static async Task Write(DbContext db,Stream content)
{
await db.Database.OpenConnectionAsync();
try {
var conn = db.Database.GetDbConnection();
var cmd = conn.CreateCommand();
cmd.Transaction = db.Database.CurrentTransaction?.GetDbTransaction();
var parm = cmd.CreateParameter();
cmd.Parameters.Add(parm);
parm.ParameterName = "@id";
parm.Value = attachment.Id;
parm = cmd.CreateParameter();
cmd.Parameters.Add(parm);
parm.ParameterName = "@content";
parm.Value = content;
cmd.CommandText = "update Attachment set File = @content where Id = @id";
await cmd.ExecuteNonQueryAsync();
} finally {
await db.Database.CloseConnectionAsync();
}
}
public static Task InsertAttachment(DbContext db,Stream content){
var strat = db.Database.CreateExecutionStrategy();
return strat.ExecuteAsync(async () => {
using (var trans = await db.Database.BeginTransactionAsync())
{
db.Set<Attachment>.Add(attachment);
await db.SaveChangesAsync();
await Write(db,content);
trans.Commit();
db.ChangeTracker.AcceptAllChanges();
}
});
}
本文链接:https://www.f2er.com/2681074.html