首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何让ASP.NET Web API的Action方法在希望的Culture下执行

如何让ASP.NET Web API的Action方法在希望的Culture下执行

作者头像
蒋金楠
发布于 2018-01-15 11:13:44
发布于 2018-01-15 11:13:44
1.5K00
代码可运行
举报
文章被收录于专栏:大内老A大内老A
运行总次数:0
代码可运行

在今天编辑推荐的《Hello Web API系列教程——Web API与国际化》一文中,作者通过自定义的HttpMessageHandler的方式根据请求的Accep-Language报头设置当前线程UI Culture的方式来解决Localization的问题。如果你对ASP.NET Web API的执行机制有足够了解的话,你会发现实际上有很多种解决方案。不过这些解决方案都不够完美,原因很简单:ASP.NET Web API的整个框架均采用基于Task的并行编程模式,所以每个可扩展组件均可以在不同的线程中执行,这样会导致我们没有办法100%控制目标方法真正执行的线程的UI Culture。不过在默认情况下,大部分组件是按照同步的方式执行的,所以我们之需要在目标Action方法执行之前设置当前线程的UI Culture即可。

目录 一、两个辅助的扩展方法 二、第1种方案:自定义ActionFilter 三、第2种方案:自定义HttpActionDescriptor 四、第3种方案:自定义HttpActionInvoker 五、第4种方案:为HttpController创建一个基类

一、两个辅助的扩展方法

我们针对HttpRequestMessage定义了如下两个扩展方法。SetCurrentUICulture从请求的Accpet-Language报头提取客户端接受的语言并据此设置当前线程的UI Culture。在这之前,它会将当前线程的UI Culture保存到HttpRequestMessage对象中。ResetCurrentUICulture方法将这个CultureInfo对象从HttpRequestMessage其中提取出来,将当前线程的UI Cuilture回复到之前的状态。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   1: public static class HttpRequestMessageExtensions
   2: {
   3:     public static void SetCurrentUICulture(this HttpRequestMessage request)
   4:     {
   5:         StringWithQualityHeaderValue acceptCultureHeader =  request.Headers.AcceptLanguage.OrderByDescending(header => header.Quality).FirstOrDefault();
   6:         if (null != acceptCultureHeader)
   7:         {
   8:             request.Properties["__CurrentCulture"] = Thread.CurrentThread.CurrentUICulture;
   9:             Thread.CurrentThread.CurrentUICulture = new CultureInfo(acceptCultureHeader.Value);
  10:         }
  11:     }
  12:  
  13:     public static void ResetCurrentUICulture(this HttpRequestMessage request)
  14:     {
  15:         object culture;
  16:         if (request.Properties.TryGetValue("__CurrentCulture", out culture))
  17:         {
  18:             Thread.CurrentThread.CurrentUICulture = (CultureInfo)culture;
  19:         }
  20:     }
  21: } 

二、第1种方案:自定义ActionFilter

我想这应该是大家最容易想到的解决方案,因为ActionFilter可以注册一些回调操作在目标Action方法执行前后被自动调用。为此我们定义了如下一个继承自ActionFilterAttribute的UseAcceptCultureAttribute类型。我们分别在重写的OnActionExecuting和OnActionExecuted方法中利用上面定义的两个扩展方法对当前线程的UI Culture进行设置和恢复。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   1: public class UseAcceptCultureAttribute: ActionFilterAttribute
   2: {
   3:     public override void OnActionExecuting(HttpActionContext actionContext)
   4:     {
   5:         actionContext.Request.SetCurrentUICulture();
   6:     }
   7:  
   8:     public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
   9:     {
  10:         actionExecutedContext.Request.ResetCurrentUICulture();
  11:     }
  12: }

为了验证这个ActionFilterAttribute特性,我们定义了如下一个继承自ApiController的HelloController。唯一的Action方法返回的字符串是从资源文件中提取的(类型Resources为资源文件自动生成的类型),而ActionFilterAttribute就应用在这个Get方法上。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   1: public class HelloController : ApiController
   2: {
   3:     
          [UseAcceptCulture]
   4:     public string Get()
   5:     {
   6:         return Resources.HelloWorld;
   7:     }
   8: }

