EmbedIO со списком неизвестных веб-API - PullRequest
0 голосов
/ 16 февраля 2020

Я хочу иметь модульную настройку EmbedIO с динамическим c списком неизвестных типов контроллеров веб-API. Я думал, что это будет легко :( Но в данный момент я застрял при регистрации веб-API:

// Some APIs to setup at the EmbedIO webserver in "Server"
Dictionary<string, WebApiController> apis = ...;

// Register the APIs at the webserver
foreach(KeyValuePair<string, WebApiController> kvp in apis)
{
    // Exception: "Controller type must be a subclass of WebApiController."
    Server.WithWebApi(kvp.Key, m => m.WithController(() => kvp.Value));
}

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

Я попытался с dynamic вместо WebApiController или вернул object и дал тип в качестве первого параметра для WithController - что бы я ни пытался, это приводило к исключению; Или когда я использую class WebApiControllerWrapper : WebApiController и Dictionary<string, WebApiControllerWrapper>, экспортированные методы контроллера окончательного типа отсутствуют, потому что они не определены в WebApiControllerWrapper.

Кажется, единственный способ - это использовать отражение для вызова c generi WithController - или кто-нибудь знает другое рабочее решение (я в. NET Standard 2.1)?

1 Ответ

0 голосов
/ 17 февраля 2020

Мне удалось решить это с помощью дерева выражений, которое вызывает обобщенный c метод для создания фабричной функции:

public class ModularWebApiController : WebApiController
{
    public Func<T> CreateFactoryMethod<T>() where T : WebApiController => () => (T)this;
}

public static class Extensions
{
    public static WebApiModule WithController(this WebApiModule webApiModule, ModularWebApiController api)
    {
        Delegate factoryFunc = Expression
            .Lambda(Expression.Call(
                Expression.Constant(api), 
                typeof(ModularWebApiController).GetMethod("CreateFactoryMethod").MakeGenericMethod(api.GetType())
            ))
            .Compile();
        return (WebApiModule)typeof(WebApiModuleExtensions)
                    .GetMethods(BindingFlags.Static | BindingFlags.Public)
                    .Single(mi => mi.IsGenericMethod & mi.Name == "WithController" && mi.GetParameters().Length == 2)
                    .MakeGenericMethod(api.GetType())
            .Invoke(null, new object[] { webApiModule, factoryFunc.DynamicInvoke(Array.Empty<object>()) });
    }
}

Мне нужно было только убедиться, что все типы контроллеров веб-API расширяют * Типа 1004 *, и мне пришлось изменить настройку модульного веб-API для EmbedIO:

Dictionary<string, ModularWebApiController> apis = ...;
foreach(KeyValuePair<string, ModularWebApiController> kvp in apis)
{
    Server.WithWebApi(kvp.Key, m => m.WithController(kvp.Value));
}

После просмотра источника EmbedIO я думаю, что это единственный способ настроить модульный веб-API, где Код не знает, какие типы контроллеров веб-API будут использоваться.

Теперь я могу загрузить и скопировать любой тип контроллера веб-API, настроенный в файле конфигурации JSON, например:

[
    {
        "Type": "name.space.WebApiControllerTypeName",
        "Path": "/webapipath/"
    },
    {
        "Type": "name.space.AnotherWebApiControllerTypeName",
        "Path": "/anotherwebapipath/"
    }
]

Просто для примера. Интересно, почему кажется, что никто больше не хочет этого делать;)

...