public HttpControllerDescriptor SelectController(HttpRequestMessage request) { // Log this lookup and add to history for insights var log = new Log("Sxc.Http", null, request?.RequestUri?.AbsoluteUri); AddToInsightsHistory(request?.RequestUri?.AbsoluteUri, log); var wrapLog = log.Call <HttpControllerDescriptor>(); if (!HandleRequestWithThisController(request)) { return(wrapLog("upstream", PreviousSelector.SelectController(request))); } var routeData = request.GetRouteData(); var controllerTypeName = routeData.Values[Names.Controller] + "Controller"; // Now Handle the 2sxc app-api queries // Figure out the Path, or show error for that var appFolder = AppFolderUtilities.GetAppFolder(request, log, wrapLog); var controllerPath = ""; try { // new for 2sxc 9.34 #1651 var edition = ""; if (routeData.Values.ContainsKey(Names.Edition)) { edition = routeData.Values[Names.Edition].ToString(); } if (!string.IsNullOrEmpty(edition)) { edition += "/"; } log.Add($"Edition: {edition}"); var tenant = Eav.Factory.StaticBuild <DnnSite>(); var controllerFolder = Path.Combine(tenant.AppsRootRelative, appFolder, edition + "api/"); controllerFolder = controllerFolder.Replace("\\", @"/"); log.Add($"Controller Folder: {controllerFolder}"); controllerPath = Path.Combine(controllerFolder + controllerTypeName + ".cs"); log.Add($"Controller Path: {controllerPath}"); // note: this may look like something you could optimize/cache the result, but that's a bad idea // because when the file changes, the type-object will be different, so please don't optimize :) if (File.Exists(HostingEnvironment.MapPath(controllerPath))) { var assembly = BuildManager.GetCompiledAssembly(controllerPath); var type = assembly.GetType(controllerTypeName, true, true); // help with path resolution for compilers running inside the created controller request?.Properties.Add(CodeCompiler.SharedCodeRootPathKeyInCache, controllerFolder); var descriptor = new HttpControllerDescriptor(_config, type.Name, type); return(wrapLog("ok", descriptor)); } log.Add("path not found, error will be thrown in a moment"); } catch (Exception e) { var msg = ApiErrPrefix + ApiErrGeneral + ApiErrSuffix; throw AppFolderUtilities.ReportToLogAndThrow(request, HttpStatusCode.InternalServerError, e, msg, wrapLog); } var msgFinal = $"2sxc Api Controller Finder: Controller {controllerTypeName} not found in app. " + $"We checked the virtual path '{controllerPath}'"; throw AppFolderUtilities.ReportToLogAndThrow(request, HttpStatusCode.NotFound, new Exception(), msgFinal, wrapLog); }
public HttpResponseMessage Inspect(string path) { var wrapLog = Log.Call <HttpResponseMessage>(); Log.Add($"Controller Path from appRoot: {path}"); if (string.IsNullOrWhiteSpace(path) || path.Contains("..")) { var msg = $"Error: bad parameter {path}"; return(wrapLog(msg, Request.CreateErrorResponse(HttpStatusCode.InternalServerError, msg))); } // Ensure make windows path slashes to make later work easier path = path.Backslash(); try { var controllerVirtualPath = Path.Combine(AppFolderUtilities.GetAppFolderVirtualPath(Request, Log), path); Log.Add($"Controller Virtual Path: {controllerVirtualPath}"); if (!File.Exists(HostingEnvironment.MapPath(controllerVirtualPath))) { var msg = $"Error: can't find controller file: {controllerVirtualPath}"; return(wrapLog(msg, Request.CreateErrorResponse(HttpStatusCode.InternalServerError, msg))); } var assembly = BuildManager.GetCompiledAssembly(controllerVirtualPath); var controllerName = path.Substring(path.LastIndexOf('\\') + 1); controllerName = controllerName.Substring(0, controllerName.IndexOf('.')); var controller = assembly.DefinedTypes.FirstOrDefault(a => controllerName.Equals(a.Name, StringComparison.InvariantCultureIgnoreCase)); if (controller == null) { var msg = $"Error: can't find controller class: {controllerName} in file {Path.GetFileNameWithoutExtension(path)}. This can happen if the controller class does not have the same name as the file."; return(wrapLog(msg, Request.CreateErrorResponse(HttpStatusCode.InternalServerError, msg))); } var controllerSecurity = GetSecurity(controller); var controllerDto = new ApiControllerDto { controller = controller.Name, actions = controller.GetMethods() .Where(methodInfo => methodInfo.IsPublic && !methodInfo.IsSpecialName && GetHttpVerbs(methodInfo).Count > 0) .Select(methodInfo => { var methodSecurity = GetSecurity(methodInfo); var mergedSecurity = MergeSecurity(controllerSecurity, methodSecurity); return(new ApiActionDto { name = methodInfo.Name, verbs = GetHttpVerbs(methodInfo).Select(m => m.ToUpperInvariant()), parameters = methodInfo.GetParameters().Select(p => new ApiActionParamDto { name = p.Name, type = ApiExplorerJs.JsTypeName(p.ParameterType), defaultValue = p.DefaultValue, isOptional = p.IsOptional, isBody = IsBody(p), }).ToArray(), security = methodSecurity, mergedSecurity = mergedSecurity, returns = ApiExplorerJs.JsTypeName(methodInfo.ReturnType), }); }), security = controllerSecurity }; var responseMessage = Request.CreateResponse(HttpStatusCode.OK); responseMessage.Content = new StringContent(controllerDto.ToJson(), Encoding.UTF8, "application/json"); return(wrapLog("ok", responseMessage)); } catch (Exception exc) { return(wrapLog($"Error: {exc.Message}.", Request.CreateErrorResponse(HttpStatusCode.InternalServerError, exc))); } }