/// <summary>
        /// Generates a URL based on the current Umbraco URL with a custom query string that will route to the specified SurfaceController
        /// </summary>
        /// <param name="url"></param>
        /// <param name="action"></param>
        /// <param name="surfaceType"></param>
        /// <param name="additionalRouteVals"></param>
        /// <returns></returns>
        public static string SurfaceAction(this UrlHelper url, string action, Type surfaceType, object additionalRouteVals)
        {
            if (string.IsNullOrEmpty(action))
            {
                throw new ArgumentNullOrEmptyException(nameof(action));
            }
            if (surfaceType == null)
            {
                throw new ArgumentNullException(nameof(surfaceType));
            }

            var area = "";

            var surfaceController = Current.SurfaceControllerTypes.SingleOrDefault(x => x == surfaceType);

            if (surfaceController == null)
            {
                throw new InvalidOperationException("Could not find the surface controller of type " + surfaceType.FullName);
            }
            var metaData = PluginController.GetMetadata(surfaceController);

            if (metaData.AreaName.IsNullOrWhiteSpace() == false)
            {
                //set the area to the plugin area
                area = metaData.AreaName;
            }

            var encryptedRoute = CreateEncryptedRouteString(metaData.ControllerName, action, area, additionalRouteVals);

            var result = Current.UmbracoContext.OriginalRequestUrl.AbsolutePath.EnsureEndsWith('?') + "ufprt=" + encryptedRoute;

            return(result);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Return the Url for a Web Api service
        /// </summary>
        /// <param name="url"></param>
        /// <param name="actionName"></param>
        /// <param name="apiControllerType"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        public static string GetUmbracoApiService(this UrlHelper url, string actionName, Type apiControllerType, object id = null)
        {
            if (actionName == null)
            {
                throw new ArgumentNullException(nameof(actionName));
            }
            if (string.IsNullOrWhiteSpace(actionName))
            {
                throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(actionName));
            }
            if (apiControllerType == null)
            {
                throw new ArgumentNullException(nameof(apiControllerType));
            }

            var area = "";

            var apiController = Current.UmbracoApiControllerTypes
                                .SingleOrDefault(x => x == apiControllerType);

            if (apiController == null)
            {
                throw new InvalidOperationException("Could not find the umbraco api controller of type " + apiControllerType.FullName);
            }
            var metaData = PluginController.GetMetadata(apiController);

            if (metaData.AreaName.IsNullOrWhiteSpace() == false)
            {
                //set the area to the plugin area
                area = metaData.AreaName;
            }
            return(url.GetUmbracoApiService(actionName, ControllerExtensions.GetControllerName(apiControllerType), area, id));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Returns the result of a child action of a SurfaceController
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="htmlHelper"></param>
        /// <param name="actionName"></param>
        /// <param name="surfaceType"></param>
        /// <returns></returns>
        public static IHtmlString Action(this HtmlHelper htmlHelper, string actionName, Type surfaceType)
        {
            Mandate.ParameterNotNull(surfaceType, "surfaceType");
            Mandate.ParameterNotNullOrEmpty(actionName, "actionName");

            var routeVals = new RouteValueDictionary(new { area = "" });

            var surfaceController = SurfaceControllerResolver.Current.RegisteredSurfaceControllers
                                    .SingleOrDefault(x => x == surfaceType);

            if (surfaceController == null)
            {
                throw new InvalidOperationException("Could not find the surface controller of type " + surfaceType.FullName);
            }
            var metaData = PluginController.GetMetadata(surfaceController);

            if (!metaData.AreaName.IsNullOrWhiteSpace())
            {
                //set the area to the plugin area
                if (routeVals.ContainsKey("area"))
                {
                    routeVals["area"] = metaData.AreaName;
                }
                else
                {
                    routeVals.Add("area", metaData.AreaName);
                }
            }

            return(htmlHelper.Action(actionName, metaData.ControllerName, routeVals));
        }
        private void RoutePluginControllers()
        {
            var umbracoPath = GlobalSettings.UmbracoMvcArea;

            //we need to find the plugin controllers and route them
            var pluginControllers =
                SurfaceControllerResolver.Current.RegisteredSurfaceControllers.Concat(
                    UmbracoApiControllerResolver.Current.RegisteredUmbracoApiControllers).ToArray();

            //local controllers do not contain the attribute
            var localControllers = pluginControllers.Where(x => PluginController.GetMetadata(x).AreaName.IsNullOrWhiteSpace());
            foreach (var s in localControllers)
            {
                if (TypeHelper.IsTypeAssignableFrom<SurfaceController>(s))
                {
                    RouteLocalSurfaceController(s, umbracoPath);
                }
                else if (TypeHelper.IsTypeAssignableFrom<UmbracoApiController>(s))
                {
                    RouteLocalApiController(s, umbracoPath);
                }
            }

            //need to get the plugin controllers that are unique to each area (group by)
            var pluginSurfaceControlleres = pluginControllers.Where(x => !PluginController.GetMetadata(x).AreaName.IsNullOrWhiteSpace());
            var groupedAreas = pluginSurfaceControlleres.GroupBy(controller => PluginController.GetMetadata(controller).AreaName);
            //loop through each area defined amongst the controllers
            foreach (var g in groupedAreas)
            {
                //create an area for the controllers (this will throw an exception if all controllers are not in the same area)
                var pluginControllerArea = new PluginControllerArea(g.Select(PluginController.GetMetadata));
                //register it
                RouteTable.Routes.RegisterArea(pluginControllerArea);
            }
        }
        /// <summary>
        /// Return the Url for a Web Api service
        /// </summary>
        /// <param name="url"></param>
        /// <param name="actionName"></param>
        /// <param name="apiControllerType"></param>
        /// <param name="routeVals"></param>
        /// <returns></returns>
        public static string GetUmbracoApiService(this UrlHelper url, string actionName, Type apiControllerType, RouteValueDictionary routeVals = null)
        {
            if (string.IsNullOrEmpty(actionName))
            {
                throw new ArgumentNullOrEmptyException(nameof(actionName));
            }
            if (apiControllerType == null)
            {
                throw new ArgumentNullException(nameof(apiControllerType));
            }

            var area = "";

            var apiController = Current.UmbracoApiControllerTypes
                                .SingleOrDefault(x => x == apiControllerType);

            if (apiController == null)
            {
                throw new InvalidOperationException("Could not find the umbraco api controller of type " + apiControllerType.FullName);
            }
            var metaData = PluginController.GetMetadata(apiController);

            if (!metaData.AreaName.IsNullOrWhiteSpace())
            {
                //set the area to the plugin area
                area = metaData.AreaName;
            }
            return(url.GetUmbracoApiService(actionName, ControllerExtensions.GetControllerName(apiControllerType), area, routeVals));
        }
Ejemplo n.º 6
0
    /// <summary>
    ///     Auto-routes all back office api controllers
    /// </summary>
    private void AutoRouteBackOfficeApiControllers(IEndpointRouteBuilder endpoints)
    {
        // TODO: We could investigate dynamically routing plugin controllers so we don't have to eagerly type scan for them,
        // it would probably work well, see https://www.strathweb.com/2019/08/dynamic-controller-routing-in-asp-net-core-3-0/
        // will probably be what we use for front-end routing too. BTW the orig article about migrating from IRouter to endpoint
        // routing for things like a CMS is here https://github.com/dotnet/aspnetcore/issues/4221

        foreach (Type controller in _apiControllers)
        {
            PluginControllerMetadata meta = PluginController.GetMetadata(controller);

            // exclude front-end api controllers
            if (!meta.IsBackOffice)
            {
                continue;
            }

            endpoints.MapUmbracoApiRoute(
                meta.ControllerType,
                _umbracoPathSegment,
                meta.AreaName,
                meta.IsBackOffice,
                string.Empty); // no default action (this is what we had before)
        }
    }
Ejemplo n.º 7
0
        /// <summary>
        /// Helper method to create a new form to execute in the Umbraco request pipeline to a surface controller plugin
        /// </summary>
        /// <param name="html"></param>
        /// <param name="action"></param>
        /// <param name="surfaceType">The surface controller to route to</param>
        /// <param name="additionalRouteVals"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, Type surfaceType,
                                               object additionalRouteVals,
                                               IDictionary <string, object> htmlAttributes)
        {
            Mandate.ParameterNotNullOrEmpty(action, "action");
            Mandate.ParameterNotNull(surfaceType, "surfaceType");

            var area = "";

            var surfaceController = SurfaceControllerResolver.Current.RegisteredSurfaceControllers
                                    .SingleOrDefault(x => x == surfaceType);

            if (surfaceController == null)
            {
                throw new InvalidOperationException("Could not find the surface controller of type " + surfaceType.FullName);
            }
            var metaData = PluginController.GetMetadata(surfaceController);

            if (!metaData.AreaName.IsNullOrWhiteSpace())
            {
                //set the area to the plugin area
                area = metaData.AreaName;
            }
            return(html.BeginUmbracoForm(action, metaData.ControllerName, area, additionalRouteVals, htmlAttributes));
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Helper method to create a new form to execute in the Umbraco request pipeline to a surface controller plugin
        /// </summary>
        /// <param name="html"></param>
        /// <param name="action"></param>
        /// <param name="surfaceType">The surface controller to route to</param>
        /// <param name="additionalRouteVals"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="method"></param>
        /// <returns></returns>
        public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, Type surfaceType,
                                               object additionalRouteVals,
                                               IDictionary <string, object> htmlAttributes,
                                               FormMethod method)
        {
            if (string.IsNullOrWhiteSpace(action))
            {
                throw new ArgumentNullOrEmptyException(nameof(action));
            }
            if (surfaceType == null)
            {
                throw new ArgumentNullException(nameof(surfaceType));
            }

            var area = "";

            var surfaceController = Current.SurfaceControllerTypes.SingleOrDefault(x => x == surfaceType);

            if (surfaceController == null)
            {
                throw new InvalidOperationException("Could not find the surface controller of type " + surfaceType.FullName);
            }
            var metaData = PluginController.GetMetadata(surfaceController);

            if (metaData.AreaName.IsNullOrWhiteSpace() == false)
            {
                //set the area to the plugin area
                area = metaData.AreaName;
            }
            return(html.BeginUmbracoForm(action, metaData.ControllerName, area, additionalRouteVals, htmlAttributes, method));
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Return the Url for an Umbraco controller
        /// </summary>
        public static string GetUmbracoControllerUrl(this LinkGenerator linkGenerator, string actionName, Type controllerType, IDictionary <string, object> values = null)
        {
            if (actionName == null)
            {
                throw new ArgumentNullException(nameof(actionName));
            }

            if (string.IsNullOrWhiteSpace(actionName))
            {
                throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(actionName));
            }

            if (controllerType == null)
            {
                throw new ArgumentNullException(nameof(controllerType));
            }

            var area = string.Empty;

            if (!typeof(ControllerBase).IsAssignableFrom(controllerType))
            {
                throw new InvalidOperationException($"The controller {controllerType} is of type {typeof(ControllerBase)}");
            }

            PluginControllerMetadata metaData = PluginController.GetMetadata(controllerType);

            if (metaData.AreaName.IsNullOrWhiteSpace() == false)
            {
                // set the area to the plugin area
                area = metaData.AreaName;
            }

            return(linkGenerator.GetUmbracoControllerUrl(actionName, ControllerExtensions.GetControllerName(controllerType), area, values));
        }
