Как указать параметр типа динамического значения в действии веб-API? - PullRequest
0 голосов
/ 20 февраля 2019

Некоторый контекст

Я пытаюсь создать контроллер веб-API, способный работать с любой реализацией репозитория.Цель состоит в том, чтобы иметь возможность изменять реализации базы данных без необходимости прикасаться к контроллеру.

Репозитории могут работать с разными типами баз данных, следовательно, имеют разные типы столбцов PK.Например, SQL Server обычно использует int, а MongoDB обычно использует строки.Во время выполнения мой контроллер будет введен с правильной реализацией базы данных с помощью интерфейса репозитория.

Проблема

Внедрение зависимостей работает хорошо, и каждая реализация репо работает сама по себе,Проблема возникает на уровне действий в контроллере.

У каждого репо есть свое определение поля Id.Таким образом, репо является общим.Но я не могу отметить параметр действия как общий.Откуда он взял этот тип?Другой вариант - установить его как dynamic, но это означает, что мне нужно написать код, чтобы определить тип параметра, который я получил во время выполнения, и вручную проанализировать или преобразовать его перед передачей в репозиторий.

Какой-то код

В некотором смысле я пытаюсь добиться чего-то вроде этого:

// ----------------- Interfaces -----------------
interface IRepository
{
    Task<object> FindAsync(object id);
}

interface IRepository<TId> : IRepository where TId : struct
{
   Task<SomeData> FindAsync(TId id);
}

// ----------------- Base implementation -----------------
class SqlServerRepository : IRepository<int>
{
    public async Task<SomeData> FindAsync(int id) { ... }

    // Explicit implementation to allow access only through interface reference
    async Task<object> IRepository.FindAsync(object id) => await FindAsync((int)id);
}

class MongoDbRepository : IRepository<string>
{
    // Same example as SqlServerRepository but for string ids
}


// ----------------- The famous controller -----------------
public class SomeController : Controller
{
    private readonly IRepository db;

    public SomeController(IRepository db)
    {
        this.db = db;
    }

    public async Task<IAsyncResult> Get(dynamic id) // <<<< Problem starts here
    {
        return await db.FindAsync(id);
    }
}

Мой вопрос

Какмогу ли я указать в параметре универсальный параметр (или dynamic / что-нибудь еще?) таким образом, чтобы я мог просто передать его в репозиторий без приведения, анализа или ручного труда?

1 Ответ

0 голосов
/ 21 февраля 2019

Решено с использованием дженериков!Закончилось определение контроллера как универсального.Это заставляет .NET Core игнорировать его, чтобы не создавать его экземпляры.

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

При загрузке основного проекта Web Api .NET Core перебирает все ссылки на сборки, чтобы найти ApplicationFeatures, и автоматически находит новую реализацию контроллера!Магия!

Теперь у меня могут быть общие параметры действия.

/// ============ Main Project or Base Class Library =============
public class SomeController<TId> : Controller
{
    private readonly IRepository<TId> db;

    public SomeController(IRepository<TId> db)
    {
        this.db = db;
    }

    public async Task<IAsyncResult> Get(TId id)
    {
        return await db.FindAsync(id);
    }
}

/// =========== New Assembly ============
public class SomeController : SomeController<int>
{
    public SomeController(IRepository<int> db) : base(db) { }
}

Все, что остается сделать при изменении реализации базы данных, это реализовать универсальный репозиторий, наследовать универсальный контроллер изамените ссылку на внедряющую сборку в основном проекте!Та Дааа !!:)

Я люблю .NET ...

...