【C#】对异步请求处理程序IHttpAsyncHandler的理解和分享一个易用性封装 【手记】走近科学之为什么明明实现了IEnumerable<T>的类型却不能调用LINQ扩展方法 【手记】手机网页弹出层后屏蔽底层的滑动响应 【手记】ASP.NET提示“未能创建类型”处理 【Web】一个非常简单的移动web消息框 【手记】解决EXCEL跑SQL遇“查询无法运行或数据库表无法打开...”
【C#】对异步请求处理程序IHttpAsyncHandler的理解和分享一个易用性封装
在asp.net项目中,添加一个【一般处理程序】来处理请求是很自然的事,这样会得到一个实现自IHttpHandler的类,然后只需在ProcessRequest方法中写上处理逻辑就行了。但是这样的一个请求处理程序(下称ashx)是同步的,就是接待该次请求的线程会一直等待处理完才能解脱,后果就是,如果这个ashx比较耗时,并且同时对它的请求又多的话,服务器需要开启若干个线程来跑这个ashx,并且这些线程都要各自跑很久才能被收回或挪作它用,如果这样的ashx还有不少的话,那么对整个服务器资源的开销是很大的,所以有必要采用IHttpAsyncHandler来实现这种ashx,即异步请求处理程序,异步化以后,线程把请求接进来就完事了,反手就可以去处理其它请求,然后由别的线程或硬件来处理具体的任务~取决于任务是CPU消耗型(密集运算,如图片处理)还是I/O型(数据库读写、网络访问等),老实说如果耗时任务总是CPU消耗型,那同步异步在资源消耗上没什么区别,因为总得有个线程来跑任务,换不换线程意义不大。但总的来说异步化没坏处,而且万一对任务类型评估错误呢。
改用IHttpAsyncHandler后,多了两个方法BeginProcessRequest和EndProcessRequest,原有的ProcessRequest事实上已经废弃,请求不会进入里面,而是改为在BeginProcessRequest中处理请求,原IsReusable属性功能不变。说回BeginProcessRequest,这是一个典型的传统异步方法(相对于.net 4.5后的async/await新式异步方法来说),逻辑相比原来的同步方法ProcessRequest有点绕,首先入参除了熟悉的HttpContext外还有两个,然后还有个IAsyncResult类型的返回值。熟悉APM(异步编程模型)套路的朋友知道该怎么搞,不熟悉的可参看MSDN,要点就是实例化一个实现IAsyncResult的类,在其中异步或起线程执行逻辑,然后返回这个对象。现成的实现IAsyncResult的类在.net 4.0后有Task,但如果项目不到4.0,你还找不到一个可以拿来就用的类,如果要为每个ashx实现一个IAsyncResult,想想都蛋疼,哪怕总共只需实现一个IAsyncResult我都不情愿,好在委托这个东西编译器会为它自动生成异步模型,于是有了下面这个简单的封装:
/// <summary> /// 异步请求处理基类 /// <para>- 子类实现ProcessRequest方法并在其中处理请求</para> /// <para>- 默认允许实例重用(IsReusable=true),子类可重写为false</para> /// </summary> public abstract class HttpAsyncHandler : IHttpAsyncHandler { readonly Action<HttpContext> _processRequestDel; protected HttpAsyncHandler() => _processRequestDel = ProcessRequest; /// <summary> /// 处理请求 /// </summary> //总是要有个让子类处理业务逻辑的地方,既然原来的ProcessRequest已废弃,不如废物利用 public abstract void ProcessRequest(HttpContext context); /// <summary> /// 多次请求是否可以重用实例。默认true /// </summary> public virtual bool IsReusable => true; public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) => _processRequestDel.BeginInvoke(context, cb, extraData); //利用ProcessRequest委托的异步能力 //虽然不End也不会导致异步还没跑完就返回响应(HttpApplication的实现似乎保证这一点),但异步中抛出的异常会被忽略,所以需要End暴露问题 public void EndProcessRequest(IAsyncResult result) => _processRequestDel.EndInvoke(result); }
有了这个封装好的基类,在写新的ashx时就可以把IHttpHandler改为HttpAsyncHandler,完了把ProcessRequest方法标成override就行,老ashx也可以经过简单修改异步化。举例:
public class FooHandler : HttpAsyncHandler // 替掉IHttpHandler { //加上override public override void ProcessRequest(HttpContext context) { //在这里写逻辑 context.Response.Write("OK"); } }
需要注意的是IsReusable在HttpAsyncHandler中已改为true,所以如果你的ashx明确需要false,请override该属性,如:
public override bool IsReusable => false;
对于.net 4.5及以上版本,微软已经写好了个HttpTaskAsyncHandler,性质一样,只不过形式上符合新式的async/await用法,总之目的都是让开发者可以优雅的使用异步ashx,不必繁琐的从IHttpAsyncHandler开始。
EOF
【手记】走近科学之为什么明明实现了IEnumerable<T>的类型却不能调用LINQ扩展方法
比如Json.NET的JObject明明实现了IEnumerable<T>,具体来说是IEnumerable<KeyValuePair<string, JToken>>,按说JObject类型的对象是可以直接调用Select、Where等linq扩展方法的,但偏偏就是不行,代码如下:
using System.Linq; ... var jobj = new JObject(); var xxx = jobj.Select(x=>x); //报错:JObject未包含Select定义,也不存在第1个参数为JObject的Select扩展方法... foreach(var x in jobj) { } //可以 var xxx = ((IEnumerable<KeyValuePair<string, JTokin>>)jobj).Select(x=>x); //也可以
究竟是人性的扭曲还是道德的沦丧?答案就在:
因为JObject除了本身实现了一个IEnumerable<KeyValuePair<string, JToken>>,它实现的另一个接口JContainer也实现了一个IEnumerable<JToken>,等于JObject直接和间接实现了两个不同的IEnumerable<T>,当.Select的时候编译器不能确定调用哪个类型的Select,所以就这样了。——爆栈
这个需求场景很常见,但好像到目前还没有一个正统的做法,以至于一搜这个问题,出来的招数五花八门,典型的包括:
- 给body上overflow:hidden,fixed什么的。问题在于:手机端可能没用,或者会让页面回到顶部~影响体验
- 简单粗暴的屏蔽touchmove。问题在于:弹出层内部需要滚动就不行
- 张鑫旭大神的招数。问题在于:我感觉复杂,就没试
终于还是让我在爆栈找到一个挺满意的招:https://stackoverflow.com/a/31063201/5482608,在此分享一下。
我是在本机启动IIS Express调试一个ashx(一般处理程序)时遇到这个报错,网上的说法普遍有这么几种:
- 把bbb.ashx中的Class="aaa.bbb" 改为Class="bbb",即把命名空间删掉
- 把bbb.ashx.cs中的代码复制到bbb.ashx中来,保持<% WebHandler ....%>这句在顶端,并且将其中的CodeBehind="xx"属性删除,最后删除bbb.ashx.cs文件
上述方法对我没用,问题依旧,有用的是这招:
- 把项目的输出目录由bin\xxx改为bin\
适用:h5+jquery,移动网页最佳
最近在写个简单的公众号页面,前端验证时有些信息要提示,很简单的需求实在不想找啥现成的轮子,又不至于用alert这么粗暴,遂写了个非常简单的消息框,效果如图:
特点:
- 有黑层遮罩
- 点击消失,无论是点消息框还是外面
用法:
//定义函数。我个人还是习惯PascalCase命名 function MsgBox(msg,title) { $('<div onclick="$(this).remove();"style="z-index:9999;padding:10px;display:flex;justify-content:center;align-items:center;position:fixed;top:0;left:0;width:100%;height:100%;<div><div style="color:#555;background-color:#DDD;font-size:0.8em;padding:3px;border-top-left-radius:5px;border-top-right-radius:5px;">' + (title === undefined ? '提示' : title) + '</div><div style="min-height:80px;min-width:250px;display:flex;justify-content:center;align-items:center;padding:20px;border-top:1px solid #BBB;border-bottom-left-radius:5px;border-bottom-right-radius:5px;text-align:justify">' + msg + '</div></div></div>') .appendTo($(document.body)); } //使用 MsgBox('内容'); //标题显示为“提示” MsgBox('内容','我的标题'); //自定义标题
欢迎吐槽或推荐更好的方案。
-end-
【手记】解决EXCEL跑SQL遇“查询无法运行或数据库表无法打开...”
报错:
解决:在语句开头指定SET NOCOUNT ON
就是这么神cao奇dan。
- 【手记】走近科学之为什么JObject不能调用LINQ扩展方法
- C#技巧【调用线程无法访问此对象,因为另一个线程拥有该对象的问题的解决办法】【C#读写EXCEL源码提示“office检测到此文件存在一个问题。为帮助保护您的计算机,不能打开此文件”的解决】
- 【手记】解决EXCEL跑SQL遇“查询无法运行或数据库表无法打开...”
- Sql2012如何将远程服务器数据库及表、表结构、表数据导入本地数据库 自定义日志记录功能,按日记录,很方便 C#常量和字段以及各种方法的语法总结 类型,对象,线程栈,托管堆在运行时的关系,以及clr如何调用静态方法,实例方法,和虚方法 asp.net webapi 自定义身份验证
- 【手记】ASP.NET提示“未能创建类型”处理
- sql server 关于表中只增标识问题 C# 实现自动化打开和关闭可执行文件(或 关闭停止与系统交互的可执行文件) ajaxfileupload插件上传图片功能,用MVC和aspx做后台各写了一个案例 将小写阿拉伯数字转换成大写的汉字, C# WinForm 中英文实现, 国际化实现的简单方法 ASP.NET Core 2 学习笔记(六)ASP.NET Core 2 学习笔记(三)
- C#编译器优化那点事 c# 如果一个对象的值为null,那么它调用扩展方法时为甚么不报错 webAPI 控制器(Controller)太多怎么办? .NET MVC项目设置包含Areas中的页面为默认启动页 (五)Net Core使用静态文件 学习ASP.NET Core Razor 编程系列八——并发处理
- asp.net<Web版> ---将excel表数据导入到数据库问题<一>---未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0” 提供程序
- 在ASP.NET中使用IHttpHandler处理请求(如自实现AJAX)时,无法获得Session(或者说是Session 为 null)的原因及解决方法
- asp.net网站,打开网站,提示下载网页解决方法(未知文件类型、text/vnd.wap.wml)
- C#和Asp.net下调用Excel后无法自动关闭进程的解决方法
- 【手记】手机网页弹出层后屏蔽底层的滑动响应
- 解决asp.net Sharepoint无法连接发布自定义字符串处理程序,不能进行输出缓存处理的方法
- EF Core使用SQL调用返回其他类型的查询 ASP.NET Core 2.0 使用NLog实现日志记录 CSS 3D transforms cSharp:use Activator.CreateInstance with an Interface? SqlHelper DBHelper C# Thread.Abort方法真的让线程停止了吗? 注意!你的Thread.Abort方法真
- 检测到指定的WEB服务器运行的不是ASP.NET 1.1版,您无法运行ASP.NET应用程序或服务和创建ASP.NET程序时候发生错误 HTTP/1.0 500 Server Error的解决方法
- Visual Studio 2008不能创建数据库连接出现:未能加载文件或程序集“Microsoft.SqlServer.Management.Sdk.Sfc, Version=10.0.0.0, Culture=neutral,PublicKeyToken=89845dcd8080cc91”或它的一个依赖项。系统找不到指定的文件的解决办法
- vs2003提示:试图运行项目时出错:无法在WEB服务器上启动调试.未能启动ASP.NET或ATL SERVER 调试. 验证服务器上是否正确安装了ASP.NET或ATL SERVER的解决方案
- 解决 web服务器部署常见问题,server application unavailable 和 程序无法连接数据库 的问题(asp.net 2.0 + oracle9i + winXP)
- ASP.NET配置(web.config)无法连接到SQL Server 数据库的解决方法