Ejemplo n.º 10
0
 public void Ensure_Same_Area3()
 {
     Assert.Throws <InvalidOperationException>(() =>
                                               new PluginControllerArea(new PluginControllerMetadata[]
     {
         PluginController.GetMetadata(typeof(Plugin1Controller)),
         PluginController.GetMetadata(typeof(Plugin2Controller)),
         PluginController.GetMetadata(typeof(Plugin4Controller))                                                                                                         //no area assigned
     }));
 }
Ejemplo n.º 11
0
 public void Ensure_Same_Area1()
 {
     Assert.Throws <InvalidOperationException>(() =>
                                               new PluginControllerArea(new PluginControllerMetadata[]
     {
         PluginController.GetMetadata(typeof(Controller1)),
         PluginController.GetMetadata(typeof(Controller2)),
         PluginController.GetMetadata(typeof(Controller3))                                                                                                         //not same area
     }));
 }
Ejemplo n.º 12
0
        public void Ensure_Same_Area2()
        {
            var area = new PluginControllerArea(new PluginControllerMetadata[]
            {
                PluginController.GetMetadata(typeof(Plugin1Controller)),
                PluginController.GetMetadata(typeof(Plugin2Controller))
            });

            Assert.Pass();
        }
        public void Ensure_Same_Area2()
        {
            var area = new PluginControllerArea(TestObjects.GetGlobalSettings(),
                                                new PluginControllerMetadata[]
            {
                PluginController.GetMetadata(typeof(Plugin1Controller)),
                PluginController.GetMetadata(typeof(Plugin2Controller))
            });

            Assert.Pass();
        }
 public void Ensure_Same_Area1()
 {
     Assert.Throws <InvalidOperationException>(() =>
                                               new PluginControllerArea(TestObjects.GetGlobalSettings(),
                                                                        new PluginControllerMetadata[]
     {
         PluginController.GetMetadata(typeof(Plugin1Controller)),
         PluginController.GetMetadata(typeof(Plugin2Controller)),
         PluginController.GetMetadata(typeof(Plugin3Controller))                                             //not same area
     }));
 }
    /// <summary>
    ///     Helper method to create a new form to execute in the Umbraco request pipeline to a surface controller plugin
    /// </summary>
    public static MvcForm BeginUmbracoForm(
        this IHtmlHelper html,
        string action,
        Type surfaceType,
        object?additionalRouteVals,
        IDictionary <string, object?> htmlAttributes,
        FormMethod method)
    {
        if (action == null)
        {
            throw new ArgumentNullException(nameof(action));
        }

        if (string.IsNullOrWhiteSpace(action))
        {
            throw new ArgumentException(
                      "Value can't be empty or consist only of white-space characters.",
                      nameof(action));
        }

        if (surfaceType == null)
        {
            throw new ArgumentNullException(nameof(surfaceType));
        }

        SurfaceControllerTypeCollection surfaceControllerTypeCollection =
            GetRequiredService <SurfaceControllerTypeCollection>(html);
        Type?surfaceController = surfaceControllerTypeCollection.SingleOrDefault(x => x == surfaceType);

        if (surfaceController == null)
        {
            throw new InvalidOperationException("Could not find the surface controller of type " +
                                                surfaceType.FullName);
        }

        PluginControllerMetadata metaData = PluginController.GetMetadata(surfaceController);

        var area = string.Empty;

        if (metaData.AreaName.IsNullOrWhiteSpace() == false)
        {
            // Set the area to the plugin area
            area = metaData.AreaName;
        }

        return(html.BeginUmbracoForm(
                   action,
                   metaData.ControllerName,
                   area !,
                   additionalRouteVals,
                   htmlAttributes,
                   method));
    }
