LoginSignup
2
4

More than 5 years have passed since last update.

ASP.NET Web API パイプライン拡張サンプル

Last updated at Posted at 2018-10-06

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);
        }
    }
2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4