我正在构建一个扩展ApiController
的课程,而这个课程将由我的客户进行扩展。
在我的控制器类中,我需要更改操作的返回值的序列化方式。
例如:默认情况下,执行以下操作:
public Person Get() { return new Person(); }
将生成HTTP响应,例如:
HTTP/1.1 200 OK
{"name":null}
如果我想拦截这个Person
对象,我可以从MediaTypeFormatter
扩展,并将它附加到控制器的Configuration.Formatters
集合,并按照我想要的方式序列化对象。< / p>
public abstract class MyController : ApiController
{
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
Configuration.Formatters.OfType<JsonMediaTypeFormatter>().ToList()
.ForEach(f => Configuration.Formatters.Remove(f));
Configuration.Formatters.Insert(0, new MyPersonFormatter());
}
现在,该操作将格式化为:
HTTP/1.1 200 OK
{"my custom wrapper":{"name":null}}
但是,如果我想拦截无效行动怎么办?
默认情况下,void操作将转换为具有空体的204 No Content响应。我如何将数据插入到响应的正文中?
注意:如果可以在控制器内完成,我希望我的抽象控制器能够自行完成所有管道工作,而不是在客户端强制执行任何操作。
答案 0 :(得分:2)
在内部,在默认的HttpActionDescriptor
中,框架将ResultConverter
个void
方法设置为自己的VoidResultConverter
,它返回带有空内容的HTTP 204。另外,通过明确地将其称为VoidResultConverter
,您甚至不能强迫它使用Reflection替换其实现。
HttpActionDescriptor.cs中的第34行:
private static readonly VoidResultConverter _voidResultConverter = new VoidResultConverter();
但是,您可以使用自定义ActionDescriptor
替换void
个ActionFilter
方法(全局,基本控制器中,或使用属性在某些操作上明确定义) :
public class VoidActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var retType = actionContext.ActionDescriptor.ReturnType;
if (retType == typeof(void) || retType == null)
{
actionContext.ActionDescriptor = new VoidActionDescriptor(actionContext.ActionDescriptor);
}
base.OnActionExecuting(actionContext);
}
}
这里是VoidActionDescriptor
,它实际上是常规ReflectedHttpActionDescriptor
的包装:
public class VoidActionDescriptor : HttpActionDescriptor
{
private readonly HttpActionDescriptor _currentDescriptor;
public VoidActionDescriptor(HttpActionDescriptor currentDescriptor)
{
if (currentDescriptor == null)
throw new ArgumentNullException("currentDescriptor");
this._currentDescriptor = currentDescriptor;
}
// this is what we're here for
public override IActionResultConverter ResultConverter
{
get { return new MyVoidResultConverter(); }
}
// wrapper methods from now on
public override Collection<HttpParameterDescriptor> GetParameters()
{
return this._currentDescriptor.GetParameters();
}
public override Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken)
{
return this._currentDescriptor.ExecuteAsync(controllerContext, arguments, cancellationToken);
}
public override string ActionName
{
get { return this._currentDescriptor.ActionName; }
}
public override Type ReturnType
{
get { return this._currentDescriptor.ReturnType; }
}
}
它唯一有趣的事情是将自定义MyVoidResultConverter
返回到其ResultConverter
属性中。
现在最后一块是实际的IActionResultConverter
:
public class MyVoidResultConverter : IActionResultConverter
{
public HttpResponseMessage Convert(HttpControllerContext controllerContext, object actionResult)
{
var res = controllerContext.Request.CreateResponse(HttpStatusCode.OK);
res.Content = new StringContent("void response");
return res;
}
}