/// <summary> /// Initializes a new instance of the <see cref="WebSocketHandlerBase" /> class. /// </summary> /// <param name="maxBufferSize">Maximum size of the buffer.</param> protected WebSocketHandlerBase(int maxBufferSize, RestApiSettings defaultSettings) { if (maxBufferSize < 32) { maxBufferSize = 32; } this.MaxBufferSize = maxBufferSize; }
/// <summary> /// Initializes a new instance of the <see cref="RuntimeRoute" /> class. /// </summary> /// <param name="methodInfo">The method information.</param> /// <param name="instanceType">Type of the instance.</param> /// <param name="instance">The instance.</param> /// <param name="isActionUsed">if set to <c>true</c> [is action used].</param> /// <param name="isTokenRequired">if set to <c>true</c> [is token required].</param> /// <param name="moduleName">Name of the module.</param> /// <param name="setting">The setting.</param> /// <param name="permissions">The permissions.</param> /// <param name="headerKeys">The header keys.</param> public RuntimeRoute(MethodInfo methodInfo, Type instanceType, object instance, bool isActionUsed, bool isTokenRequired, string moduleName, RestApiSettings setting, IDictionary<string, ApiPermission> permissions = null, List<string> headerKeys = null) { this.MethodInfo = methodInfo; this.Instance = instance; this.IsActionUsed = isActionUsed; this.InstanceType = instanceType; this.ModuleName = moduleName; this.IsTokenRequired = isTokenRequired; this.Setting = setting; this.Permissions = permissions; this.HeaderKeys = headerKeys; }
/// <summary> /// Initializes a new instance of the <see cref="ApiHandlerBase" /> class. /// </summary> /// <param name="defaultApiSettings">The default API settings.</param> /// <param name="allowOptions">if set to <c>true</c> [allow options].</param> protected ApiHandlerBase(RestApiSettings defaultApiSettings, bool allowOptions = false) { // Ensure it is never null. Default values should be safe. DefaultSettings = defaultApiSettings ?? new RestApiSettings { TokenHeaderKey = HttpConstants.HttpHeader.TOKEN, ClientIdentifierHeaderKey = HttpConstants.HttpHeader.CLIENTIDENTIFIER, EnableContentCompression = true }; DefaultSettings.Name = DefaultSettings.Name.SafeToString(defaultSettingName); DefaultSettings.ApiTracking = DefaultSettings.ApiTracking ?? Framework.ApiTracking; settingsContainer.Merge(DefaultSettings.Name, DefaultSettings, false); this.AllowOptions = allowOptions; }
/// <summary> /// Initializes a new instance of the <see cref="ApiHandlerBase" /> class. /// </summary> /// <param name="defaultApiSettings">The default API settings.</param> /// <param name="allowOptions">if set to <c>true</c> [allow options].</param> protected ApiHandlerBase(RestApiSettings defaultApiSettings, bool allowOptions = false) { // Ensure it is never null. Default values should be safe. DefaultSettings = defaultApiSettings ?? new RestApiSettings { TokenHeaderKey = HttpConstants.HttpHeader.TOKEN, ClientIdentifierHeaderKey = HttpConstants.HttpHeader.CLIENTIDENTIFIER, EnableContentCompression = true, TrackingEvent = false, EnableOutputFullExceptionInfo = false }; DefaultSettings.Name = DefaultSettings.Name.SafeToString("Default"); DefaultSettings.ApiTracking = DefaultSettings.ApiTracking ?? DiagnosticFileLogger.CreateOrUpdateDiagnosticFileLogger(DefaultSettings.Name); settingsContainer.Merge(DefaultSettings.Name, DefaultSettings, false); this.AllowOptions = allowOptions; }
/// <summary> /// Packages the output. <c>Flush()</c> would be called in this method. /// </summary> /// <param name="response">The response.</param> /// <param name="data">The data.</param> /// <param name="baseException">The base exception.</param> /// <param name="acceptEncoding">Name of the compress.</param> /// <param name="noBody">if set to <c>true</c> [no body].</param> /// <param name="settings">The settings.</param> /// <returns>System.Object.</returns> protected virtual void PackageOutput(HttpResponse response, object data, BaseException baseException = null, string acceptEncoding = null, bool noBody = false, RestApiSettings settings = null) { PackageResponse(response, data, baseException, acceptEncoding, noBody, settings); }
/// <summary> /// Packages the response. <c>Flush()</c> would be called in this method. /// </summary> /// <param name="response">The response.</param> /// <param name="data">The data.</param> /// <param name="ex">The ex.</param> /// <param name="acceptEncoding">The accept encoding.</param> /// <param name="noBody">if set to <c>true</c> [no body].</param> /// <param name="settings">The settings.</param> public static void PackageResponse(HttpResponseBase response, object data, BaseException ex = null, string acceptEncoding = null, bool noBody = false, RestApiSettings settings = null) { if (response != null) { if (settings == null) { settings = defaultRestApiSettings; } var objectToReturn = ex != null ? (settings.EnableOutputFullExceptionInfo ? ex.ToExceptionInfo() : new SimpleExceptionInfo { Message = ex.Hint != null ? (ex.Hint.Message ?? ex.Hint.Cause) : ex.RootCause.Message, Data = data == null ? null : JObject.FromObject(data), Code = ex.Hint?.Code ?? ex.Code } as object) : data; response.Headers.Add(HttpConstants.HttpHeader.SERVERNAME, EnvironmentCore.ServerName); response.Headers.AddIfNotNull(HttpConstants.HttpHeader.TRACEID, ApiTraceContext.TraceId); response.StatusCode = (int)(ex == null ? (noBody ? HttpStatusCode.NoContent : HttpStatusCode.OK) : ex.Code.ToHttpStatusCode()); if (!noBody) { response.ContentType = "application/json"; if (settings.EnableContentCompression) { acceptEncoding = acceptEncoding.SafeToString().ToLower(); if (acceptEncoding.Contains("gzip")) { response.Filter = new System.IO.Compression.GZipStream(response.Filter, System.IO.Compression.CompressionMode.Compress); response.Headers.Remove(HttpConstants.HttpHeader.ContentEncoding); response.AppendHeader(HttpConstants.HttpHeader.ContentEncoding, "gzip"); } else if (acceptEncoding.Contains("deflate")) { response.Filter = new System.IO.Compression.DeflateStream(response.Filter, System.IO.Compression.CompressionMode.Compress); response.Headers.Remove(HttpConstants.HttpHeader.ContentEncoding); response.AppendHeader(HttpConstants.HttpHeader.ContentEncoding, "deflate"); } } response.Write(objectToReturn.ToJson(true, JsonConverters)); } response.Headers.Add(HttpConstants.HttpHeader.SERVEREXITTIME, DateTime.UtcNow.ToFullDateTimeTzString()); response.Flush(); } }
/// <summary> /// Packages the response. <c>Flush()</c> would be called in this method. /// </summary> /// <param name="response">The response.</param> /// <param name="data">The data.</param> /// <param name="ex">The ex.</param> /// <param name="acceptEncoding">Name of the compression.</param> /// <param name="noBody">if set to <c>true</c> [no body].</param> /// <param name="settings">The settings.</param> /// <returns>System.Object.</returns> public static void PackageResponse(HttpResponse response, object data, BaseException ex = null, string acceptEncoding = null, bool noBody = false, RestApiSettings settings = null) { if (response != null) { PackageResponse(new HttpResponseWrapper(response), data, ex, acceptEncoding, noBody, settings); } }
/// <summary> /// Adds the setting. /// </summary> /// <param name="name">The name.</param> /// <param name="setting">The setting.</param> /// <param name="overrideIfExists">The override if exists.</param> /// <returns>System.Boolean.</returns> public static bool AddSetting(string name, RestApiSettings setting, bool overrideIfExists = false) { if (setting != null) { return settingsContainer.Merge(name.SafeToString(), setting, overrideIfExists); } return false; }
/// <summary> /// Packages the response. <c>Flush()</c> would be called in this method. /// </summary> /// <param name="response">The response.</param> /// <param name="data">The data.</param> /// <param name="ex">The ex.</param> /// <param name="acceptEncoding">The accept encoding.</param> /// <param name="noBody">if set to <c>true</c> [no body].</param> /// <param name="contentType">Type of the content.</param> /// <param name="settings">The settings.</param> public static void PackageResponse(HttpResponseBase response, object data, BaseException ex = null, string acceptEncoding = null, bool noBody = false, string contentType = null, RestApiSettings settings = null) { if (response != null) { if (settings == null) { settings = defaultRestApiSettings; } var objectToReturn = ex != null ? (settings.OmitExceptionDetail ? ex.ToSimpleExceptionInfo() : ex.ToExceptionInfo()) : data; response.Headers.Add(HttpConstants.HttpHeader.SERVERNAME, EnvironmentCore.ServerName); response.Headers.AddIfNotNullOrEmpty(HttpConstants.HttpHeader.TRACEID, ApiTraceContext.TraceId); response.StatusCode = (int)(ex == null ? (noBody ? HttpStatusCode.NoContent : HttpStatusCode.OK) : ex.Code.ToHttpStatusCode()); if (!noBody) { response.ContentType = contentType.SafeToString(HttpConstants.ContentType.Json); if (settings.EnableContentCompression) { acceptEncoding = acceptEncoding.SafeToString().ToLower(); if (acceptEncoding.Contains(HttpConstants.HttpValues.GZip)) { response.Filter = new System.IO.Compression.GZipStream(response.Filter, System.IO.Compression.CompressionMode.Compress); response.Headers.Remove(HttpConstants.HttpHeader.ContentEncoding); response.AppendHeader(HttpConstants.HttpHeader.ContentEncoding, HttpConstants.HttpValues.GZip); } else if (acceptEncoding.Contains("deflate")) { response.Filter = new System.IO.Compression.DeflateStream(response.Filter, System.IO.Compression.CompressionMode.Compress); response.Headers.Remove(HttpConstants.HttpHeader.ContentEncoding); response.AppendHeader(HttpConstants.HttpHeader.ContentEncoding, "deflate"); } } response.Write(objectToReturn.ToJson(true, JsonConverters)); } response.Headers.Add(HttpConstants.HttpHeader.SERVEREXITTIME, DateTime.UtcNow.ToFullDateTimeTzString()); } }
/// <summary> /// Adds the handler (instance and settings) into route. /// </summary> /// <param name="instance">The instance.</param> /// <param name="settings">The settings.</param> public void Add(object instance, RestApiSettings settings = null) { InitializeRoute(instance, settings); }
/// <summary> /// Initializes a new instance of the <see cref="RestApiRouter" /> class. /// </summary> /// <param name="defaultApiSettings">The default API settings.</param> /// <param name="allowOptions">if set to <c>true</c> [allow options].</param> public RestApiRouter(RestApiSettings defaultApiSettings, bool allowOptions = false) : base(defaultApiSettings, allowOptions) { }
/// <summary> /// Initializes the routes. /// </summary> /// <param name="instance">The instance.</param> /// <param name="settings">The settings.</param> /// <exception cref="DataConflictException">Route</exception> protected void InitializeRoute(object instance, RestApiSettings settings = null) { lock (routeOperationLocker) { if (instance != null) { var typeName = instance.GetType().FullName; if (!initializedTypes.Contains(typeName)) { #region Initialize routes var doneInterfaceTypes = new List<string>(); foreach (var interfaceType in instance.GetType().GetInterfaces()) { InitializeApiType(doneInterfaceTypes, routes, interfaceType, instance, settings); } #endregion initializedTypes.Add(typeName); } } } }
/// <summary> /// Initializes the type of the API. /// </summary> /// <param name="doneInterfaceTypes">The done interface types.</param> /// <param name="routes">The routes.</param> /// <param name="interfaceType">Type of the interface.</param> /// <param name="instance">The instance.</param> /// <param name="settings">The settings.</param> /// <param name="parentApiContractAttribute">The parent API class attribute.</param> /// <param name="parentApiModuleAttribute">The parent API module attribute.</param> protected void InitializeApiType(List<string> doneInterfaceTypes, Dictionary<string, RuntimeRoute> routes, Type interfaceType, object instance, RestApiSettings settings = null, ApiContractAttribute parentApiContractAttribute = null, ApiModuleAttribute parentApiModuleAttribute = null) { if (routes != null && interfaceType != null && doneInterfaceTypes != null) { if (doneInterfaceTypes.Contains(interfaceType.FullName)) { return; } var ApiContract = parentApiContractAttribute ?? interfaceType.GetCustomAttribute<ApiContractAttribute>(true); var apiModule = parentApiModuleAttribute ?? interfaceType.GetCustomAttribute<ApiModuleAttribute>(true); var moduleName = apiModule?.ToString(); if (ApiContract != null && !string.IsNullOrWhiteSpace(ApiContract.Version)) { var apiContractName = ApiContract.Name.SafeToString(interfaceType.FullName); if (ApiContract.Version.SafeToLower().Equals(BuildInFeatureVersionKeyword)) { throw new InvalidObjectException("ApiContract.Version", reason: "<buildin> cannot be used as version due to it is used internally."); } foreach (var method in interfaceType.GetMethods()) { var apiOperationAttribute = method.GetCustomAttribute<ApiOperationAttribute>(true); var apiTransportAttribute = method.GetCustomAttribute<ApiTransportAttribute>(); #region Initialize based on ApiOperation if (apiOperationAttribute != null) { var permissions = new Dictionary<string, ApiPermission>(); var additionalHeaderKeys = new HashSet<string>(); var apiPermissionAttributes = method.GetCustomAttributes<ApiPermissionAttribute>(true); if (apiPermissionAttributes != null) { foreach (var one in apiPermissionAttributes) { permissions.Merge(one.PermissionIdentifier, one.Permission); } } var headerKeyAttributes = method.GetCustomAttributes<ApiHeaderAttribute>(true); if (headerKeyAttributes != null) { foreach (var one in headerKeyAttributes) { additionalHeaderKeys.Add(one.HeaderKey); } } var routeKey = GetRouteKey(ApiContract.Version, apiOperationAttribute.ResourceName, apiOperationAttribute.HttpMethod, apiOperationAttribute.Action); RuntimeRoute runtimeRoute = null; if (apiTransportAttribute != null) { runtimeRoute = new RuntimeRoute(apiTransportAttribute); } else { var tokenRequired = method.GetCustomAttribute<TokenRequiredAttribute>(true) ?? interfaceType.GetCustomAttribute<TokenRequiredAttribute>(true); runtimeRoute = new RuntimeRoute(method, interfaceType, instance, !string.IsNullOrWhiteSpace(apiOperationAttribute.Action), tokenRequired != null && tokenRequired.TokenRequired, moduleName, apiContractName, settings, permissions, additionalHeaderKeys.ToList()); } if (routes.ContainsKey(routeKey)) { throw new DataConflictException("Route", objectIdentity: routeKey, data: new { existed = routes[routeKey].SafeToString(), newMethod = method.GetFullName(), newInterface = interfaceType.FullName }); } routes.Add(routeKey, runtimeRoute); } #endregion } foreach (var one in interfaceType.GetInterfaces()) { InitializeApiType(doneInterfaceTypes, routes, one, instance, settings, ApiContract, apiModule); } } doneInterfaceTypes.Add(interfaceType.FullName); } }
/// <summary> /// Initializes the type of the API. /// </summary> /// <param name="doneInterfaceTypes">The done interface types.</param> /// <param name="routes">The routes.</param> /// <param name="interfaceType">Type of the interface.</param> /// <param name="instance">The instance.</param> /// <param name="settings">The settings.</param> /// <param name="parentApiContractAttribute">The parent API class attribute.</param> /// <param name="parentApiModuleAttribute">The parent API module attribute.</param> protected void InitializeApiType(List<string> doneInterfaceTypes, Dictionary<string, RuntimeRoute> routes, Type interfaceType, object instance, RestApiSettings settings = null, ApiContractAttribute parentApiContractAttribute = null, ApiModuleAttribute parentApiModuleAttribute = null) { if (routes != null && interfaceType != null && doneInterfaceTypes != null) { if (doneInterfaceTypes.Contains(interfaceType.FullName)) { return; } var apiContract = parentApiContractAttribute ?? interfaceType.GetCustomAttribute<ApiContractAttribute>(true); var apiModule = parentApiModuleAttribute ?? interfaceType.GetCustomAttribute<ApiModuleAttribute>(true); var moduleName = apiModule?.ToString(); if (apiContract != null && !string.IsNullOrWhiteSpace(apiContract.Version)) { if (apiContract.Version.SafeToLower().Equals(BuiltInFeatureVersionKeyword)) { throw ExceptionFactory.CreateInvalidObjectException("apiContract.Version", reason: "<builtin> cannot be used as version due to it is used internally."); } foreach (var method in interfaceType.GetMethods()) { var apiOperationAttribute = method.GetCustomAttribute<ApiOperationAttribute>(true); #region Initialize based on ApiOperation if (apiOperationAttribute != null) { var permissions = new Dictionary<string, ApiPermission>(); var additionalHeaderKeys = new HashSet<string>(); var apiPermissionAttributes = method.GetCustomAttributes<ApiPermissionAttribute>(true); if (apiPermissionAttributes != null) { foreach (var one in apiPermissionAttributes) { permissions.Merge(one.PermissionIdentifier, one.Permission); } } var headerKeyAttributes = method.GetCustomAttributes<ApiHeaderAttribute>(true); if (headerKeyAttributes != null) { foreach (var one in headerKeyAttributes) { additionalHeaderKeys.Add(one.HeaderKey); } } var routeKey = GetRouteKey(apiContract.Version, apiOperationAttribute.ResourceName, apiOperationAttribute.HttpMethod, apiOperationAttribute.Action); var tokenRequired = method.GetCustomAttribute<TokenRequiredAttribute>(true) ?? interfaceType.GetCustomAttribute<TokenRequiredAttribute>(true); var runtimeRoute = new RuntimeRoute(method, interfaceType, instance, !string.IsNullOrWhiteSpace(apiOperationAttribute.Action), tokenRequired != null && tokenRequired.TokenRequired, moduleName, settings, permissions, additionalHeaderKeys.ToList()); if (routes.ContainsKey(routeKey)) { throw new DataConflictException("Route", objectIdentity: routeKey, data: new { existed = routes[routeKey].SafeToString(), newMethod = method.GetFullName(), newInterface = interfaceType.FullName }); } routes.Add(routeKey, runtimeRoute); } #endregion } foreach (var one in interfaceType.GetInterfaces()) { InitializeApiType(doneInterfaceTypes, routes, one, instance, settings, apiContract, apiModule); } //Special NOTE: // Move this add action in scope of if apiContract is valid. // Reason: in complicated cases, when [A:Interface1] without ApiContract, but [Interface2: Interface] with defining ApiContract, and [B: A, Interface2], then correct contract definition might be missed. doneInterfaceTypes.Add(interfaceType.FullName); } } }
/// <summary> /// Initializes a new instance of the <see cref="SecuredApiRouter"/> class. /// </summary> /// <param name="defaultApiSettings">The default API settings.</param> public SecuredApiRouter(RestApiSettings defaultApiSettings) : base(defaultApiSettings, false) { }
/// <summary> /// Initializes a new instance of the <see cref="RestApiContextConsistenceAttribute"/> class. /// </summary> /// <param name="restApiSetting">The rest API settings.</param> public RestApiContextConsistenceAttribute(RestApiSettings restApiSetting) : base() { this.settings = restApiSetting; ApiTracking = restApiSetting?.ApiTracking; }