我想在来自 SQL 数据库的 ASP.NET 核心 MVC 视图上显示视频
I want to Show Video on ASP.NET Core MVC View from SQL Database
所以基本上我已经使用下面的逻辑将我的视频文件存储到我的 SQL 服务器数据库 table:
using (var dataStream = new MemoryStream())
{
await file.CopyToAsync(dataStream);
VideoSegment video = new VideoSegment
{
VideoData = dataStream.ToArray(),
ProfileidForVideoSegment = userprofileid.Id
};
Context.VideoSegments.Add(video);
Context.SaveChanges();
}
所以使用上面的代码,我的数据以 varbinary(MAX) 的形式完美地存储到 table,但现在我想检索此视频数据以显示在我的 asp.net 核心网站上播放的视频。我为此搜索了很多,但每次我都找到与 aspx 相关的解决方案,简单 asp.net MVC。但仍在搜索 ASP.NET 核心 MVC 网站,因为我想在我的 asp.net 核心 MVC 不简单 asp.net MVC 网站中显示视频。
所以请告诉我如何完成这项工作的解决方案。任何形式的帮助将不胜感激。
谢谢
这是一个您可以关注的工作演示:
型号:
public class VideoSegment
{
public int Id { get; set; }
public byte[] VideoData { get; set; }
}
Create.cshtml:
@model VideoSegment
<h1>Create</h1>
<div class="row">
<div class="col-md-4">
<form asp-action="Create" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="VideoData" class="control-label"></label>
<input name="file" type="file" class="form-control" />
<span asp-validation-for="VideoData" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
VideoSegmentsController:
public IActionResult Create()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Create([FromForm]IFormFile file)
{
using (var dataStream = new MemoryStream())
{
await file.CopyToAsync(dataStream);
VideoSegment video = new VideoSegment
{
VideoData = dataStream.ToArray(),
};
_context.VideoSegment.Add(video);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
}
成功添加视频片段后,您将重定向到 Index 操作并显示视频:
Index.cshtml:
@model IEnumerable<VideoSegment>
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.VideoData)
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
<video autoplay controls src="/Home/SampleVideoStream?id=@item.Id"></video>
</td>
</tr>
}
</tbody>
</table>
VideoSegmentsController:
public class VideoSegmentsController : Controller
{
private readonly YourDbContext _context;
public VideoSegmentsController(YourDbContext context)
{
_context = context;
}
// GET: VideoSegments
public async Task<IActionResult> Index()
{
return View(await _context.VideoSegment.ToListAsync());
}
}
家庭控制器:
public class HomeController : Controller
{
private readonly YourDbContext _context;
public HomeController(YourDbContext context)
{
_context = context;
}
public IActionResult SampleVideoStream(int id)
{
var data = _context.VideoSegment.Find(id);
return File(data.VideoData, "video/mp4");
}
}
可以直接从 SQL 服务器 table 流式传输 varbinary。但是你需要克服一个障碍。
首先,您需要一种访问 DbDataReader
的方法。这样您就可以重用与 EF Core 相同的基础设施,因此您无需自己管理连接。由于不支持此位,以后可能会损坏。
// Based on https://github.com/dotnet/efcore/blob/16188163c24b1c803c4d694e9222a2f717fcb376/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs#L211
public static Task<RelationalDataReader> ExecuteReaderRawAsync(this DatabaseFacade db, string sql, IEnumerable<object> parameters, CancellationToken cancellationToken = default)
{
var dependencies = ((IDatabaseFacadeDependenciesAccessor)db).Dependencies as IRelationalDatabaseFacadeDependencies;
var cmd = dependencies.RawSqlCommandBuilder
.Build(sql, parameters);
return cmd.RelationalCommand
.ExecuteReaderAsync(new RelationalCommandParameterObject(
dependencies.RelationalConnection,
cmd.ParameterValues,
null,
((IDatabaseFacadeDependenciesAccessor)db).Context,
dependencies.CommandLogger
), cancellationToken);
}
现在您可以select将 varbinary 列作为流;
using var reader = await context.Database.ExecuteReaderRawAsync(
"select VideoData from VideoSegment where Id = {0}",
new object[] { Id });
if (await reader.ReadAsync()){
using var stream = reader.DbDataReader.GetStream(0);
// TODO copy stream to the response.
}
将流复制到数据库列中稍微容易一些。尽管如果您使用 EF Core 插入行,则必须先执行此操作。
var streamParm = new SqlParameter()
{
SqlDbType = SqlDbType.VarBinary,
Value = stream
};
await context.Database.ExecuteSqlInterpolatedAsync(
$"update VideoSegment set VideoData = {streamParm} where id = {Id}");
所以基本上我已经使用下面的逻辑将我的视频文件存储到我的 SQL 服务器数据库 table:
using (var dataStream = new MemoryStream())
{
await file.CopyToAsync(dataStream);
VideoSegment video = new VideoSegment
{
VideoData = dataStream.ToArray(),
ProfileidForVideoSegment = userprofileid.Id
};
Context.VideoSegments.Add(video);
Context.SaveChanges();
}
所以使用上面的代码,我的数据以 varbinary(MAX) 的形式完美地存储到 table,但现在我想检索此视频数据以显示在我的 asp.net 核心网站上播放的视频。我为此搜索了很多,但每次我都找到与 aspx 相关的解决方案,简单 asp.net MVC。但仍在搜索 ASP.NET 核心 MVC 网站,因为我想在我的 asp.net 核心 MVC 不简单 asp.net MVC 网站中显示视频。 所以请告诉我如何完成这项工作的解决方案。任何形式的帮助将不胜感激。 谢谢
这是一个您可以关注的工作演示:
型号:
public class VideoSegment
{
public int Id { get; set; }
public byte[] VideoData { get; set; }
}
Create.cshtml:
@model VideoSegment
<h1>Create</h1>
<div class="row">
<div class="col-md-4">
<form asp-action="Create" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="VideoData" class="control-label"></label>
<input name="file" type="file" class="form-control" />
<span asp-validation-for="VideoData" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
VideoSegmentsController:
public IActionResult Create()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Create([FromForm]IFormFile file)
{
using (var dataStream = new MemoryStream())
{
await file.CopyToAsync(dataStream);
VideoSegment video = new VideoSegment
{
VideoData = dataStream.ToArray(),
};
_context.VideoSegment.Add(video);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
}
成功添加视频片段后,您将重定向到 Index 操作并显示视频:
Index.cshtml:
@model IEnumerable<VideoSegment>
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.VideoData)
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
<video autoplay controls src="/Home/SampleVideoStream?id=@item.Id"></video>
</td>
</tr>
}
</tbody>
</table>
VideoSegmentsController:
public class VideoSegmentsController : Controller
{
private readonly YourDbContext _context;
public VideoSegmentsController(YourDbContext context)
{
_context = context;
}
// GET: VideoSegments
public async Task<IActionResult> Index()
{
return View(await _context.VideoSegment.ToListAsync());
}
}
家庭控制器:
public class HomeController : Controller
{
private readonly YourDbContext _context;
public HomeController(YourDbContext context)
{
_context = context;
}
public IActionResult SampleVideoStream(int id)
{
var data = _context.VideoSegment.Find(id);
return File(data.VideoData, "video/mp4");
}
}
可以直接从 SQL 服务器 table 流式传输 varbinary。但是你需要克服一个障碍。
首先,您需要一种访问 DbDataReader
的方法。这样您就可以重用与 EF Core 相同的基础设施,因此您无需自己管理连接。由于不支持此位,以后可能会损坏。
// Based on https://github.com/dotnet/efcore/blob/16188163c24b1c803c4d694e9222a2f717fcb376/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs#L211
public static Task<RelationalDataReader> ExecuteReaderRawAsync(this DatabaseFacade db, string sql, IEnumerable<object> parameters, CancellationToken cancellationToken = default)
{
var dependencies = ((IDatabaseFacadeDependenciesAccessor)db).Dependencies as IRelationalDatabaseFacadeDependencies;
var cmd = dependencies.RawSqlCommandBuilder
.Build(sql, parameters);
return cmd.RelationalCommand
.ExecuteReaderAsync(new RelationalCommandParameterObject(
dependencies.RelationalConnection,
cmd.ParameterValues,
null,
((IDatabaseFacadeDependenciesAccessor)db).Context,
dependencies.CommandLogger
), cancellationToken);
}
现在您可以select将 varbinary 列作为流;
using var reader = await context.Database.ExecuteReaderRawAsync(
"select VideoData from VideoSegment where Id = {0}",
new object[] { Id });
if (await reader.ReadAsync()){
using var stream = reader.DbDataReader.GetStream(0);
// TODO copy stream to the response.
}
将流复制到数据库列中稍微容易一些。尽管如果您使用 EF Core 插入行,则必须先执行此操作。
var streamParm = new SqlParameter()
{
SqlDbType = SqlDbType.VarBinary,
Value = stream
};
await context.Database.ExecuteSqlInterpolatedAsync(
$"update VideoSegment set VideoData = {streamParm} where id = {Id}");