MVC 4! + Angular2 rooting - połączenie 2 autostrad

Trochę się zakopałem ostatnio ale na rozgrzewkę mam temat z ostatniej przygody. 
Jestem zadziorny i jak wszyscy .Net robią Angular2 z MVC 5, to w tym projekcie che pogodzić Angulara z MVC 4. 

Specyfika projektu to:

  • /front/*  - to Angular2 dostępny tylko dla zweryfikowanych
  • !/front/* - MVC wraz z weryfikacją.

Angular oczywiście będzie pracował na własnym zarejestrowanym routingu, MVC też, i rozgraniczenie tego na czystych wpisach do MapRoute działało dobrze jeśli użytkownik wszedł na stronę logowania a następnie korzystał z aplikacji. Jeśli jednak posiadał linka /front/xza, a nie był zweryfikowany otrzymywał 404. Brutalne :) Brakowało małęgo RedirectTo /Login?ReturnUrl=%2ffront%2fxza  Brutalne :)

Spróbowałem więc na poziomie rooting odfiltrować.
Klasa do zarejestrowania Constraint

 public class ServerRouteConstraint : IRouteConstraint
 {
     private readonly Func<Uri, bool> _predicate;

     public ServerRouteConstraint(Func<Uri, bool> predicate)
     {
         this._predicate = predicate;
     }

     public bool Match(HttpContextBase httpContext, Route route, string parameterName,
         RouteValueDictionary values, RouteDirection routeDirection)
     {
         if(routeDirection == RouteDirection.IncomingRequest)
             return this._predicate(httpContext.Request.Url);
         return true;
     }
 }

I zarejestrowanie 

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            constraints: new
            {
                serverRoute = new ServerRouteConstraint(url =>!isFront(url))
            }
    );
    routes.MapRoute(
        name: "angular",
        url: "{*url}",
        defaults: new { controller = "Home", action = "FrontIndex" },
        constraints: new
        {
            serverRoute = new ServerRouteConstraint(url => isFront(url))
        }
    );

}

private static bool isFront(Uri url)
{
    return url.PathAndQuery.StartsWith("/front",StringComparison.InvariantCultureIgnoreCase) ;
}

Ale tutaj mamy mały problem, gdyż moment wywołania isFornt nie posiada obiektu Sessji. Z tego powodu specjalnie akcja domyślnie jest przekierowywana pod akcje FrontIndex w kontrolerze Home. Tam jest weryfikacja do której również jest potrzebna sesja, i w zależności od tego albo jest wczytywany Index gdzie pałeczkę przejmuje Angular, albo path jest przekazywany do strony logowania.

[HDAuthorization]
public ActionResult Index()
{
    ViewBag.Title = "Use angular and have fun";
    return View("Index");
}

public ActionResult FrontIndex()
{
    if (HDAuthorization.IsLoginUser())
        return Index();
    else
    {
        return RedirectToAction("Login", new
        {
            ReturnUrl = Request.Path
        });
    }
}

public ActionResult Login()
{
    ViewBag.Title = "Login Page";
    return View();
}

[HttpPost]
public ActionResult Login(LoginModel model)
{
    var loginReturn = loginManager.Login(model);
    if (loginReturn.Authenticated)
    {
        if (Request.Path.StartsWith("/front/"))
            return Redirect(Request.Path);
        string requestParam = Request.Params["ReturnUrl"];
        if (string.IsNullOrWhiteSpace(requestParam))
            return  RedirectToAction("Index");
        return  Redirect(requestParam);
    }
    ViewBag.LoginError = loginReturn.FailureText;
    return View();
}

Oczywiście dla angulara konfiguracja wygląda następująco : 

const appRoutes: Routes = [
    { path: 'front/requests', component: AppRequests },
    { path: 'front/request/:id', component: AppRequest } ......

I udało się. Może nie top 100 najładniejszych rozwiązań ale spokojnie wystarcza mi odseparowanie path /front/* dla Angulara a pozostałe niech pożera MVC, natomiast co najważniejsze kiedy user nie ma dostępu do /front/ bo nie jest jeszcze zweryfikowany to dostanie redirect do login wraz z linkiem powrotnym do frontu. 

 

via GIPHY