Ejemplo n.º 1
0
        /// <summary>
        /// Serialize the request for the operation
        /// </summary>
        public void DeserializeRequest(EndpointOperation operation, RestRequestMessage request, object[] parameters)
        {
            try
            {
                var         httpRequest       = RestOperationContext.Current.IncomingRequest;
                string      contentTypeHeader = httpRequest.Headers["Content-Type"];
                ContentType contentType       = null;
                if (!String.IsNullOrEmpty(contentTypeHeader))
                {
                    contentType = new ContentType(contentTypeHeader);
                }

                for (int pNumber = 0; pNumber < parameters.Length; pNumber++)
                {
                    var parm = operation.Description.InvokeMethod.GetParameters()[pNumber];

                    // TODO: Look for MessageFormatAttribute for override

                    // Simple parameter
                    if (parameters[pNumber] != null)
                    {
                        continue; // dispatcher already populated
                    }
                    else
                    {
                        switch (contentType.MediaType)
                        {
                        case "application/xml":
                            if (!this.m_serializers.TryGetValue(parm.ParameterType, out XmlSerializer serializer))
                            {
                                serializer = new XmlSerializer(parm.ParameterType);
                                this.m_serializers.TryAdd(parm.ParameterType, serializer);
                            }
                            var requestObject = serializer.Deserialize(request.Body);
                            parameters[pNumber] = requestObject;
                            break;

                        case "application/json":
                            using (var sr = new StreamReader(request.Body))
                            {
                                JsonSerializer jsz = new JsonSerializer()
                                {
                                    TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple,
                                    TypeNameHandling = TypeNameHandling.All
                                };
                                jsz.Converters.Add(new StringEnumConverter());
                                var dserType = parm.ParameterType;
                                parameters[pNumber] = jsz.Deserialize(sr, dserType);
                            }
                            break;

                        case "application/octet-stream":
                            parameters[pNumber] = request.Body;
                            break;

                        case "application/x-www-form-urlencoded":
                            NameValueCollection nvc = new NameValueCollection();
                            using (var sr = new StreamReader(request.Body))
                            {
                                var ptext = sr.ReadToEnd();
                                var parms = ptext.Split('&');
                                foreach (var p in parms)
                                {
                                    var parmData = p.Split('=');
                                    parmData[1] += new string('=', parmData.Length - 2);
                                    nvc.Add(WebUtility.UrlDecode(parmData[0]), WebUtility.UrlDecode(parmData[1]));
                                }
                            }
                            parameters[pNumber] = nvc;
                            break;

                        default:
                            throw new InvalidOperationException("Invalid request format");
                        }
                    }
                }
            }
            catch (Exception e)
            {
                this.m_traceSource.TraceEvent(TraceEventType.Error, e.HResult, e.ToString());
                throw;
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Creats a new operation dispatcher
        /// </summary>
        public OperationDispatcher(EndpointOperation endpointOperation)
        {
            this.m_endpointOperation = endpointOperation;
            var match        = this.m_templateParser.Match(endpointOperation.Description.UriTemplate);
            var regexBuilder = new StringBuilder("^");

            this.DispatchFormatter = new DefaultDispatchFormatter();

            Type[] parmTypes = endpointOperation.Description.InvokeMethod.GetParameters().Select(o => o.ParameterType).ToArray();
            m_regexGroupNames = new string[parmTypes.Length];
            int parmCount = 0;

            while (match.Success)
            {
                switch (match.Groups[1].Value[0])
                {
                case '{':     // parameter
                    if (parmTypes.Length < parmCount)
                    {
                        throw new InvalidOperationException($"REST method accepts {parmTypes.Length} parameters but route specifies more");
                    }
                    m_regexGroupNames[parmCount] = match.Groups[1].Value;
                    var ptype = parmTypes[parmCount++];
                    switch (ptype.Name.ToLowerInvariant())
                    {
                    case "string":
                        if (match.Groups[1].Value.StartsWith("{*"))         // match all
                        {
                            m_regexGroupNames[parmCount - 1] = "{" + m_regexGroupNames[parmCount - 1].Substring(2);
                            regexBuilder.Append(@"(.*?)");
                        }
                        else
                        {
                            regexBuilder.Append(@"([A-Za-z0-9_\-%\.\~\\]*?)");
                        }
                        break;

                    case "int32":
                        regexBuilder.Append("(\\d*?)");
                        break;

                    case "guid":
                        regexBuilder.Append("([a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12})");
                        break;

                    default:
                        throw new InvalidOperationException($"Cannot use parameter type {ptype.Name} on route");
                    }
                    break;

                case '*':     // anything
                    regexBuilder.Append(".*");
                    break;

                default:
                    regexBuilder.Append(match.Groups[1].Value.Replace("$", "\\$"));
                    break;
                }

                match = match.NextMatch();
            }
            if (regexBuilder[1] == '/') // starting / is optional
            {
                regexBuilder.Insert(2, "?");
            }
            if (regexBuilder[regexBuilder.Length - 1] == '/') // ending with /? is optional
            {
                regexBuilder.Append("?");
            }

            regexBuilder.Append("$");

            this.m_regexGroupNames = this.m_regexGroupNames.Where(o => o != null).ToArray();
            this.m_traceSource.TraceEvent(TraceEventType.Verbose, 0, "Operation {0} will be bound to {1}", endpointOperation.Description.InvokeMethod, regexBuilder);
            this.m_dispatchRegex = new Regex(regexBuilder.ToString(), RegexOptions.IgnoreCase);
        }