我们定义了两个资源文件,一个为语言文化中性的Resources.resx,另一个则是针对中文的Resources.zh.resx。唯一的资源项HelloWorld分别在所在的文件中以英文和中文进行定义,而上面定义的Get方法返回的正式它们的值。

在启动之后,我们利用Fiddler来调用定义在HelloController中的Action方法Get,并手工设置Accept-Language报头的值。如下图所示,当请求的Accept-Language报头被分别设置为“en-US;q=1.0, zh-CN;q=0.8”和“en-US;q=0.8, zh-CN;q=1.0”时(即给en-US和zh-CN分配不同的Quality),返回的内容分别是英文和中文。

三、第2种方案:自定义HttpActionDescriptor

HttpActionDescriptor用于描述定义在HttpController中的Action,默认的HttpActionDescriptor类型为ReflectedHttpActionDescriptor。Action方法的执行最终实现在HttpActionDescriptor的ExecuteAsync方法中,我们可以通过自定义的HttpActionDescriptor的方式在目标Action方法执行前后对当前线程的UI Culture进行设置和恢复。为此,我们定义了如下一个ExtendedReflectedHttpActionDescriptor类型。在重写的ExecuteAsync方法中,我们调用基类的同名方法执行目标Action方法,并在这前后分别调用当前HttpRequestMessage的两个扩展方法设置和恢复当前线程的UI Culture。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   1: public class ExtendedReflectedHttpActionDescriptor : ReflectedHttpActionDescriptor
   2: {
   3:     public ExtendedReflectedHttpActionDescriptor(ReflectedHttpActionDescriptor actionDescriptor)
   4:         : base(actionDescriptor.ControllerDescriptor, actionDescriptor.MethodInfo)
   5:     { }
   6:     public override Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken)
   7:     {
   8:         controllerContext.Request.SetCurrentUICulture();
   9:         Task<object>  task = base.ExecuteAsync(controllerContext, arguments, cancellationToken);
  10:         controllerContext.Request.ResetCurrentUICulture();
  11:         return task;
  12:     }
  13: }

ASP.NET Web API利用一个名为HttpActionSelector的对象来选择与当前请求匹配的HttpActionDescriptor,要让我们自定义的ExtendedReflectedHttpActionDescriptor被使用,我们得对应的HttpActionSelector。ASP.NET Web API默认使用的HttpActionSelector类型为ApiControllerActionSelector,我们自定义的ExtentedApiControllerActionSelector就继承于它。如下面的代码片断所示,在重写的SelectAction方法中,我们调用基类的同名方法得到一个ReflectedHttpActionDescriptor 对象,并根据它创建一个ExtendedReflectedHttpActionDescriptor 对象并返回。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   1: public class ExtentedApiControllerActionSelector: ApiControllerActionSelector
   2: {
   3:     public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
   4:     {
   5:         ReflectedHttpActionDescriptor actionDescriptor = (ReflectedHttpActionDescriptor) base.SelectAction(controllerContext);
   6:         return new ExtendedReflectedHttpActionDescriptor(actionDescriptor);
   7:     }
   8: }

自定义的ExtentedApiControllerActionSelector可以在Global.asax中按照如下的方式进行注册。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   1: public class WebApiApplication : System.Web.HttpApplication
   2: {
   3:     protected void Application_Start()
   4:     {
   5:         GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionSelector), new ExtentedApiControllerActionSelector());
   6:         //...
   7:     }
   8: }

四、第3种方案:自定义HttpActionInvoker

目标Action的执行是通过一个名为HttpActionInvoker驱动执行的(它调用HttpActionDescriptor的ExecuteAsync方法),默认的HttpActionInvoker类型为ApiControllerActionInvoker。我们可以继承它,并在执行目标Action方法前后设置和恢复当前线程的UI Culture。为此我定义了如下一个ExtendedApiControllerActionInvoker,在重写的InvokeActionAsync方法中,我们调用基类的同名方法执行目标Action方法,并在这前后分别调用当前HttpRequestMessage的两个扩展方法设置和恢复当前线程的UI Culture。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   1: public class ExtendedApiControllerActionInvoker: ApiControllerActionInvoker
   2: {
   3:     public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
   4:     {
   5:         actionContext.Request.SetCurrentUICulture();
   6:         Task < HttpResponseMessage > task = base.InvokeActionAsync(actionContext, cancellationToken);
   7:         actionContext.Request.ResetCurrentUICulture();
   8:         return task;
   9:     }
  10: }

