GridFS позволяет сохранять и получать из БД MongoDB файлы. Рассмотрим, как мы можем использовать GridFS в приложении на ASP.NET Core. Прежде всего нам надо добавить в проект Nuget-пакет MongoDB.Driver.GridFS.
Далее определим в файле Program.cs следующий код:
using MongoDB.Bson; using MongoDB.Driver; using MongoDB.Driver.GridFS; var client = new MongoClient("mongodb://localhost:27017"); var db = client.GetDatabase("test"); var builder = WebApplication.CreateBuilder(); var app = builder.Build(); // по адресу "/" отправляем список с ссылками на файлы app.MapGet("/", async(context) => { IGridFSBucket gridFS = new GridFSBucket(db); // получаем список файлов var files = await gridFS.FindAsync("{}"); string fileListHtml = ""; // формируем из списка файлов список ul с ссылками на файлы foreach(var file in files.ToList()) { fileListHtml = @$"{fileListHtml}<li> <p><a href='file/{file.Id}'>{file.Filename}</a> </p> <form action='/delete/{file.Id}' method='post'><input type='submit' value='Удалить' /></form> </li>"; } // отправляем сформированный код html context.Response.ContentType = "text/html"; await context.Response.WriteAsync(@$"<!DOCTYPE html><html> <head> <meta charset='utf-8'/> <title>METANIT.COM</title> </head> <body> <h2>Список файлов</h2> <ul>{fileListHtml}</ul> </body></html>"); }); // по адресу "/file/{id}" отправляем файл по id app.MapGet("/file/{id}", async (HttpContext context, string id) => { IGridFSBucket gridFS = new GridFSBucket(db); await gridFS.DownloadToStreamAsync(new ObjectId(id), context.Response.Body); }); // по адресу "/delete/{id}" удаляем файл по id app.MapPost("/delete/{id}", async (HttpContext context, string id) => { IGridFSBucket gridFS = new GridFSBucket(db); await gridFS.DeleteAsync(new ObjectId(id)); context.Response.Redirect("/"); }); // по адресу "/upload" отправляем страницу для загрузки файлов app.MapGet("/upload", async (context) => { string html = @"<!DOCTYPE html> <html> <head> <meta charset='utf-8'/> <title>METANIT.COM</title> </head> <body> <h2>Выберите файлы для загрузки</h2> <form action='upload' method='post' enctype='multipart/form-data'> <input type='file' name='uploads' /><br><br> <input type='file' name='uploads' /><br><br> <input type='submit' value='Загрузить' /> </form> </body> </html>"; context.Response.ContentType = "text/html"; await context.Response.WriteAsync(html); }); // по POST-запросу на адрес "/upload" получаем загруженные файлы и сохраняем в бд app.MapPost("/upload", async (context) => { IGridFSBucket gridFS = new GridFSBucket(db); // проходим по всем файлам, получаем из них поток и сохраняем в gridfs foreach (var file in context.Request.Form.Files) { using (var stream = file.OpenReadStream()) { await gridFS.UploadFromStreamAsync(file.FileName, stream); } } context.Response.Redirect("/"); }); app.Run();
Разберем в общих чертах этот код. Вначале создается клиент MongoClient и объект IMongoDatabase, который будет представлять базу данных "test":
var client = new MongoClient("mongodb://localhost:27017"); // определяем клиент var db = client.GetDatabase("test"); // определяем объект базы данных
Поскольку для простоты весь код веб-приложения определен в одном файле Program.cs, то нет смысла задействовать встроенную систему внедрения зависимостей, и добавлять MongoClient и IMongoDatabase в приложение в виде сервисов. Поэтому проще их определить в виде глобальных переменных.
Далее после создания объекта WebApplication определяем конечную точку, которая обрабатывает GET-запросы к корню приложения и получает информацию обо всех файлах из базы данных:
app.MapGet("/", async(context) => { IGridFSBucket gridFS = new GridFSBucket(db); // получаем список файлов var files = await gridFS.FindAsync("{}"); string fileListHtml = ""; // формируем из списка файлов список ul с ссылками на файлы foreach(var file in files.ToList()) { fileListHtml = @$"{fileListHtml}<li> <p><a href='file/{file.Id}'>{file.Filename}</a> </p> <form action='/delete/{file.Id}' method='post'><input type='submit' value='Удалить' /></form> </li>"; } // отправляем сформированный код html context.Response.ContentType = "text/html"; await context.Response.WriteAsync(@$"<!DOCTYPE html><html> <head> <meta charset='utf-8'/> <title>METANIT.COM</title> </head> <body> <h2>Список файлов</h2> <ul>{fileListHtml}</ul> </body></html>"); });
Здесь считываем с помощью вызова gridFS.FindAsync("{}")
список данных файлов из БД и формируем из него html-элементы <li>
, которые содержат ссылку на сам файл и кнопку для его удаления. Затем вставляем
сформированные li-элементы в код html-страницы и отправляем его клиенту. То есть при обращении по адресу "/" пользователь увидит список файлов.
Далее определена конечная точка, которая обрабатывает GET-запросы по адресу "/file/{id}", то есть в качестве последнего сегмента принимает параметр id, который представляет идентификатор файла в бд:
app.MapGet("/file/{id}", async (HttpContext context, string id) => { IGridFSBucket gridFS = new GridFSBucket(db); await gridFS.DownloadToStreamAsync(new ObjectId(id), context.Response.Body); });
В данном случае с помощью метода gridFS.DownloadToStreamAsync
загружаем файл из БД в поток ответа context.Response.Body
. Таким образом,
пользователь увидит файл в браузере.
Затем определена конечная точка, которая обрабатывает POST-запросы по адресу "/delete/{id}" - в качестве параметра id передается идентификатор файла в бд.
app.MapPost("/delete/{id}", async (HttpContext context, string id) => { IGridFSBucket gridFS = new GridFSBucket(db); await gridFS.DeleteAsync(new ObjectId(id)); context.Response.Redirect("/"); });
Здесь с помощью метода gridFS.DeleteAsync()
удаляем файл по id и затем переадресуем пользователь на главную страницу по списком файлов.
Затем определяем конечную точку, которая обрабатывает GET-запросы по адресу "/upload" и отправляет пользователю html-страницу для загрузки пары файлов:
app.MapGet("/upload", async (context) => { string html = @"<!DOCTYPE html> <html> <head> <meta charset='utf-8'/> <title>METANIT.COM</title> </head> <body> <h2>Выберите файлы для загрузки</h2> <form action='upload' method='post' enctype='multipart/form-data'> <input type='file' name='uploads' /><br><br> <input type='file' name='uploads' /><br><br> <input type='submit' value='Загрузить' /> </form> </body> </html>"; context.Response.ContentType = "text/html"; await context.Response.WriteAsync(html); });
И в конце определяем конечную точку, которая обрабатывает POST-запросы по тому же адресу, получает из запроса отправленные файлы и с помощью метода
gridFS.UploadFromStreamAsync()
сохраняет их в бд:
app.MapPost("/upload", async (context) => { IGridFSBucket gridFS = new GridFSBucket(db); // проходим по всем файлам, получаем из них поток и сохраняем в gridfs foreach (var file in context.Request.Form.Files) { using (var stream = file.OpenReadStream()) { await gridFS.UploadFromStreamAsync(file.FileName, stream); } } context.Response.Redirect("/"); });
Например, запустим проект и перейдем по адресу "/upload" для загрузки файлов. Загрузим пару файлов:
После успешной загрузки нас переадресует на главную страницу со списком файлов:
Мы можем нажать на файл, и сервер отправит выбранный файл. Например, если файл - изображение, то браузер отобразит его:
При нажатии на кнопку удаления файл будет удален.