Owin学习笔记(二) 中间件开发

Owin中也有类似于ASP.NET的管道,以前在做ASP.NET项目的时候,可以制作很多不同功能HttpHandler或者HttpModule并注册在Web.config中重复使用。在Owin的管道中,我们可以注册中间件(Middleware)来实现相似的功能。

所有的Owin中间件需要继承OwinMiddleware这个抽象类。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public abstract class OwinMiddleware
 
{
 
        //构造函数,定义了下一个需要运行的中间件
 
        protected OwinMiddleware(OwinMiddleware next);
 
  
 
        //下一个需要运行的中间件
 
        protected OwinMiddleware Next { get; set; }
 
  
 
        //中间件的执行方法
 
        public abstract Task Invoke(IOwinContext context);
 
}


 

当一个请求发送到Owin服务器之后,Owin服务器会自动获取Request中信息并转换成一个IOwinContext对象,然后依次运行定义在Owin管道中的中间件的Invoke方法。在每个中间件的Invoke方法中,开发人员都可以获取到请求的上下文,并且做出不同的Response。

 

这里需要注意管道中的中间件是有顺序的,他的顺序就是你在Owin启动类Startup中的注册顺序。每个中间件运行完毕之后,都可以指定是否继续运行后续的中间件。在Invoke方法中可以显示调用Next.Invoke(context)来表明需要继续运行后续的中间件。

 

下面我们做一个简单的PNG图片水印中间件。

 

创建项目

首先我们创建一个空的命令行工程PNGWatermark,并依次引入一下Nuget Library

Install-Package Microsoft.Owin.Host    //使用Owin Host托管
Install-Package Microsoft.Owin.StaticFiles    //静态文件中间件

Install-Package Microsoft.Owin.Host.HttpListener //使用HttpListener作为Owin服务器

 

创建水印中间件

添加一个新类PngWatermarkMiddleware,  其中的AddTextToImg方法是我从网上随便Copy的,这里的主要代码在Invoke方法中。因为Owin中不能使用ASP.NET的Server.MapPath方法,所以这里需要借助PhysicalFileSystem类,来吧url转换成对应的服务器文件路径。在这个方法最后我没有写Next.Invoke(context),  是因为我认为加上水印之后,后续的中间件已经不需要运行了。

 

   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
public class PngWatermarkMiddleware : OwinMiddleware
 
    {
 
        public PngWatermarkMiddleware(OwinMiddleware next) : base(next)
 
        {
 
  
 
        }
 
  
 
        public override async Task Invoke(IOwinContext context)
 
        {
 
            //获取网站根目录
 
            PhysicalFileSystem pfs = new PhysicalFileSystem(string.Empty);
 
            IFileInfo info = null;
 
  
 
            //转换url为绝对文件路径, 并检查文件是否存在
 
            var isFile = pfs.TryGetFileInfo(context.Request.Uri.LocalPath, out info);
 
  
 
            if (isFile && info.Name.EndsWith(".png"))
 
            {
 
  
 
                //如果是文件,就读取图片内容,加水印
 
                Image image = Image.FromFile(info.PhysicalPath);
 
  
 
                var imageByteAfterAddingWatermark = AddTextToImg(image, "Author: Lamond");
 
                context.Response.ContentType = "application/x-png";
 
                context.Response.StatusCode = (int)HttpStatusCode.OK;
 
                await context.Response.WriteAsync(imageByteAfterAddingWatermark);
 
            }
 
        }
 
  
 
        public static byte[] AddTextToImg(Image image, string text)
 
        {
 
            Bitmap bitmap = new Bitmap(image, image.Width, image.Height);
 
            Graphics g = Graphics.FromImage(bitmap);
 
  
 
            float fontSize = 12.0f; //字体大小
 
            float textWidth = text.Length * fontSize; //文本的长度
 
  
 
  
 
            //下面定义一个矩形区域,以后在这个矩形里画上白底黑字
 
            float rectX = 0;
 
            float rectY = 0;
 
            float rectWidth = text.Length * (fontSize + 8);
 
            float rectHeight = fontSize + 8;
 
            //声明矩形域
 
            RectangleF textArea = new RectangleF(rectX, rectY, rectWidth, rectHeight);
 
  
 
            //定义字体
 
            Font font = new Font("宋体", fontSize);
 
  
 
            //白笔刷,画文字用
 
            Brush whiteBrush = new SolidBrush(Color.White);
 
  
 
            //黑笔刷,画背景用
 
            Brush blackBrush = new SolidBrush(Color.Black);
 
  
 
            g.FillRectangle(blackBrush, rectX, rectY, rectWidth, rectHeight);
 
  
 
            g.DrawString(text, font, whiteBrush, textArea);
 
  
 
            MemoryStream ms = new MemoryStream();
 
            bitmap.Save(ms, ImageFormat.Png);
 
  
 
            return ms.ToArray();
 
        }
 
    }

 

 

注入水印中间件

Owin中间件需要在Owin启动类的Configuration中注册,所以这里我们需要加一个Owin Startup类,代码如下

   

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Startup
 
    {
 
        public void Configuration(IAppBuilder app)
 
        {
 
            app.Use<PngWatermarkMiddleware>();
 
        }
 
}

 

 

以OwinHost方式启动项目

在Program.cs中加入以下代码,启动Owin服务器

 

   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Program
 
    {
 
        static void Main(string[] args)
 
        {
 
            var url = "http://localhost:1234";
 
  
 
            using (WebApp.Start<Startup>(url))
 
            {
 
                Console.WriteLine("Server Started");        
 
     }
 
  
 
     Console.Read();
 
        }
 
}

 

 

最终运行效果

下面我们将一个logo.png放置到当前项目的bin/debug目录中

 

然后启动项目,运行效果如下

打开浏览器,输入http://localhost:1234/logo.png

浏览器会自动下载一个logo.png, 打开之后,其内容如下,水印已经成功加上了

posted @   LamondLu  阅读(567)  评论(1编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示
主题色彩