Ejemplo n.º 16
0
        /// <summary>
        /// Creates the routes
        /// </summary>
        protected internal void CreateRoutes()
        {
            var umbracoPath = GlobalSettings.UmbracoMvcArea;

            //Create the front-end route
            var defaultRoute = RouteTable.Routes.MapRoute(
                "Umbraco_default",
                "Umbraco/RenderMvc/{action}/{id}",
                new { controller = "RenderMvc", action = "Index", id = UrlParameter.Optional }
                );

            defaultRoute.RouteHandler = new RenderRouteHandler(ControllerBuilder.Current.GetControllerFactory());

            //Create the install routes
            var installPackageRoute = RouteTable.Routes.MapRoute(
                "Umbraco_install_packages",
                "Install/PackageInstaller/{action}/{id}",
                new { controller = "InstallPackage", action = "Index", id = UrlParameter.Optional }
                );

            installPackageRoute.DataTokens.Add("area", umbracoPath);

            //we need to find the surface controllers and route them
            var surfaceControllers = SurfaceControllerResolver.Current.RegisteredSurfaceControllers.ToArray();

            //local surface controllers do not contain the attribute
            var localSurfaceControlleres = surfaceControllers.Where(x => PluginController.GetMetadata(x).AreaName.IsNullOrWhiteSpace());

            foreach (var s in localSurfaceControlleres)
            {
                var meta  = PluginController.GetMetadata(s);
                var route = RouteTable.Routes.MapRoute(
                    string.Format("umbraco-{0}-{1}", "surface", meta.ControllerName),
                    umbracoPath + "/Surface/" + meta.ControllerName + "/{action}/{id}", //url to match
                    new { controller = meta.ControllerName, action = "Index", id = UrlParameter.Optional },
                    new[] { meta.ControllerNamespace });                                //only match this namespace
                route.DataTokens.Add("umbraco", "surface");                             //ensure the umbraco token is set
            }

            //need to get the plugin controllers that are unique to each area (group by)
            //TODO: One day when we have more plugin controllers, we will need to do a group by on ALL of them to pass into the ctor of PluginControllerArea
            var pluginSurfaceControlleres = surfaceControllers.Where(x => !PluginController.GetMetadata(x).AreaName.IsNullOrWhiteSpace());
            var groupedAreas = pluginSurfaceControlleres.GroupBy(controller => PluginController.GetMetadata(controller).AreaName);

            //loop through each area defined amongst the controllers
            foreach (var g in groupedAreas)
            {
                //create an area for the controllers (this will throw an exception if all controllers are not in the same area)
                var pluginControllerArea = new PluginControllerArea(g.Select(PluginController.GetMetadata));
                //register it
                RouteTable.Routes.RegisterArea(pluginControllerArea);
            }
        }
 private void RouteLocalSurfaceController(Type controller, string umbracoPath)
 {
     var meta = PluginController.GetMetadata(controller);
     var route = RouteTable.Routes.MapRoute(
         string.Format("umbraco-{0}-{1}", "surface", meta.ControllerName),
         umbracoPath + "/Surface/" + meta.ControllerName + "/{action}/{id}",//url to match
         new { controller = meta.ControllerName, action = "Index", id = UrlParameter.Optional },
         new[] { meta.ControllerNamespace }); //look in this namespace to create the controller
     route.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, "surface"); //ensure the umbraco token is set
     route.DataTokens.Add("UseNamespaceFallback", false); //Don't look anywhere else except this namespace!
     //make it use our custom/special SurfaceMvcHandler
     route.RouteHandler = new SurfaceRouteHandler();
 }
