using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationModels; using System.Reflection; using System.Text; namespace zero.Api.Controllers; public class ZeroApiControllerModelConvention : IControllerModelConvention { protected Type BaseClassType { get; set; } = typeof(ZeroApiController); readonly AttributeRouteModel AppAwareRouteModel; readonly AttributeRouteModel AppUnawareRouteModel; readonly Type SystemApiType = typeof(ZeroSystemApiAttribute); readonly ApiParameterTransformer Transformer = new(); readonly bool RuntimeIsAppAware = false; public ZeroApiControllerModelConvention(string path, bool isAppAware = false) { RuntimeIsAppAware = isAppAware; AppAwareRouteModel = BuildRouteModel(path, true); AppUnawareRouteModel = BuildRouteModel(path, false); } /// /// Configure routing model for all backoffice controllers /// public virtual void Apply(ControllerModel controller) { bool hasAttributeRouteModels = controller.Selectors.Any(selector => selector.AttributeRouteModel != null); if (controller.ControllerType.IsSubclassOf(BaseClassType)) { bool isAppAware = RuntimeIsAppAware && controller.ControllerType.GetCustomAttribute(SystemApiType) == null; controller.Selectors[0].AttributeRouteModel = isAppAware ? AppAwareRouteModel : AppUnawareRouteModel; controller.Filters.Add(new DisableBrowserCacheFilterAttribute()); foreach (var action in controller.Actions) { action.RouteParameterTransformer = Transformer; } } } protected virtual AttributeRouteModel BuildRouteModel(string pathSegment, bool appAware = false) { StringBuilder path = new(); path.Append(pathSegment.EnsureSurroundedWith('/')); path.Append("{zero_app_key}/"); // TODO add route constraint which only allows registered app-ids // see https://nemi-chand.github.io/creating-custom-routing-constraint-in-aspnet-core-mvc/ path.Append("[controller]"); return new AttributeRouteModel(new RouteAttribute(path.ToString())); } }