Подтвердить что ты не робот

Является ли vNext полностью "условно-ориентированным программированием"?

Я вижу тревожную тенденцию в vNext и нуждаюсь в некотором назидании, потому что Im не видит большую картину того, где мы принимаем сообщество. Почему vNext отказался от базовых парадигм ООП, таких как интерфейсы, вместо того, что я могу описать только как "программирование на основе условных обозначений"?

Возможно, мне просто не повезло, и типы классов, с которых я начал, - это разовые единороги, но в течение коротких трех дней, когда я работал с vNext, я сталкивался с двумя классами, которые, похоже, отказались от базовых программных конструкций, которые меня озадачили.

Первый - это класс промежуточного программного обеспечения. Средство промежуточного уровня в vNext предназначено для работы без реализации какого-либо интерфейса или наследования из какого-либо общего базового класса, но магически вызывается в конвейере vNext с помощью метода Invoke. Когда мы решили, что интерфейсные контракты бессмысленны? Это просто не имеет для меня никакого смысла. Если есть третья сторона, которая собирается позвонить в мое промежуточное ПО, тогда должен быть контракт, в котором говорится, что я собираюсь реализовать XX. Он выражает намерение, а также обеспечивает проверку времени компиляции. Без контракта нет ничего, что помешало бы третьей стороне полностью изменить подпись метода, которого он ожидает, и только во время выполнения вы знаете, что что-то пошло не так. Не говоря уже о бедных разработчиках, мне и моим родственникам, глядя на код неспособный расшифровать то, что должно быть реализовано, и последовательность событий жизненного цикла, которые заставляют меня от пункта A до пункта B.

public class SampleMiddleware // complete lack of interface implementation or base class inheritance
{
    private readonly RequestDelegate _next;

    public SampleMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    // yet a magical method that somehow gets invoked in a pipeline.. wth..
    public async Task Invoke(HttpContext context)
    {
        context.Response.ContentType = "text/html";
        await context.Response.WriteAsync("SampleMidlleware fired!");
    }
} 

Второй - это веб-приложение, которое самостоятельно размещается в консольном приложении. Когда вы пытаетесь запустить команду для запуска самостоятельного хостинга (dnx . web) только во время выполнения, вы получаете ошибку, которую забыли магический класс Startup. Опять же, потому что мне не хватает терминологии, и я могу описать это только как "основанное на соглашениях программирование". В OWIN мы, по крайней мере, имели OwinStartupAttribute, которые могли быть применены на уровне сборки. Теперь мы остались, ну ничего.. Ничто в моем коде не указывает, что я намерен определить класс запуска, который может быть вызван сторонней программой.

System.InvalidOperationException: тип с именем "StartupDevelopment" или "Запуск" не удалось найти в сборке "ConsoleApp1".

Угадайте, что происходит, когда вы следуете "подсказке" из приведенного выше исключения?

System.InvalidOperationException: метод, названный 'ConfigureDevelopment' или 'Configure' в типе "ConsoleApp1.Startup" не найден.

Программирование неудачей, да, детка! Нет проблем, это будет только четверть моей оценки того, сколько времени потребуется, чтобы отправить это приложение. О, и можете ли вы угадать, какой интерфейс реализует класс Startup? Правильно, ничего, нада, молния. Вы это чувствуете? Я чувствую запах дыма..

ConsoleApp1

public class Program
{
    public void Main(string[] args)
    {
        var config = new Configuration()
                       .AddJsonFile("config.json")
                       .AddCommandLine(args);

        Console.WriteLine(config.Get("message"));

        foreach (var arg in args)
        {
            Console.WriteLine(arg);
        }

        Console.ReadLine();
    }
}

Startup.cs

public class Startup
{
    public IConfiguration Configuration { get; set; }

    public Startup(IHostingEnvironment env)
    {
        // Setup configuration sources.
        Configuration = new Configuration()
            .AddJsonFile("config.json")
            .AddEnvironmentVariables();
    }
}

project.json

  "commands": {
    "ConsoleApp1": "ConsoleApp1",
    "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000/"
  }

Любой из вас "старые таймеры" напомнит global.asax и его использование событий приложений на основе конвенций? Application_Error(object send, EventArgs e) Вы чувствуете запах? Кто хочет бедных с помощью статей и документации, потому что они не могут вспомнить "конвенцию"? Его, как и они, заявили: "Винт OOP, проверка времени компиляции винтов, винтовая визуальная студия и ее передовая интеллисенса, пусть они едят документацию".

Пожалуйста, назидайте меня на это безумие...

4b9b3361

Ответ 1

Я думаю, что до сих пор вы стали жертвой нескольких "одноразовых единорогов". Кажется, что весь пакет Microsoft.AspNet.Hosting заполнен ими. Тем не менее, большая часть этого достигается благодаря инъекции зависимости уровня метода, которая по самой своей природе не может придерживаться контракта. И вы правы, это соответствует той же тенденции, что и в ASP.Net, для нескольких платформ. Следуйте соглашениям, чтобы свести к минимуму конфигурацию или настроить ее самостоятельно. Дело в том, что на самом деле сколько фреймворков идет, поэтому вы можете "вставать и работать" с минимальным количеством кода.

Запуск

В качестве примера команда "web" позволяет указать вашу сборку запуска в командной строке с помощью --app или из файл конфигурации Microsoft.AspNet.Hosting.ini по умолчанию, используя Hosting:Application. Тот факт, что вам не нужно создавать свой собственный WebHostBuilder, связано с программированием на основе условных обозначений, но вы можете, конечно, начать со своей собственной Program.cs и построить его самостоятельно, если хотите.

Middleware

Классы промежуточного ПО еще один пример внедрения уровня метода - многие параметры могут быть добавлены непосредственно из приложения IServiceProvider. Я не думаю, что могу добавить что-нибудь полезное в то, что сказал Тугберк в блоге; это хорошо прочитано.

Контроллеры/Действия

Я знаю, что вы не спрашивали о контроллерах, но действия в контроллерах похожи; вы не найдете интерфейс на них в любой из популярных инфраструктур MVC. Вместо этого параметры вводятся зависимостями при использовании привязки модели. В настоящее время команда MVC6 позволяет украшать [FromServices] для ввода зависимостей на уровне запросов через функцию привязки модели, но я слышал рассказы, которые они собираются удалить. Я надеюсь, что они настроили его на внедрение более последовательно напрямую от поставщика услуг, чтобы мы могли использовать его в наших собственных рамках.

Другие мысли

Я искренне желаю, чтобы был хороший способ ссылаться на "группу методов" (как его называет компилятор), не зная параметров, чтобы мы могли сделать больше инъекций зависимостей на уровне метода и меньше соблюдения определенных интерфейсов. Я также хотел бы, чтобы был хороший способ объявить интерфейс, что у него есть метод, и кто волнует, что такое аргументы.

public interface IMiddleware
{
    // No syntax for this
    Task Invoke(... any);
}

// No syntax for this either, unless you know in advance what the parameters will be
await serviceProvider.InjectAndInvoke(middleware.Invoke);

Если бы С# добавили это в спецификацию, то у нас наверняка были бы интерфейсы, которые вы ищете.