[ASP.NET Core] route정보를 json으로 외재화

개요

프로젝트가 진행됨에 따라 라우팅 정보는 계속 변화하고 추가됩니다. 이를 위해 매번 코드를 건드리는 것은 위험하므로 정적인 appsetting.json으로 이전 시키는 과정을 통해 필요한 정보를 외재화하는 방안을 알아봅니다.

MapRoute에 필요한 정보

ASP.NET Core MVC의 라우터는 다양한 형태로 라우팅경로를 받을 수 있습니다만, 모든 경우의 수를 커버하는 파서를 만들어 설명하면 너무 복잡해지므로 여기서는 간단한 기본 구조를 처리하도록 하겠습니다.
보통은 다음 정도의 정보로 되어있을 것입니다.

route.MapRoute(
  name:"route1",
  template:"member/{action}",
  default:new {controller = "Member", action="Index"}
);

템플릿만으로 부족한 경우도 있기 때문에 default옵션까지는 커버해야 합니다(사실 constrain도 커버해야하지만 거기까지는 본 포스팅에서 다루지 않겠습니다 ^^)
제 경우 매번 name을 정하는 것도 고역이었습니다. 고유하기만 하면 되기 때문에 알아서 이름을 고유하게 넣어줬으면 좋겠다 싶은 기분이죠.
위의 내용을 정리해보면 다음과 같은 키가 도출됩니다.

  • name – 생략하면 알아서 고유값으로 셋팅해 줌.
  • template – 생략하면 빈 문자열이 됨.
  • controller – 지정하면 default의 controller항목이 됨.
  • action – 지정하면 default의 action항목이 됨.

json에 반영

위에서 제안된 내용 정도만 고민하여 appsetting.json에 반영해보죠.

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },
  //....
  "Route": [
    {
      "tmpl": "Main/{action=Index}",
      "default": { "controller": "Main" }
    },
    {
      "tmpl": "Admin/{action}",
      "default": { "controller": "Admin", "action": "Index" }
    },
    {
      "name": "bstestdefult",
      "tmpl": "{action=Index}",
      "default": { "controller": "Home" }
    }
  ]
}

Route라는 키를 신설하고 여기에 배열로 순서를 정할 수 있는 개별 라우팅 항목을 넣어줍니다.
찬찬히 3개의 샘플을 보면 첫 번째는 name, action을 생략하고 있습니다. 두 번째는 name만 생략했고, 세 번째는 action만 생략한 상태죠.
사실 json은 자유롭게 구성할 수 있으니 파서를 어떤 방향으로 구현하는가에 따라서 얼마든지 기능이 추가될 수 있을 것입니다.
이 포스팅에서는 위의 json 정도만 커버하는 파서를 제작해보겠습니다.

파서 제작

파서는 손쉽게 UseMvc 시점에 작성해주면 충분합니다만 재활용을 생각하면 별도의 메소드로 작성해도 좋습니다. 여기서는 그냥 바로 람다에 작성하도록 하겠습니다.

var map = configure.GetSection("Route");

if(map != null) { //Route항목이 있다면..

    app.UseMvc(route => {

        var i = 0; //고유이름을 자동으로 셋팅하기 위한 카운터

        foreach(var k in map.GetChildren()) {

            //컨트롤러와 액션항목을 읽어들이고
            var controller = k["default:controller"];
            var action = k["default:action"];

            //각 존재 여부에 따라 4가지 조합에 맞게 기본 값에 들어갈 객체를 구성해준다.
            object def = null;
            if(controller != null) {
                if(action != null) def = new { controller = controller, action = action };
                else def = new { controller = controller };
            } else if(action != null) def = new { action = action };
            else def = new { };

            //최종적으로 MapRoute에 설정
            route.MapRoute(
                name: k["name"] == null ? (i++) + "" : k["name"] + "", //이름이 없으면 i++로 설정
                template: k["tmpl"] == null ? "" : k["tmpl"] + "", //템플릿이 없으면 빈 문자열로 설정
                defaults: def
            );
        }
    });

} else app.UseMvcWithDefaultRoute(); //항목이 없으면 기본으로 대응

요 정도의 간단한 파서로 손쉽게 라우팅 정보를 외재화시켰습니다.

결론

프레임웍을 구성하는 많은 설정은 될수록 외재화 시켜야 설정의 변화 때문에 코드를 건드리는 일이 적어집니다. 수 많은 항목을 다 빼는게 맞지만 그 중에 현실적으로 의미가 있는 라우터 정보를 기준으로 외재화를 연습해봤습니다.