/// <summary> /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler" /> interface. /// </summary> /// <param name="context">An <see cref="T:System.Web.HttpContext" /> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param> public void ProcessRequest(HttpContext context) { ApiEventLog eventLog = null; var entryStamp = DateTime.UtcNow; RestApiSettings settings = DefaultSettings; RuntimeContext runtimeContext = null; string traceId = null; BaseException baseException = null; context.Response.Headers.Add(HttpConstants.HttpHeader.SERVERENTRYTIME, entryStamp.ToFullDateTimeTzString()); var acceptEncoding = context.Request.Headers[HttpConstants.HttpHeader.AcceptEncoding].SafeToLower(); try { traceId = context.Request.TryGetHeader(HttpConstants.HttpHeader.TRACEID); Prepare(context.Request); if (context.Request.HttpMethod.Equals(HttpConstants.HttpMethod.Options, StringComparison.OrdinalIgnoreCase)) { if (this.AllowOptions) { //Return directly. IIS would append following headers by default, according to what exactly web.config have. //Access-Control-Allow-Origin: * //Access-Control-Allow-Headers: Content-Type //Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS return; } } runtimeContext = ProcessRoute(context.Request); runtimeContext.CheckNullObject("runtimeContext"); settings = runtimeContext.Settings ?? DefaultSettings; if (runtimeContext.Version.Equals(BuildInFeatureVersionKeyword, StringComparison.OrdinalIgnoreCase)) { var buildInResult = ProcessBuildInFeature(runtimeContext, context.Request.IsLocal); PackageOutput(context.Response, buildInResult, null, acceptEncoding, runtimeContext.IsVoid ?? false, settings); } else { //Initialize additional header keys if (runtimeContext.CustomizedHeaderKeys.HasItem()) { var currentApiContext = ContextHelper.ApiContext; foreach (var one in runtimeContext.CustomizedHeaderKeys) { currentApiContext.CustomizedHeaders.Merge(one, context.Request.TryGetHeader(one)); } } if (settings != null && settings.ApiTracking != null && settings.TrackingEvent) { eventLog = new ApiEventLog { RawUrl = context.Request.RawUrl, EntryStamp = entryStamp, UserAgent = context.Request.UserAgent, TraceId = traceId, // If request came from ApiTransport or other proxy ways, ORIGINAL stands for the IP ADDRESS from original requester. IpAddress = context.Request.TryGetHeader(HttpConstants.HttpHeader.ORIGINAL).SafeToString(context.Request.UserHostAddress), CultureCode = context.Request.UserLanguages == null ? null : context.Request.UserLanguages.FirstOrDefault(), ContentLength = context.Request.ContentLength }; } InitializeContext(context.Request, runtimeContext); if (!string.IsNullOrWhiteSpace(traceId)) { ApiTraceContext.Initialize(runtimeContext, traceId, entryStamp); } if (eventLog != null) { if (runtimeContext.ApiInstance != null) { eventLog.ServiceIdentifier = runtimeContext.ApiInstance.GetType().Name; } if (runtimeContext.ApiMethod != null) { eventLog.ApiFullName = runtimeContext.ApiMethod.Name; } eventLog.ResourceName = runtimeContext.ResourceName; eventLog.ServerIdentifier = EnvironmentCore.ServerName; eventLog.UserIdentifier = runtimeContext.UserIdentifier; var clientIdentifierHeaderKey = settings.ClientIdentifierHeaderKey; if (!string.IsNullOrWhiteSpace(clientIdentifierHeaderKey)) { eventLog.ClientIdentifier = context.Request.TryGetHeader(clientIdentifierHeaderKey); } eventLog.ModuleName = runtimeContext.ModuleName; eventLog.ResourceEntityKey = runtimeContext.IsActionUsed ? runtimeContext.Parameter2 : runtimeContext.Parameter1; } if (runtimeContext.Exception != null) { throw runtimeContext.Exception; } try { if (runtimeContext.ApiTransportAttribute != null) { if (runtimeContext.ApiTransportAttribute.ApiTransportAdapter != null) { runtimeContext.ApiTransportAttribute.ApiTransportAdapter.PrepareInteraction(runtimeContext.ApiMethod, runtimeContext.ApiInstance, runtimeContext.EntityKey); } InvokeByTransport(context.Request, context.Response, runtimeContext.ApiTransportAttribute); } else { string jsonBody; var invokeResult = Invoke(runtimeContext.ApiInstance, runtimeContext.ApiMethod, context.Request, runtimeContext.EntityKey, out jsonBody); if (eventLog != null && !string.IsNullOrWhiteSpace(jsonBody)) { eventLog.Content = jsonBody.Length > 50 ? ((jsonBody.Substring(0, 40) + "..." + jsonBody.Substring(jsonBody.Length - 6, 6))) : jsonBody; } PackageOutput(context.Response, invokeResult, null, acceptEncoding, runtimeContext.IsVoid ?? false, settings); } } catch (Exception invokeEx) { throw invokeEx.Handle("Invoke", new { Url = context.Request.RawUrl, Method = context.Request.HttpMethod }); } } } catch (Exception ex) { var apiTracking = settings?.ApiTracking; baseException = ex.Handle("ProcessRequest", new { Uri = context.Request.Url.ToString() }); (apiTracking ?? Framework.ApiTracking).LogException(baseException.ToExceptionInfo(runtimeContext?.ApiServiceName, EnvironmentCore.ServerName)); if (eventLog != null) { eventLog.ExceptionKey = baseException.Key; } PackageOutput(context.Response, null, baseException, acceptEncoding, settings: settings); } finally { if (settings?.ApiTracking != null) { var exitStamp = DateTime.UtcNow; if (eventLog != null) { try { eventLog.ExitStamp = exitStamp; settings.ApiTracking.LogApiEvent(eventLog); } catch { } } if (ApiTraceContext.Root != null) { try { ApiTraceContext.Exit(baseException, exitStamp); settings.ApiTracking.LogApiTraceLog(ApiTraceContext.GetCurrentTraceLog(true)); } catch { } } } ThreadExtension.Clear(); } }
/// <summary> /// Called by the ASP.NET MVC framework before the action method executes. /// </summary> /// <param name="filterContext">The filter context.</param> public override void OnActionExecuting(ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); DateTime entryStamp = DateTime.UtcNow; var request = filterContext.HttpContext.Request; var traceId = request.TryGetHeader(HttpConstants.HttpHeader.TRACEID); var traceSequence = request.TryGetHeader(HttpConstants.HttpHeader.TRACESEQUENCE).ObjectToNullableInt32(); var methodInfo = (filterContext.ActionDescriptor as ReflectedActionDescriptor)?.MethodInfo; ContextHelper.ConsistContext(request, this.settings?.Name); if (!string.IsNullOrWhiteSpace(traceId)) { ApiTraceContext.Initialize(traceId, traceSequence, entryStamp); } if (settings != null && settings.TrackingEvent) { var context = filterContext.HttpContext; ApiEvent = new ApiEventLog { ApiFullName = methodInfo?.GetFullName(), RawUrl = context.Request.RawUrl, EntryStamp = entryStamp, UserAgent = context.Request.UserAgent, TraceId = traceId, // If request came from ApiTransport or other proxy ways, ORIGINAL stands for the IP ADDRESS from original requester. IpAddress = context.Request.TryGetHeader(settings?.OriginalIpAddressHeaderKey.SafeToString(HttpConstants.HttpHeader.ORIGINAL)).SafeToString(context.Request.UserHostAddress), CultureCode = ContextHelper.ApiContext.CultureCode, ContentLength = context.Request.ContentLength, OperatorCredential = ContextHelper.CurrentCredential as BaseCredential, Protocol = context.Request.Url.Scheme, ReferrerUrl = context.Request.UrlReferrer?.ToString(), ServerIdentifier = EnvironmentCore.ServerName, ServiceIdentifier = EnvironmentCore.ProjectName }; } var controllerType = methodInfo?.DeclaringType; var tokenRequiredAttribute = methodInfo?.GetCustomAttribute<TokenRequiredAttribute>(true) ?? controllerType?.GetCustomAttribute<TokenRequiredAttribute>(true); var permissionAttributes = controllerType?.GetCustomAttributes<ApiPermissionAttribute>(true).ToDictionary(); permissionAttributes.Merge(methodInfo?.GetCustomAttributes<ApiPermissionAttribute>(true).ToDictionary(), true); var tokenRequired = tokenRequiredAttribute != null && tokenRequiredAttribute.TokenRequired; if (tokenRequired) { if (!ContextHelper.IsUser) { var baseException = (new UnauthorizedTokenException(ContextHelper.Token)).Handle( filterContext.HttpContext.Request.ToExceptionScene(filterContext.RouteData?.GetControllerName()), data: new { filterContext.HttpContext.Request.RawUrl }); HandleUnauthorizedAction(filterContext, baseException); } else if (permissionAttributes.HasItem()) { var baseException = ContextHelper.CurrentUserInfo?.Permissions.ValidateApiPermission(permissionAttributes, ContextHelper.Token, methodInfo?.GetFullName()); if (baseException != null) { HandleUnauthorizedAction(filterContext, baseException); } } } ApiTraceContext.Enter(methodInfo.GetFullName(), setNameAsMajor: true); }