Ejemplo n.º 18
0
        /// <summary>
        /// Auto-routes all front-end surface controllers
        /// </summary>
        private void AutoRouteSurfaceControllers(IEndpointRouteBuilder endpoints)
        {
            foreach (Type controller in _surfaceControllerTypeCollection)
            {
                // exclude front-end api controllers
                PluginControllerMetadata meta = PluginController.GetMetadata(controller);

                endpoints.MapUmbracoSurfaceRoute(
                    meta.ControllerType,
                    _umbracoPathSegment,
                    meta.AreaName);
            }
        }
    /// <summary>
    ///     Returns the result of a child action of a SurfaceController
    /// </summary>
    public static IHtmlContent ActionLink(this IHtmlHelper htmlHelper, string actionName, Type surfaceType)
    {
        if (actionName == null)
        {
            throw new ArgumentNullException(nameof(actionName));
        }

        if (string.IsNullOrWhiteSpace(actionName))
        {
            throw new ArgumentException(
                      "Value can't be empty or consist only of white-space characters.",
                      nameof(actionName));
        }

        if (surfaceType == null)
        {
            throw new ArgumentNullException(nameof(surfaceType));
        }

        SurfaceControllerTypeCollection surfaceControllerTypeCollection =
            GetRequiredService <SurfaceControllerTypeCollection>(htmlHelper);
        Type?surfaceController = surfaceControllerTypeCollection.SingleOrDefault(x => x == surfaceType);

        if (surfaceController == null)
        {
            throw new InvalidOperationException("Could not find the surface controller of type " +
                                                surfaceType.FullName);
        }

        var routeVals = new RouteValueDictionary(new { area = string.Empty });

        PluginControllerMetadata metaData = PluginController.GetMetadata(surfaceController);

        if (!metaData.AreaName.IsNullOrWhiteSpace())
        {
            // set the area to the plugin area
            if (routeVals.ContainsKey("area"))
            {
                routeVals["area"] = metaData.AreaName;
            }
            else
            {
                routeVals.Add("area", metaData.AreaName);
            }
        }

        return(htmlHelper.ActionLink(actionName, metaData.ControllerName, routeVals));
    }
        private static void RouteLocalApiController(Type controller, string umbracoPath)
        {
            var meta  = PluginController.GetMetadata(controller);
            var url   = umbracoPath + (meta.IsBackOffice ? "/BackOffice" : "") + "/Api/" + meta.ControllerName + "/{action}/{id}";
            var route = RouteTable.Routes.MapHttpRoute(
                $"umbraco-api-{meta.ControllerName}",
                url, // url to match
                new { controller = meta.ControllerName, id = UrlParameter.Optional },
                new[] { meta.ControllerNamespace });

            if (route.DataTokens == null) // web api routes don't set the data tokens object
            {
                route.DataTokens = new RouteValueDictionary();
            }
            route.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, "api"); //ensure the umbraco token is set
        }
