Skip to content

Service api

padzikm edited this page Dec 11, 2015 · 7 revisions

Apart from taking part in composition main application's page in response for a request, service components want to communicate with service server parts directly, for example via ajax calls from javascript. This type of communication cannot be pass through main application public api, because will pollute main api with actions not relevant for it, and main app only integrate services, so this wouldn't be direct call to wanted service.
Solution to this is very simple - when service is registered in main app's routing in unique way with its key, let's also add unique prefix for all its routes. In this way each service will have its own private api, which always starts with unique per service prefix. The simplest unique prefix is service name, as there can be only one service with given name in whole system. So each service will have its own api and in main application we restricted that cannot be area that ends with "service" to not confuse it with services private apis. Registering service with prefix is a matter of only adding prefix to route. As a result all service areas will remain to be areas, only with prefix in url and controllers without area will be registerd as area, because of prefix at the beginning. Registering controllers without area as area:

public override void RegisterArea(AreaRegistrationContext context)
{
      CreateRoute(
          context,
          ProductsConsts.ServiceName + "_service",
          ProductsConsts.ServiceName + "/{controller}/{action}/{id}", //Registering api with unique prefix
          new { action = "Index", id = UrlParameter.Optional},
          new[] { "CompositeUI.Products.Web.Controllers" }
          );
}

Registering controllers from area as area:

public override void RegisterArea(AreaRegistrationContext context) 
{
      CreateRoute(
          context,
          ProductsConsts.ServiceName + "_testArea_default",
          ProductsConsts.ServiceName + "/TestArea/{controller}/{action}/{id}", //Registering api with unique prefix
          new { action = "Index", id = UrlParameter.Optional }
          );
}

Notice that during registering area namespace is automatically captured and suffixed with ".Controllers" before storing in route, so if you register area from within namespace, that after adding ".Controllers" won't match your controller's namespace, then you must specify it manually.

As a result each url generated inside service will be automatically prefixed to point to this service. Example:

Url.Action("AddCustomer") //Creates /ServiceNameService/CurrentController/AddCustomer

As we can want to generate route that points to main application public api and not to private service api - for example button inside widget that will redirect user to different page on click - we can pass "external" parameter set to true when creating url. When this parameter is included in additional route values, then only main app routes will respond and will provide url pointing to main app public api. One thing to remember is that all service routes are registerd as areas, so when we want we want to create url from within area controller, then it's enough to just specify "external parameter and rest of the route values as normal, but when you want to create public url from controller without area, then you have to delete the area value that is include in route values to be able to match controller without area in main app.
Example of generating public api url from within area controller:

Url.Action("AddCustomer", new { _external_ = true }) //Creates /CurrentArea/CurrentController/AddCustomer

Example of generating public api url from within controller without area:

Url.Action("AddCustomer", new { area = "", _external_ = true }) //Creates /CurrentController/AddCustomer
Clone this wiki locally