vNext完全是"基于会议的编程"吗?

Tug*_*ain 27 .net visual-studio-2015 asp.net-core

我在vNext中看到一个令人不安的趋势,需要一些启发,因为我没有看到我们被视为社区的大局.为什么vNext放弃了基本的OOP范式,比如接口代替我只能描述为"基于约定的编程"?

也许我只是运气不好,我开始的课程类型是一次性的独角兽,但在短短的三天里,我一直在使用vNext,我遇到了两个似乎放弃了基本编程结构的类让我神秘莫测.

第一个是中间件类.vNext中的中间件设计为在不实现任何接口的情况下工作,也不从任何公共基类继承,但通过Invoke方法在vNext管道中神奇地调用.我们什么时候决定接口合同毫无意义?这对我来说根本没有意义.如果有第三方打算调用我的中间件,那么应该有一份合同,声明我将实施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!");
    }
} 
Run Code Online (Sandbox Code Playgroud)

第二个是在控制台应用程序中自托管的Web应用程序.当您尝试运行该命令以dnx . web仅在运行时启动自托管()时,您会收到错误,即您忘记了一个神奇的Startup类.再次,因为我缺乏术语,我只能将其描述为"基于约定的编程".在OWIN我们至少有OwinStartupAttribute可能在装配级应用.现在我们离开了,什么都没有.我的代码中没有任何内容表明我的意图是定义一个可以被第三方程序调用的启动类.

System.InvalidOperationException:在程序集"ConsoleApp1"中找不到名为"StartupDevelopment"或"Startup"的类型.

猜猜当你按照上面的例外中的"提示"时会发生什么?

System.InvalidOperationException:找不到"ConsoleApp1.Startup"类型中名为"ConfigureDevelopment"或"Configure"的方法.

失败的编程,是的宝贝!没问题,这只会使我估计需要多长时间才能运送这个应用程序.哦,你能猜出这个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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Startup.cs

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

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

project.json

  "commands": {
    "ConsoleApp1": "ConsoleApp1",
    "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000/"
  }
Run Code Online (Sandbox Code Playgroud)

你们中的任何一个"老定时器"都会回忆起global.asax它对基于会议的应用事件的使用吗?Application_Error(object send, EventArgs e)你闻到了吗?谁想通过文章和文档来穷,因为他们不记得"惯例"?这就像他们宣称的那样,"螺旋OOP,螺旋编译时检查,螺旋Visual Studio及其高级智能感知,让他们吃文档."

请教我这个疯狂......

Mat*_*rey 8

我认为到目前为止,你已成为一些"一次性独角兽"的受害者.整个Microsoft.AspNet.Hosting包裹似乎充满了它们.然而,其中很大一部分归功于方法级依赖注入,它本质上不能遵守契约.而且你是对的,这是跟随ASP.Net一段时间以来的趋势,对于多个平台:按照惯例来最小化配置,或者自己配置它.问题是,实际上有多少框架正在运行,因此您可以使用尽可能少的代码"启动并运行".

启动

举个例子,在"网络"命令允许您指定启动组件上使用命令行--app默认Microsoft.AspNet.Hosting.ini配置文件使用Hosting:Application.您不必自己构建自己的事实WebHostBuilder是由于基于约定的编程,但您可以从您自己的Program.cs开始,如果您愿意,可以自己构建它.

中间件

中间件类是方法级注入的另一个例子 - 许多参数可以直接从应用程序中添加IServiceProvider.我不认为我可以添加任何有助于Tugberk在博客文章中说的内容; 这是一个很好的阅读.

控制器/行动

我知道你没有询问控制器,但控制器中的动作类似; 你不会在任何流行的MVC框架中找到它们的接口.相反,参数是使用模型绑定依赖注入的.目前,MVC6团队允许[FromServices]装饰在via Model Binding中注入请求级别的依赖项,但我听说过他们正在考虑删除它的故事.我希望他们将其设置为直接从服务提供商注入更多,因此我们可以在我们自己的框架中使用它.

其他想法

老实说,我希望在不知道参数的情况下有一个很好的方法来引用"方法组"(编译器调用它),这样我们就可以进行更多的方法级依赖注入,减少对特定接口的依从性.我还希望有一种很好的方法来声明一个接口,它有一个方法,谁在乎这些参数是什么.

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);
Run Code Online (Sandbox Code Playgroud)

如果C#要将其添加到规范中,那么我们肯定可以拥有您正在寻找的接口.

  • @TugboatCaptain我认为我们不需要任何东西,就像我们没有"Main"方法那样.没有人试图理解为什么我们没有接口,因为它是众所周知的.中间件和启动类也是如此. (2认同)