Работа с файлами из базы данных MongoDB и GridFS в ASP.NET

Последнее обновление: 30.10.2022

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" для загрузки файлов. Загрузим пару файлов:

Загрузка файлов в GridFS в базу данных MongoDB в ASP.NET и C#

После успешной загрузки нас переадресует на главную страницу со списком файлов:

Получение файлов из GridFS из базы данных MongoDB в ASP.NET и C#

Мы можем нажать на файл, и сервер отправит выбранный файл. Например, если файл - изображение, то браузер отобразит его:

Загрузка файлов из базы данных MongoDB с помощью GridFS в ASP.NET и C#

При нажатии на кнопку удаления файл будет удален.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850