一个基本的 Katana 应用程序






4.87/5 (9投票s)
引言
正如我们在上一篇文章中所见,Katana 只是支持 OWIN 规范的一组组件,并用于创建解耦的 Web 应用程序。在 Katana 应用程序中,请求管道中的每个组件都可以轻松地替换为另一个组件。
存在用于构建 OWIN 规范中不同层的类型。有用于启动宿主、启动服务器(将监听并处理请求)的类型,以及代表管道中中间件组件的类型。
因此,例如,我们可以使用 WebApp 类来启动 Web 服务器,该服务器将监听特定端口,并使用这些类型将不同的中间件组件插入到管道中。
我们将了解 Katana 中有助于构建解耦 Web 应用程序的重要类型。
OWIN Katana 应用程序中一些重要的类型是:-
启动类
宿主使用此类来创建管道。它指定将成为请求管道一部分的各种组件。指定启动类有不同的方法。
我们可以通过以下三种不同的方式向运行时指定启动类。
- 基于命名约定的启动类指定方法 我们可以将启动类命名为 Startup,运行时将识别它为启动类。
- 基于属性的启动类指定方法 我们可以使用程序集属性 OwinStartup 在 AssemblyInfo.cs 中指定启动类。 [assembly: OwinStartup(typeof(SampleApplication.OurStartupClass))]
- 基于配置的启动类指定方法 <add key="owin:appStartup" value="StartupNamespace.StartupClass" /> 我们可以将值指定为命名空间后跟类名。
上述三种指定类名的方法按 указанный 顺序应用。因此,配置优先于属性和命名约定。所以即使我们有一个名为 Startup 的类,我们也可以在配置文件中指定另一个启动类名。
我们将使用第一种方法,定义一个启动类和该类中的一个 Configuration 方法。
public class Startup
{
public void Configuration(IAppBuilder app)
{
}
}
需要注意的是,方法名必须是 Configuration,否则我们会收到运行时错误,提示未定义名为 configuration 的方法。通过将方法重命名为 configuration1(或任何其他名称)并运行应用程序,我们可以验证这一点。正如预期的那样,我们会收到以下错误。
Configuration 方法向我们介绍了 Katana 中使用的另一个重要类型——IAppBuilder 接口。
IAppBuilder 接口
如上所示,Configuration 方法接收 IAppBuilder 引用。IAppBuilder 类型包含配置我们应用程序的方法。
这些方法是扩展方法,因此它们可以通过属于不同程序集的各种类型访问。所以我们需要添加正确的程序集来访问这些方法。如果我们查看IAppBuilder 的定义,它没有定义 Run() 方法,因为该方法是由AppBuilderUseExtensions类定义的。
当 Katana 需要处理我们应用程序的请求时,它会调用Run()方法。当浏览器向我们的应用程序发送请求时,使用 WebApp.Start() 方法中传递的 URL,此 Run 方法执行,我们在浏览器中收到响应消息。
app.Run(owin => owin.Response.WriteAsync("Hello from owin test app"));
Run 方法的输入参数是 Func 委托。这个 Func 委托接受另一个有用类型IOwinContext的对象并返回一个任务。
IOwinContext 接口
传递给 Run() 方法的 IOwinContext 引用属于 Microsoft.Owin 命名空间。除了包含各种环境属性的属性外,它还包装了 OWIN 规范中提到的环境字典。
IOwinContext 类型定义了以下有用成员
Request 包含请求特定属性。 | |
Response 包含响应特定属性。 | |
TraceOutput 用于跟踪响应 | |
Authentication 用于在应用程序中提供身份验证功能 | |
Get<T> 用于在环境中设置值 | |
Set<T> 用于从环境中获取值 | |
Environment Owin 暴露的用于在请求管道中传递值的字典 |
现在,在我们了解了IAppBuilder 和 IOwin 类型之后,我们将按如下方式实现 Configuration 方法。 在传递给 Run() 方法的 lambda 表达式中,我们将向 owin Environment 字典添加一个键,然后仅在浏览器中显示其值。
app.Run(owin => {
owin.Set<string>("firstname", "ashish");
return owin.Response.WriteAsync(string.Format("Hello your {0} is {1}",
"firstname",(string)owin.Get<string>("firstname")));
我们已经定义了 Startup 类和 Run 方法,但除非我们告诉运行时使用它来配置请求管道,否则它没什么用。由于我们将自托管应用程序,我们将使用另一个有用的类型WebApp Class。
WebApp 类
此类型包含加载和启动 Web 应用程序的方法。
WebApp 类属于 Microsoft.Owin.Hosting 命名空间,并包含 重载的 Start () 方法来加载和启动 Web 应用程序。虽然这些方法可用于启动 Web 应用程序,但它们在提供的参数和 Web 应用程序配置方面有所不同。
Start<Tstartup>() 使用我们在Tstartup中指定的入口类型启动 WebApplication。
Start<TStartup>(uri) 使用我们在Tstartup中指定的入口类型启动 WebApplication。并监听 uri 参数上传递的请求。
由于上述两种方法都返回一个IDisposable引用,我们可以将这些方法放在 using 块中调用。因此,每当控件退出我们的 using() 块时,我们的 webapplication 就会关闭。
以下是我们可用于启动 http 侦听器的代码,它监听指定 URL 和端口上的请求。 Startup 是我们在其中定义应用程序配置信息的类。配置信息允许 Katana 创建请求管道。
string uri = "https://:2000";
WebApp.Start<Startup>(uri)
我们还需要定义作为上面 Start 方法参数传递的 Startup 类。
执行完上面一行后,我们的应用程序将开始监听给定 URL 的请求。虽然我们这里使用了端口 2000,但我们可以使用任何可用端口。以下是启动我们在控制台应用程序 Main 方法中定义的 Web 服务器的代码。现在我们的 Web 服务器已经启动并正在监听请求。
static void Main(string[] args)
{
string uri = "https://:7990";
using (WebApp.Start<Startup>(uri))
{
Console.WriteLine("Web server on {0} starting.", uri);
Console.ReadKey();
Console.WriteLine("Web server on {0} stopping.", uri);
}
}
由于我们定义了 StartUp 类,我们将能够执行我们的应用程序,否则,如果我们不定义 startup 类,我们会收到一个编译错误,抱怨 StartUp 类未定义。
现在让我们按 F5 运行应用程序。应用程序开始执行后,我们将以下 URL 粘贴到浏览器中。这是我们的 Web 服务器正在监听请求的地址,如我们在 Main() 方法中配置的那样。
https://:2000
我们将在浏览器中看到以下响应。
因此,现在我们的 Web 服务器已托管在控制台应用程序中,可以监听请求并向浏览器发送响应。
创建请求管道
在 Owin 应用程序中,通常会创建一个组件链来构成请求处理管道。我们使用的 Run 方法可用于插入单个中间件组件。
如前所述,IAppBuilder 定义了静态扩展方法。此接口定义的一个静态方法是 Use,它有两个重载。
public static IAppBuilder Use<T>(this IAppBuilder app, params object[] args);
和
public static IAppBuilder Use(this IAppBuilder app, Func<Microsoft.Owin.IOwinContext, Func<System.Threading.Tasks.Task>, System.Threading.Tasks.Task>
因此,我们不会通过传递给 run() 方法的参数的 lambda 表达式来定义我们的中间件功能,而是创建一个单独的中间件类。这种方法更有用,因为它使我们能够创建中间件组件链。
下面我们定义了一个名为 Middleware 的类。
public class MiddlewareClass
{
private AppFunc _nextMiddleware;
public MiddlewareClass(AppFunc nextMiddleware)
{
_nextMiddleware = nextMiddleware;
}
public async Task Invoke(IDictionary<string, object> environment)
{
Console.WriteLine("Hello OWIN");
await _nextMiddleware(environment);
}
}
在为该类提供实现之前,有几点需要注意。
Middleware 类的构造函数需要一个具有 IDictionary<String,Object> 输入类型并返回 Task 的委托。此委托表示管道中的下一个中间件。
中间件中的方法名为 Invoke。这是在中间件中调用的方法,并且我们可以从该方法调用请求管道中的下一个组件。
我们可以使用以下方式配置应用程序以使用上述 Middleware。
public void Configuration(IAppBuilder app)
{
app.Use(typeof(MiddlewareClass));
}
运行应用程序,我们将得到以下响应。
虽然我们创建了一个中间件类,但使用这种方法我们可以轻松地创建中间件类的链。