Ejemplo n.º 21
0
        private void RouteLocalApiController(Type controller, string umbracoPath)
        {
            var meta  = PluginController.GetMetadata(controller);
            var route = RouteTable.Routes.MapHttpRoute(
                string.Format("umbraco-{0}-{1}", "api", meta.ControllerName),
                umbracoPath + "/Api/" + meta.ControllerName + "/{action}/{id}", //url to match
                new { controller = meta.ControllerName, id = UrlParameter.Optional });

            //web api routes don't set the data tokens object
            if (route.DataTokens == null)
            {
                route.DataTokens = new RouteValueDictionary();
            }
            route.DataTokens.Add("Namespaces", new[] { meta.ControllerNamespace }); //look in this namespace to create the controller
            route.DataTokens.Add("UseNamespaceFallback", false);                    //Don't look anywhere else except this namespace!
            route.DataTokens.Add("umbraco", "api");                                 //ensure the umbraco token is set
        }
Ejemplo n.º 22
0
        /// <summary>
        /// Auto-routes all front-end api controllers
        /// </summary>
        private void AutoRouteFrontEndApiControllers(IEndpointRouteBuilder endpoints)
        {
            foreach (Type controller in _apiControllers)
            {
                PluginControllerMetadata meta = PluginController.GetMetadata(controller);

                // exclude back-end api controllers
                if (meta.IsBackOffice)
                {
                    continue;
                }

                endpoints.MapUmbracoApiRoute(
                    meta.ControllerType,
                    _umbracoPathSegment,
                    meta.AreaName,
                    meta.IsBackOffice,
                    defaultAction: string.Empty); // no default action (this is what we had before)
            }
        }
        private void RouteLocalApiController(Type controller, string umbracoPath)
        {
            var meta = PluginController.GetMetadata(controller);

            //url to match
            var routePath = meta.IsBackOffice == false
                                ? umbracoPath + "/Api/" + meta.ControllerName + "/{action}/{id}"
                                : umbracoPath + "/BackOffice/Api/" + meta.ControllerName + "/{action}/{id}";

            var route = RouteTable.Routes.MapHttpRoute(
                string.Format("umbraco-{0}-{1}", "api", meta.ControllerName),
                routePath,
                new { controller = meta.ControllerName, id = UrlParameter.Optional },
                new[] { meta.ControllerNamespace });
            //web api routes don't set the data tokens object
            if (route.DataTokens == null)
            {
                route.DataTokens = new RouteValueDictionary();
            }
            route.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, "api"); //ensure the umbraco token is set
        }
Ejemplo n.º 24
0
        /// <summary>
        /// Return the Url for a Web Api service
        /// </summary>
        /// <param name="url"></param>
        /// <param name="actionName"></param>
        /// <param name="apiControllerType"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        public static string GetUmbracoApiService(this UrlHelper url, string actionName, Type apiControllerType, object id = null)
        {
            Mandate.ParameterNotNullOrEmpty(actionName, "actionName");
            Mandate.ParameterNotNull(apiControllerType, "apiControllerType");

            var area = "";

            var apiController = UmbracoApiControllerResolver.Current.RegisteredUmbracoApiControllers
                                .SingleOrDefault(x => x == apiControllerType);

            if (apiController == null)
            {
                throw new InvalidOperationException("Could not find the umbraco api controller of type " + apiControllerType.FullName);
            }
            var metaData = PluginController.GetMetadata(apiController);

            if (metaData.AreaName.IsNullOrWhiteSpace() == false)
            {
                //set the area to the plugin area
                area = metaData.AreaName;
            }
            return(url.GetUmbracoApiService(actionName, ControllerExtensions.GetControllerName(apiControllerType), area));
        }