C# ASP.NET. Можно ли хранить модель локально?

У меня есть модель Note с полями:

public string Title { get; set; }
public string Text { get; set; }

Я хочу добавить в эту модель любую запись(или даже записи) через один контроллер:

Note note = new Note();
note.Add("Заголовок", "Текст");

И получить список Note уже в другом контроллере. Без использования бд(MSSQL, Postrge - не важно)

Можно ли такое реализовать?


Ответы (1 шт):

Автор решения: Sergey Savelyev

Можно, но не всегда нужно.

UPD: Нижеизложенный способ показывает приблизительную реализацию, но не затрагивает вопросы грамотной абстракции. По-хорошему NotesInMemoryRepository должен реализовывать некий интерфейс INotesRepository и не быть статическим, а регистрироваться как Singleton в контейнере DI, чтобы впоследствии можно было заинжектить именно INotesRepository в нужный контроллер/сервис и не зависеть от конкретной реализации. Автор, для более подробной информации на эту тему, почитайте о принципах SOLID, в частности о последнем из них: принцип инверсии зависимостей. За замечание спасибо @bulson

Однако, если прям вот очень нужно.
Если я правильно понял, вас интересует реализация некоего репозитория, но не в БД, а в памяти. В таком случае, подходящим вариантом будет ConcurrentDictionary<,>, за счёт обеспечения потокобезопасности, на случай нескольких одновременных запросов из контроллеров.

Также, из логических соображений, я бы советовал добавить поле Id в вашу модель, для удобства хранения. Однако, если преследуете цель сделать название строго уникальным, то добавлять это свойство не обязательно, можно организовать всё тоже самое через Title.

Также, поскольку напрямую возвращать объекты из словаря опасно тем, что возвращается ссылка на объект, лучше создать метод Copy() в классе Note, и возвращать его копию. Это нужно для того, чтобы редактируемый вне репозитория объект не изменялся в этот же момент в самом репозитории.

public class Note
{
    public string Id { get; set; }

    public string Title { get; set; }

    public string Text { get; set; }

    public Note Copy() => new Note { Id = this.Id, Title = this.Title, Text = this.Text };
}

Примерно так мог бы выглядеть статический репозиторий в памяти. Обращаться к нему можно из любого контроллера.

public static class NotesInMemoryRepository
{
    private static ConcurrentDictionary<string, Note> _notes;

    static NotesInMemoryRepository()
    {
        _notes = new ConcurrentDictionary<string, Note>();
    }

    public static Note Get(string id)
    {
        if (!_notes.ContainsKey(id))
        {
            throw new Exception($"Note with id {id} not found");
        }

        return _notes[id].Copy();
    }

    public static Note[] GetAll()
    {
        return _notes.Select(keyValue => keyValue.Value.Copy()).ToArray();
    }

    public static Note Create(string title, string text)
    {
        var note = new Note
        {
            Id = Guid.NewGuid().ToString(), // В качестве Id генерируем уникальный GUID
            Title = title,
            Text = text
        };

        _notes.TryAdd(note.Id, note);

        return note.Copy();
    }

    public static Note Update(string id, Note note)
    {
        if (!_notes.ContainsKey(id))
        {
            throw new Exception($"Note with id {id} not found");
        }

        var noteToUpdate = _notes[id];
        noteToUpdate.Title = note.Title;
        noteToUpdate.Text = note.Text;

        return noteToUpdate.Copy();
    }

    public static void Delete(string id)
    {
        if (!_notes.ContainsKey(id))
        {
            throw new Exception($"Note with id {id} not found");
        }

        _notes.TryRemove(id, out _);
    } 
}

Пример использования:

var createdNote = NotesInMemoryRepository.Create("Заголовок", "Текст"); // создана заметка с уникальным Id
createdNote.Title = "Новый заголовок"; // присвоим ей новый заголовок

var updatedNote = NotesInMemoryRepository.Update(createdNote.Id, createdNote); // и запишем обновку в репозиторий
NotesInMemoryRepository.Delete(updatedNote.Id); // а теперь удалим, потому что можем

В любом случае, подобный подход я бы советовал использовать только в случае, если вам нужно реализовать какой-то локальный кэш для не самых важных данных. Нужно отдавать себе отчёт, что подобный репозиторий и все данные в нём существуют только пока приложение запущено.

→ Ссылка