public object BindPrimitive(Request request, string parameterName, Type parameterType) { //TODO: what if there are multiple values here? string stringValue = null; if (request.RouteTokens.ContainsKey(parameterName)) { stringValue = request.RouteTokens[parameterName]; } else if (request.QueryString.ContainsKey(parameterName)) { stringValue = request.QueryString[parameterName][0]; } if (parameterType == typeof(int)) { int x = 0; var parsed = null != stringValue && int.TryParse(stringValue, out x); if(parsed) { return x; } //TODO: indicate this to the developer //I don't like returning 4xx here without calling the action, because it prevents further validations return 0; } //TODO: tons of types, I would like to think of a clever way to not have to handcode all of them return stringValue; }
public void RequestBindsToRequest() { var binder = new RequestBinder(); Assert.True(binder.SupportsType(typeof(Request))); var request = new Request(); Assert.Equal(request, binder.Bind(request, "blah", typeof(Request))); }
public void BodyGetsDeserializedAsJson() { var binder = new DefaultBinder(); var request = new Request { RequestBody = GenerateStreamFromString("{ \"name\": \"Fred\", \"isBig\": true }") }; var boundBird = binder.Bind(request, "bird", typeof(Bird)) as Bird; Assert.NotNull(boundBird); Assert.True(boundBird.IsBig); Assert.Equal("Fred", boundBird.Name); }
private object BindParameter(ParameterExpression parameter, Request request, List<ParameterBinder> parameterBinders) { var binder = parameterBinders.FirstOrDefault(b => b.SupportsType(parameter.Type)); if (null == binder) { //TODO: figure out how to get this error to the developer return null; } return binder.Bind(request, parameter.Name, parameter.Type); }
public object HandleRequest(Request request, List<ParameterBinder> parameterBinders) { //TODO: handle parameter not available //TODO: should repeating the key be valid for collection types? //var callValues = _parameters.Select(p => Convert.ChangeType(queryString[p.Name][0], p.ParameterType)).ToArray(); var callValues = _parameters.Select(p => BindParameter(p, request, parameterBinders)).ToArray(); // var stringValue = queryString[_parameterName][0]; // //TODO: let users register converts // object castValue = Convert.ChangeType(stringValue, _parameterType); return _handler.DynamicInvoke(callValues); }
public void RouteTokensBind() { var binder = new DefaultBinder(); Assert.True(binder.SupportsType(typeof(int))); Assert.True(binder.SupportsType(typeof(string))); var routeTokens = new Dictionary<string, string>(); routeTokens["myInt"] = "2"; routeTokens["myString"] = "turquoise"; var request = new Request{ RouteTokens = routeTokens, QueryString = new Dictionary<string, string[]>() }; Assert.Equal(2, binder.Bind(request, "myInt", typeof(int))); Assert.Equal("turquoise", binder.Bind(request, "myString", typeof(string))); }
public void QueryStringBinds() { var binder = new DefaultBinder(); Assert.True(binder.SupportsType(typeof(int))); Assert.True(binder.SupportsType(typeof(string))); var queryString = new Dictionary<string, string[]>(); queryString["myInt"] = new []{"2"}; queryString["myString"] = new []{"turquoise"}; var request = new Request{ QueryString = queryString, RouteTokens = new Dictionary<string, string>() }; Assert.Equal(2, binder.Bind(request, "myInt", typeof(int))); Assert.Equal("turquoise", binder.Bind(request, "myString", typeof(string))); }
public void RouteTokensHideQueryString() { //I don't know if this is the behavior I want, but since it's what happens now changing it should fail a test var binder = new DefaultBinder(); Assert.True(binder.SupportsType(typeof(int))); Assert.True(binder.SupportsType(typeof(string))); var queryString = new Dictionary<string, string[]>(); queryString["myInt"] = new []{"not 2"}; queryString["myString"] = new []{"not turquoise"}; var routeTokens = new Dictionary<string, string>(); routeTokens["myInt"] = "2"; routeTokens["myString"] = "turquoise"; var request = new Request{ RouteTokens = routeTokens, QueryString = queryString }; Assert.Equal(2, binder.Bind(request, "myInt", typeof(int))); Assert.Equal("turquoise", binder.Bind(request, "myString", typeof(string))); }
//TODO: consider access level - this is primarily public for testing public Task HandleRequest(string method, string path, string queryString, IDictionary<string, string[]> requestHeaders, Stream requestBody, IDictionary<string, string[]> responseHeaders, Stream responseStream, Action<int> setStatusCode) { var parsedQueryString = ParseQueryString(queryString); var request = new Request { QueryString = parsedQueryString, RequestHeaders = requestHeaders, RequestBody = requestBody, RouteTokens = new Dictionary<string, string>()}; var handler = _router.ResolveRoute(method, path, request.RouteTokens); if (null != handler) { //TODO: don't assume the return is a string var result = (handler.HandleRequest(request, _binders) ?? "").ToString(); byte[] responseBytes = Encoding.UTF8.GetBytes(result); responseHeaders["Content-Length"] = new string[] { responseBytes.Length.ToString(CultureInfo.InvariantCulture) }; responseHeaders["Content-Type"] = new string[] { "text/plain; charset=utf-8" }; return responseStream.WriteAsync(responseBytes, 0, responseBytes.Length); } else { setStatusCode(404); var text = path + " not found"; byte[] responseBytes = Encoding.UTF8.GetBytes(text); responseHeaders["Content-Length"] = new string[] { responseBytes.Length.ToString(CultureInfo.InvariantCulture) }; responseHeaders["Content-Type"] = new string[] { "text/plain; charset=utf-8" }; return responseStream.WriteAsync(responseBytes, 0, responseBytes.Length); } }
public override object Bind(Request request, string parameterName, Type parameterType) { if (_primitiveTypes.Contains(parameterType)) { return BindPrimitive(request, parameterName, parameterType); } // TODO: content negotiation, assume JSON for this pass var requestBody = request.RequestBody; if (null == requestBody) { return null; } using (var streamReader = new StreamReader(requestBody)) { using (var jsonReader = new JsonTextReader(streamReader)) { return _serializer.Deserialize(jsonReader, parameterType); } } }
public override object Bind(Request request, string parameterName, Type parameterType) { return request; }
public abstract object Bind(Request request, string parameterName, Type parameterType);