ASP.NET WebAPI 12 Actionの実行
4007 ワード
Actionのアクティブ化は、Actionがメソッドの呼び出しに対応し、結果の交渉を実行する2つのステップに大きく分けることができます.WebAPIでは、HttpActionInvoker(System.Web.Http.Controllers)によってActionの実行が行われる.
HttpActionInvokerも「標準化コンポーネント」であり、WebAPIのデフォルト実装は、ApiControllerActionInvoker(System.Web.Http.Controllers,ApiControllerActionInvokerの実装におけるActionメソッドの呼び出しは、実際にはHttpActionDescriptorのExecuteAsyncのメソッドによって実行され、コンテンツ交渉はContentNegotiatorによって処理される.
アクションの実行
public interface IHttpActionInvoker
{
Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, CancellationToken cancellationToken);
}
HttpActionInvokerも「標準化コンポーネント」であり、WebAPIのデフォルト実装は、ApiControllerActionInvoker(System.Web.Http.Controllers,ApiControllerActionInvokerの実装におけるActionメソッドの呼び出しは、実際にはHttpActionDescriptorのExecuteAsyncのメソッドによって実行され、コンテンツ交渉はContentNegotiatorによって処理される.
アクションの実行
ActionExecutor
ReflectedHttpActionDescriptor ExecuteAsyncメソッド実装でActionの実行をその内部クラスActionExecutorに渡す
public class ReflectedHttpActionDescriptor : HttpActionDescriptor
{
public abstract Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken);
}
ReflectedHttpActionDescriptorでは、アクションの実行を内部クラスActionExecutorに渡します.
public override Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken)
{
if (controllerContext == null)
{
throw Error.ArgumentNull("controllerContext");
}
if (arguments == null)
{
throw Error.ArgumentNull("arguments");
}
if (cancellationToken.IsCancellationRequested)
{
return TaskHelpers.Canceled<object>();
}
try
{
object[] argumentValues = PrepareParameters(arguments, controllerContext);
return _actionExecutor.Value.Execute(controllerContext.Controller, argumentValues);
}
catch (Exception e)
{
return TaskHelpers.FromError<object>(e);
}
}
ActionExecutorはActionの実行に対してツリーを表す方式を採用しています.この後、Action実行のdemoを書きます.
コンテンツ交渉(結果のシーケンス化)
先のパラメータバインドでは、パラメータの逆シーケンス化は、要求ヘッダ情報のContent-Typeに基づいて異なるシーケンス化オブジェクトを取得するものであり、結果をシーケンス化する過程でも同様であるが、取得したヘッダ情報はAcceptである.
Actionに対する戻り結果は,void,,object,ActionResult,HttpResponseMessageの場合が多い.HttpResponseMessageは、HttpMessageHandler全体の戻り値がHttpResponseMessageであるため、そのまま戻ることができる.IActionResultの場合、それ自体はExecuteAsyncメソッド(結果を返す)でHttpResponseMessageを返すことができます.異なるActionResultは不要なシーケンス化戦略を用いる.JsonResultは、結果を直接Json形式でシーケンス化します.OkNegotiatedContentResultタイプでは、JsonResultのように明確なシーケンス化方式がないため、この場合はクライアント要求に従ってシーケンス化を取得する.この方式はobjectとvoidタイプの戻り値にも同様に適用できるが,この具体的な実装はHttpResponseMessageの拡張法CreateResponseによって行われる.
ContentNegotiator
IContentNegotiator(System.Net.Http.Formatting)は、WebAPIにおいても「標準化されたコンポーネント」であり、デフォルトではDefaultContentNegotiator(System.Net.Http.Formatting)として実装されている.
public interface IContentNegotiator
{
ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters);
}
IContentNegotiatorには、MedioType情報と取得したシーケンス化オブジェクトを含むNegotiatorメソッドが1つしかありません.
public class ContentNegotiationResult
{
public MediaTypeFormatter Formatter { get; set; }
public MediaTypeHeaderValue MediaType { get; set; }
}
Demoでは、コンテンツ交渉の具体的な処理ロジックを示すためにMyContentNegotiationResultをカスタマイズしました.
ソースコード
Github: https://github.com/BarlowDu/WebAPI (API_12)
public class ReflectedHttpActionDescriptor : HttpActionDescriptor
{
public abstract Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken);
}
public override Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken)
{
if (controllerContext == null)
{
throw Error.ArgumentNull("controllerContext");
}
if (arguments == null)
{
throw Error.ArgumentNull("arguments");
}
if (cancellationToken.IsCancellationRequested)
{
return TaskHelpers.Canceled<object>();
}
try
{
object[] argumentValues = PrepareParameters(arguments, controllerContext);
return _actionExecutor.Value.Execute(controllerContext.Controller, argumentValues);
}
catch (Exception e)
{
return TaskHelpers.FromError<object>(e);
}
}
先のパラメータバインドでは、パラメータの逆シーケンス化は、要求ヘッダ情報のContent-Typeに基づいて異なるシーケンス化オブジェクトを取得するものであり、結果をシーケンス化する過程でも同様であるが、取得したヘッダ情報はAcceptである.
Actionに対する戻り結果は,void,,object,ActionResult,HttpResponseMessageの場合が多い.HttpResponseMessageは、HttpMessageHandler全体の戻り値がHttpResponseMessageであるため、そのまま戻ることができる.IActionResultの場合、それ自体はExecuteAsyncメソッド(結果を返す)でHttpResponseMessageを返すことができます.異なるActionResultは不要なシーケンス化戦略を用いる.JsonResult
ContentNegotiator
IContentNegotiator(System.Net.Http.Formatting)は、WebAPIにおいても「標準化されたコンポーネント」であり、デフォルトではDefaultContentNegotiator(System.Net.Http.Formatting)として実装されている.
public interface IContentNegotiator
{
ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters);
}
IContentNegotiatorには、MedioType情報と取得したシーケンス化オブジェクトを含むNegotiatorメソッドが1つしかありません.
public class ContentNegotiationResult
{
public MediaTypeFormatter Formatter { get; set; }
public MediaTypeHeaderValue MediaType { get; set; }
}
Demoでは、コンテンツ交渉の具体的な処理ロジックを示すためにMyContentNegotiationResult
ソースコード
Github: https://github.com/BarlowDu/WebAPI (API_12)