ASP.NET Web API パイプラインを拡張するサンプルです。
サンプルコードのみですが、内容を忘れないための備忘録として、、、
●参照
ASP.NET Web API 2
ASP.NET Web API HTTP メッセージライフサイクルポスター
サンプルソース
Program.cs
class Program
{
private static string baseAddress = "http://localhost:9000/";
static void Main(string[] args)
{
using (WebApp.Start<Startup>(url: baseAddress))
{
HttpClient client = new HttpClient();
var response = client.GetAsync(baseAddress + "MySelfHost/Values").Result;
Console.WriteLine(response);
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
}
Console.ReadLine();
}
}
ValuesController.cs
public class ValuesController : ApiController
{
public IEnumerable<string> Get()
{
return new string[] { "Value1", "Value2" };
}
public string Get(int id)
{
throw new Exception("test");
//return "Value";
}
public void Post([FromBody]string value)
{
}
public void Post(int id, [FromBody]string value)
{
}
public void Put(int id, [FromBody]string value)
{
}
public void Delete(int id)
{
}
}
Startup.cs
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
HttpConfiguration config = new HttpConfiguration();
var previousSelector =
config.Services.GetService(typeof(IHttpControllerSelector)) as IHttpControllerSelector;
config.Services.Replace(typeof(IHttpControllerSelector),
new MyWebApiControllerSelector(config) { PreviousSelector = previousSelector });
config.Services.Replace(typeof(IHttpActionSelector), new MyWebApiActionSelector());
config.Services.Replace(typeof(IExceptionHandler), new MyExceptionHandler());
config.MessageHandlers.Add(new MyMessageHandler());
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{namespace}/{controller}",
handler: null,
defaults: null,
constraints: null
);
appBuilder.UseWebApi(config);
}
}
MyMessageHandler.cs
internal class MyMessageHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
Debug.WriteLine("request");
var response = await base.SendAsync(request, cancellationToken);
Debug.WriteLine("response");
return response;
}
}
MyWebApiControllerSelector.cs
internal class MyWebApiControllerSelector : DefaultHttpControllerSelector
{
private HttpConfiguration _config;
public IHttpControllerSelector PreviousSelector { get; set; }
public MyWebApiControllerSelector(HttpConfiguration configuration) :
base(configuration)
{
_config = configuration;
}
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
IHttpRouteData routeData = request.GetRouteData();
string namespaceName = GetRouteVariable<string>(routeData, "namespace");
string controllerName = GetRouteVariable<string>(routeData, "controller");
string className = namespaceName + "." + controllerName + "Controller";
IAssembliesResolver assembliesResolver =
_config.Services.GetAssembliesResolver();
IHttpControllerTypeResolver controllersResolver =
_config.Services.GetHttpControllerTypeResolver();
ICollection<Type> controllerTypes =
controllersResolver.GetControllerTypes(assembliesResolver);
//var hoge = AppDomain.CurrentDomain.GetAssemblies();
Type typ = null;
foreach (var t in controllerTypes)
{
if (t.FullName == className)
{
typ = t;
break;
}
}
if (typ == null)
{
throw new Exception("コントローラがありません。");
}
HttpControllerDescriptor ret = new HttpControllerDescriptor();
ret.Configuration = _config;
ret.ControllerName = controllerName + "Controller";
ret.ControllerType = typ;
return ret;
}
private static T GetRouteVariable<T>(IHttpRouteData routeData, string name)
{
//戻り値
object result = null;
//取得対象のデータがrouteDataに含まれていたら、返す。
//含まれていなければ、<T>のdefaultを返す
if (routeData.Values.TryGetValue(name, out result))
{
return (T)result;
}
return default(T);
}
}
MyWebApiActionSelector.cs
internal class MyWebApiActionSelector : ApiControllerActionSelector
{
public override HttpActionDescriptor SelectAction
(HttpControllerContext controllerContext)
{
HttpActionDescriptor actionDescriptor =
base.SelectAction(controllerContext);
return actionDescriptor;
}
}
MyExceptionHandler.cs
internal class MyExceptionHandler : ExceptionHandler
{
public override void Handle(ExceptionHandlerContext context)
{
context.Result = new MyErrorResult(context.Request, context.Exception);
base.Handle(context);
}
}
MyErrorResult.cs
internal class MyErrorResult : IHttpActionResult
{
private Exception exception;
private HttpRequestMessage request;
public MyErrorResult(HttpRequestMessage request, Exception exception)
{
this.request = request;
this.exception = exception;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
JObject json = new JObject();
json.Add("status", (int)HttpStatusCode.InternalServerError);
json.Add("message", exception.Message);
json.Add("stackTrace", exception.StackTrace);
HttpResponseMessage response =
request.CreateErrorResponse(
HttpStatusCode.InternalServerError,
json.ToString(), exception
);
return Task.FromResult(response);
}
}