/// <summary> /// Called by the ASP.NET MVC framework before the action method executes. /// </summary> /// <param name="filterContext">The filter context.</param> /// <exception cref="BeetleException">BeetleActionFilterAttribute should only be applied to Queryable actions.</exception> public override void OnActionExecuting(ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); var controller = filterContext.Controller; var action = filterContext.ActionDescriptor; var reflectedAction = action as ReflectedActionDescriptor; var actionMethod = reflectedAction != null ? reflectedAction.MethodInfo : controller.GetType().GetMethod(action.ActionName); var service = controller as IBeetleService; if (_beetleConfig == null) _beetleConfig = service != null ? service.BeetleConfig : BeetleConfig.Instance; string queryString; NameValueCollection queryParams; object[] actionArgs; // handle request message GetParameters(filterContext, out queryString, out queryParams, out actionArgs); // execute the action method var contentValue = actionMethod.Invoke(controller, actionArgs); // get client hash // process the request and return the result var actionContext = new ActionContext(action.ActionName, contentValue, queryString, queryParams, MaxResultCount, CheckRequestHashNullable); var processResult = ProcessRequest(contentValue, actionContext, service); // handle response message filterContext.Result = HandleResponse(filterContext, processResult); }
/// <summary> /// Initializes a new instance of the <see cref="BeetleActionFilterAttribute" /> class. /// </summary> /// <param name="configType">Type of the config.</param> /// <exception cref="System.ArgumentException">Cannot create config instance.</exception> public BeetleActionFilterAttribute(Type configType = null) { if (configType != null) { _beetleConfig = Activator.CreateInstance(configType) as BeetleConfig; if (_beetleConfig == null) throw new ArgumentException(Resources.CannotCreateConfigInstance); } }
/// <summary> /// Handles the request. /// </summary> /// <param name="queryString">The query string.</param> /// <param name="queryParams">The query parameters.</param> /// <param name="actionArgs">The action arguments.</param> /// <param name="config">The beetle configuration.</param> /// <param name="request">The request.</param> /// <param name="actionParameters">The action parameters.</param> /// <param name="parameters">The parameters.</param> /// <exception cref="BeetleException">Action must have only one parameter (JsonObject, object or dynamic) to be able called with POST.</exception> internal static void GetParameters(out string queryString, out NameValueCollection queryParams, out object[] actionArgs, BeetleConfig config = null, HttpRequest request = null, ParameterDescriptor[] actionParameters = null, IDictionary<string, object> parameters = null) { if (config == null) config = BeetleConfig.Instance; if (request == null) request = HttpContext.Current.Request; if (request.HttpMethod == "POST") { // supported methods can only have one parameter // (MVC behavior for beetle must be same as WebApi and WebApi cannot have more than one parameters for POST) if (actionParameters == null || actionParameters.Length <= 1) { var hasPrm = actionParameters != null && actionParameters.Length == 1; object actionArg = null; // read post data request.InputStream.Position = 0; queryString = new StreamReader(request.InputStream).ReadToEnd(); if (request.ContentType.Contains("application/json")) { if (hasPrm) actionArg = JsonConvert.DeserializeObject(queryString, config.JsonSerializerSettings) as JObject; // but now there is no query string parameters, we must populate them manually for beetle queries // otherwise beetle cannot use query parameters when using post method var d = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(queryString); queryParams = new NameValueCollection(); foreach (var i in d) queryParams.Add(i.Key, i.Value == null ? string.Empty : i.Value.ToString()); } else { var prms = request.Params; queryParams = prms; var d = prms.AllKeys.ToDictionary(k => k, k => prms[k]); if (hasPrm) { var jsonStr = _javaScriptSerializer.Value.Serialize(d); actionArg = JsonConvert.DeserializeObject(jsonStr, config.JsonSerializerSettings); } } actionArgs = hasPrm ? new[] { actionArg } : new object[0]; } else { queryString = string.Empty; queryParams = null; actionArgs = null; } } else { queryString = request.Url.Query; if (queryString.StartsWith("?")) queryString = queryString.Substring(1); queryString = queryString.Replace(":", "%3A"); queryParams = request.QueryString; if (actionParameters != null && parameters != null) { actionArgs = actionParameters .Select(pd => parameters[pd.ParameterName]) .ToArray(); } else actionArgs = null; } }
/// <summary> /// Called when [action executed]. /// </summary> /// <param name="actionExecutedContext">The action executed context.</param> public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { if (actionExecutedContext.Exception != null || !actionExecutedContext.Response.IsSuccessStatusCode) return; var request = actionExecutedContext.Request; var response = actionExecutedContext.Response; var controller = actionExecutedContext.ActionContext.ControllerContext.Controller; var action = actionExecutedContext.ActionContext.ActionDescriptor.ActionName; var service = controller as IBeetleService; // get query parameters string queryString; var queryParams = GetParameters(actionExecutedContext, out queryString); object contentValue; if (!response.TryGetContentValue(out contentValue)) return; var actionContext = new ActionContext(action, contentValue, queryString, queryParams, MaxResultCount, CheckRequestHashNullable); request.Properties["BeetleService"] = service; request.Properties["BeetleActionContext"] = actionContext; if (_beetleConfig == null) _beetleConfig = service != null ? service.BeetleConfig : BeetleConfig.Instance; // call base and let WebApi process the request base.OnActionExecuted(actionExecutedContext); // get the processed query from content if (!response.TryGetContentValue(out contentValue)) return; var queryable = contentValue as IQueryable; // apply OData parameters if (queryable != null) contentValue = FixODataQuery(queryable, request, service); // process the request and return the result var processResult = ProcessRequest(contentValue, actionContext, request, service); // handle response message response.Content = HandleResponse(actionExecutedContext, processResult); }
/// <summary> /// Initializes a new instance of the <see cref="BeetleActionFilterAttribute"/> class. /// </summary> /// <param name="config">The configuration.</param> public BeetleActionFilterAttribute(BeetleConfig config) { _beetleConfig = config; }
public BeetleQueryableAttribute(BeetleConfig config) : this() { _beetleConfig = config; }
/// <summary> /// Handles the response. /// </summary> /// <param name="processResult">The process result.</param> /// <param name="config">The configuration.</param> /// <param name="response">The response.</param> /// <returns></returns> internal static ObjectContent HandleResponse(ProcessResult processResult, BeetleConfig config = null, HttpResponse response = null) { if (config == null) config = BeetleConfig.Instance; if (response == null) response = HttpContext.Current.Response; var type = processResult.Result == null ? typeof(object) : processResult.Result.GetType(); var retVal = new ObjectContent(type, processResult.Result, config.MediaTypeFormatter); // set InlineCount header info if exists object inlineCount = processResult.InlineCount; if (inlineCount != null && response.Headers["X-InlineCount"] == null) response.Headers["X-InlineCount"] = inlineCount.ToString(); if (processResult.UserData != null && response.Headers["X-UserData"] == null) { var userDataStr = JsonConvert.SerializeObject(processResult.UserData, config.JsonSerializerSettings); response.Headers["X-UserData"] = userDataStr; } return retVal; }
/// <summary> /// Handles the response. /// </summary> /// <param name="processResult">The process result.</param> /// <param name="config">The configuration.</param> /// <param name="response">The response.</param> /// <returns></returns> internal static ActionResult HandleResponse(ProcessResult processResult, BeetleConfig config = null, HttpResponse response = null) { var result = processResult.Result; if (config == null) config = BeetleConfig.Instance; if (response == null) response = HttpContext.Current.Response; // set InlineCount header info if exists object inlineCount = processResult.InlineCount; if (inlineCount != null && response.Headers["X-InlineCount"] == null) response.Headers.Add("X-InlineCount", inlineCount.ToString()); if (processResult.UserData != null && response.Headers["X-UserData"] == null) { var userDataStr = JsonConvert.SerializeObject(processResult.UserData, config.JsonSerializerSettings); response.Headers.Add("X-UserData", userDataStr); } var actionResult = result as ActionResult; if (actionResult != null) return actionResult; // write the result to response content return new BeetleJsonResult(config, processResult) { Data = result, ContentEncoding = response.HeaderEncoding, ContentType = "application/json", JsonRequestBehavior = JsonRequestBehavior.AllowGet }; }