自定义的ExtendedApiControllerActionInvoker可以在Global.asax中按照如下的方式进行注册。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   1: public class WebApiApplication : System.Web.HttpApplication
   2: {
   3:     protected void Application_Start()
   4:     {
   5:         GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionInvoker), new ExtendedApiControllerActionInvoker());
   6:          //...
   7:     }
   8: }

五、第4种方案:为HttpController创建一个基类

HttpActionInvoker的最终又是在执行HttpController时被调用的,所以我们可以在执行HttpController上作文章。所以我们定义了如下一个继承自ApiController的ExtendedApiController 类型。在重写的ExecuteAsync方法中,我们调用基类同名方法前后对当前线程的UI Culture进行了设置和恢复。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   1: public abstract class ExtendedApiController : ApiController
   2: {
   3:     public override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
   4:     {
   5:         controllerContext.Request.SetCurrentUICulture();
   6:         Task < HttpResponseMessage > task = base.ExecuteAsync(controllerContext, cancellationToken);
   7:         controllerContext.Request.ResetCurrentUICulture();
   8:         return task;
   9:     }
  10: }

那么我们的HelloController只需要继承自ExtendedApiController 即可。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2013-11-07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
ASP.NET Web API中的Controller
虽然通过Visual Studio向导在ASP.NET Web API项目中创建的 Controller类型默认派生与抽象类型ApiController,但是ASP.NET Web API框架本身只要求它实现IHttpController接口即可,所以我们将其统称为HttpController。既然HttpController指的是所有实现了IHttpController接口的类型,我们自然得先来了解一下这个接口的定义。如下面的代码片断所示,在IHttpController接口中仅仅定义了唯一的方法Exec
蒋金楠
2018/01/15
1.8K0
ASP.NET Web API中的Controller
Asp.Net WebApi核心对象解析(一)
本文主要介绍了ASP.NET Web API的背景、使用方法和核心对象,包括HttpRequestMessage、HttpResponseMessage、HttpClient等,并分析了如何使用这些对象来处理HTTP请求和响应。
彭泽0902
2018/01/04
5.1K0
ASP.NET Web API编程——模型验证与绑定
1.模型验证 使用特性约束模型属性 可以使用System.ComponentModel.DataAnnotations提供的特性来限制模型。 例如,Required特性表示字段值不能为空,Range特性限制数值类型的范围。 对实体类使用特性后,可以使用ModelState.IsValid来判断验证是否通过。 例: 实体: public class DataModel { public int Id { get; set; } public string Field1Nam
甜橙很酸
2018/04/18
3.3K0
ASP.NET Web API编程——模型验证与绑定
通过扩展让ASP.NET Web API支持W3C的CORS规范
让ASP.NET Web API支持JSONP和W3C的CORS规范是解决“跨域资源共享”的两种途径,在《通过扩展让ASP.NET Web API支持JSONP》中我们实现了前者,并且在《W3C的CORS Specification》一文中我们对W3C的CORS规范进行了详细介绍,现在我们通过一个具体的实例来演示如何利用ASP.NET Web API具有的扩展点来实现针对CORS的支持。 目录 一、ActionFilter OR HttpMessageHandler 二、用于定义
蒋金楠
2018/01/15
2.6K0
通过扩展让ASP.NET Web API支持W3C的CORS规范
ASP.NET Web API自身对CORS的支持: EnableCorsAttribute特性背后的故事
从编程的角度来讲,ASP.NET Web API针对CORS的实现仅仅涉及到HttpConfiguration的扩展方法EnableCors和EnableCorsAttribute特性。但是整个CORS体系不限于此,在它们背后隐藏着一系列的类型,我们将会利用本章余下的内容对此作全面讲述,今天我们就来讨论一下用于定义CORS授权策略的EnableCorsAttribute特性背后的故事。 目录 一、CorsPolicy 二、CorsPolicyProvider 三、CorsPoli
蒋金楠
2018/01/15
1.6K0
ASP.NET Web API自身对CORS的支持: EnableCorsAttribute特性背后的故事
ASP.NET Web API标准的“管道式”设计
ASP.NET Web API的核心框架是一个消息处理管道,这个管道是一组HttpMessageHandler的有序组合。这是一个双工管道,请求消息从一端流入并依次经过所有HttpMessageHandler的处理。在另一端,目标HttpController被激活,Action方法被执行,响应消息随之被生成。响应消息逆向流入此管道,同样会经过逐个HttpMessageHandler的处理。这是一个独立于寄宿环境的抽象管道,如何实现对请求的监听与接收,以及将接收的请求传入消息处理管道进行处理并将管道生成的响应
蒋金楠
2018/01/15
1.4K0
ASP.NET Web API标准的“管道式”设计
总体介绍ASP.NET Web API下Controller的激活与释放流程
通过《ASP.NET Web API的Controller是如何被创建的?》我们已经对HttpController激活系统的核心对象有了深刻的了解,这些对象包括用于解析程序集和有效HttpController类型的AssembliesResolver和HttpControllerTypeResolver、根据请求完整目标HttpController选择的HttpControllerSelector、负责激活目标HttpController实例的HttpControllerActivator、以及作为IoC容
潘成涛
2019/05/25
7190
总体介绍ASP.NET Web API下Controller的激活与释放流程
通过《ASP.NET Web API的Controller是如何被创建的?》我们已经对HttpController激活系统的核心对象有了深刻的了解,这些对象包括用于解析程序集和有效HttpController类型的AssembliesResolver和HttpControllerTypeResolver、根据请求完整目标HttpController选择的HttpControllerSelector、负责激活目标HttpController实例的HttpControllerActivator、以及作为IoC容
蒋金楠
2018/01/15
9680
总体介绍ASP.NET Web API下Controller的激活与释放流程
ASP.NET Web API 接口执行时间监控
软件产品常常会出现这样的情况:产品性能因某些无法预料的瓶颈而受到干扰,导致程序的处理效率降低,性能得不到充分的发挥。如何快速有效地找到软件产品的性能瓶颈,则是我们感兴趣的内容之一。 在本文中,我将解释我如何清理和替换重复、 混乱遍布许多方法在应用程序中的代码使用ASP.NET Web API 的筛选器来完成ASP.NET Web API 接口执行时间监控。我们的项目中有如下的需求:我的工作相关的项目 (使用 ASP.NET Web API 框架) 要求记录下服务接口的调用执行时间以及请求延迟、 故障率每秒的
张善友
2018/01/22
2.2K0
跨域资源共享(CORS)在ASP.NET Web API中是如何实现的?
在《通过扩展让ASP.NET Web API支持W3C的CORS规范》中,我们通过自定义的HttpMessageHandler自行为ASP.NET Web API实现了针对CORS的支持,实际上ASP.NET Web API自身也是这么做的,该自定义HttpMessageHandler就是System.Web.Http.Cors.CorsMessageHandler。 1: public class CorsMessageHandler : DelegatingHandler 2: {
蒋金楠
2018/01/15
2.9K0
跨域资源共享(CORS)在ASP.NET Web API中是如何实现的?
我这么玩Web Api(二)
数据验证,全局数据验证与单元测试 目录 一、模型状态 - ModelState 二、数据注解 - Data Annotations 三、自定义数据注解 四、全局数据验证 五、单元测试 一、模型状态 - ModelState   我理解的ModelState是微软在ASP.NET MVC中提出的一种新机制,它主要实现以下几个功能:   1. 保存客户端传过来的数据,如果验证不通过,把数据返回到客户端,这样可以保存用户输入,不需要重新输入。   2. 验证数据,以及保存数据对应的错误信息。   3. 微软的一种
逸鹏
2018/04/10
1.5K0
我这么玩Web Api(二)
使用ActionFilterAttribute 记录 WebApi Action 请求和返回结果记录
在asp.net mvc 中 webapi 和 mvc 处理消息是两个不同的管道,Asp.net mvc 和 webapi 为我们提供的 ActionFilterAttribute 拦截器,通过 重写 OnActionExecutingAsync,来 拦截action的请求消息,当执行OnActionExecutingAsync完成以后才真正进入请求的action中,action运行完后又把控制权给了 OnActionExecutedAsync ,这个管道机制可以使我们用它来轻松实现 权限认证、日志记录 ,跨域以及很多需要对全局或者部分请求做手脚的的功能。
yaphetsfang
2020/07/30
5.3K0
使用ActionFilterAttribute 记录 WebApi Action 请求和返回结果记录
ASP.NET WebAPI 中的参数绑定
当 WebAPI 调用 Controller 上的方法时, 必须为其参数赋值, 这个过程就是参数绑定。 本文介绍 WebAPI 如何绑定参数, 以及如何进行自定义。
beginor
2020/08/10
3K0
asp.net web api添加自定义认证
1、定义认证失败结果生成器   /// <summary> /// 认证失败结果生成器 /// </summary> public class AuthenticationFailureResult : IHttpActionResult { public AuthenticationFailureResult(string reasonPhrase, HttpRequestMessage request) { Rea
guokun
2020/09/03
1.1K0
asp.net web api添加自定义认证
ASP.NET Web API编程——控制器
1控制器操作的参数 控制器操作的参数可以是内置类型也可以是自定义类型,无参也是允许的。 2控制器操作返回值 类型 说明 void 操作返回值为void时,Web API返回空HTTP响应,其状态码为204(无内容) HttpResponseMessage Web api会将此返回值直接转换为HTTP消息 IHttpActionResult 接口形式 内置类型或自定义类型 无 2.1返回值为HttpResponseMess
甜橙很酸
2018/04/17
2.7K0
asp.net web api 异常捕获
1 向客户端发送错误消息 使用throw new HttpResponseException()向客户端抛出错误信息。 HttpResponseException包含两个重载的构造函数,其中一个是构造函数参数类型为HttpResponseMessage,通过其设置状态码,错误消息短语以及消息体内容来向客户端抛出比较详细的错误信息。另一个参数类型为HttpStatusCode,只能设定状态码。 2自定义异常过滤器 扩展IExceptionFilter来定义异常过滤器。异常过滤器不会捕获类型为HttpRespo
甜橙很酸
2018/03/08
1.8K0
Asp.Net Web API 2第十六课——Parameter Binding in ASP.NET Web API(参数绑定)
阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html。
aehyok
2018/08/31
1.5K0
Asp.Net Web API 2第十六课——Parameter Binding in ASP.NET Web API(参数绑定)
聊一聊Asp.net过滤器Filter那一些事
最近在整理优化.net代码时,发现几个很不友好的处理现象:登录判断、权限认证、日志记录、异常处理等通用操作,在项目中的action中到处都是。在代码优化上,这一点是很重要着力点。这时.net中的过滤器、拦截器(Filter)就派上用场了。现在根据这几天的实际工作,对其做了一个简单的梳理,分享出来,以供大家参考交流,如有写的不妥之处,多多指出,多多交流。
小小许
2020/06/10
1.4K0
谈谈基于OAuth 2.0的第三方认证 [中篇]
虽然我们在《上篇》分别讨论了4种预定义的Authorization Grant类型以及它们各自的适用场景的获取Access Token的方式,我想很多之前没有接触过OAuth 2.0的读者朋友们依然会有“不值所云” 之感,所以在介绍的内容中,我们将采用实例演示的方式对Implicit和Authorization Code这两种常用的Authorization Grant作深入介绍。本章着重介绍Implicit Authorization Grant。 Implicit Authorization Grant
蒋金楠
2018/01/15
1.3K0
谈谈基于OAuth 2.0的第三方认证 [中篇]
ASP.NET Web API的Controller是如何被创建的?
Web API调用请求的目标是定义在某个HttpController类型中的某个Action方法,所以消息处理管道最终需要激活目标HttpController对象。调用请求的URI会携带目标HttpController的名称,该名称经过路由解析之后会作为路由变量保存到一个HttpRouteData对象中,而后者会被添加到代表当前请求的HttpRequestMessage对象的属性字典中。ASP.NET Web API据此解析出目标HttpController的类型,进而实现针对目标HttpControlle
蒋金楠
2018/01/15
1.7K0
相关推荐
ASP.NET Web API中的Controller
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档