Пример #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Proxy"/> class.
        /// </summary>
        /// <param name="proxyType">The <see cref="Type"/> of the remote object for which to create a proxy.</param>
        /// <param name="configuration">Proxy configuration information.</param>
        internal Proxy(Type proxyType, ProxyConfiguration configuration)
            : base(proxyType)
        {
            this.Configuration = configuration;

            this.Context = new ProxyContext();

            this.m_jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings()
            {
                DateFormatHandling    = DateFormatHandling.IsoDateFormat,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                NullValueHandling     = NullValueHandling.Include,
                ConstructorHandling   = ConstructorHandling.AllowNonPublicDefaultConstructor,
                ContractResolver      = new ProxyContractResolver()
            });

            ResourceAttribute resourceUrlAttribute = proxyType.GetCustomAttribute <ResourceAttribute>();

            if (null == this.Configuration.Relative)
            {
                if (null != resourceUrlAttribute)
                {
                    this.Configuration.Relative = resourceUrlAttribute.Relative;

                    if (this.Configuration.Relative.Length != 0 && !this.Configuration.Relative.EndsWith("/", StringComparison.OrdinalIgnoreCase))
                    {
                        this.Configuration.Relative += "/";
                    }
                }
                else
                {
                    var invariantCulture = System.Globalization.CultureInfo.InvariantCulture;

                    this.Configuration.Relative = string.Format(invariantCulture, "api/{0}/", proxyType.Name.ToLower(invariantCulture));
                }
            }

            if (!this.Configuration.Root.EndsWith("/", StringComparison.OrdinalIgnoreCase))
            {
                this.Configuration.Root += "/";
            }
        }
Пример #2
0
        public override IMessage Invoke(IMessage msg)
        {
            IMethodCallMessage methodCall = msg as IMethodCallMessage;
            var invariantCulture          = System.Globalization.CultureInfo.InvariantCulture;

            if (null != methodCall)
            {
                try
                {
                    HttpMethod          httpMethod          = HttpMethod.Get;
                    HttpMethodAttribute httpMethodAttribute = methodCall.MethodBase.GetCustomAttribute <HttpMethodAttribute>(true);

                    if (null != httpMethodAttribute)
                    {
                        httpMethod = httpMethodAttribute.HttpMethod;
                    }

                    ResourceAttribute resourceUrlAttribute = methodCall.MethodBase.GetCustomAttribute <ResourceAttribute>(true);

                    string actionUrl = string.Empty;

                    if (null != resourceUrlAttribute)
                    {
                        actionUrl = resourceUrlAttribute.Relative;
                    }

                    Type expectedReturn = ((MethodInfo)methodCall.MethodBase).ReturnType;

                    object   retVal  = null;
                    object[] outArgs = null;

                    Dictionary <string, object> toSerialize   = new Dictionary <string, object>();
                    Dictionary <string, string> toQueryString = new Dictionary <string, string>();

                    // Determines which arguments should be used in the querystring parameters, and which arguments will be serialized and posted.
                    for (int argIndex = 0, argCount = methodCall.InArgCount; argIndex < argCount; argIndex++)
                    {
                        object value = methodCall.GetInArg(argIndex);

                        if (null == value || value.GetType().IsPrimitiveOrBasicStruct())
                        {
                            if (null != value && value is DateTime)
                            {
                                value = ((DateTime)value).ToLocalTime();

                                StringBuilder sb = new StringBuilder();
                                using (TextWriter writer = new StringWriter(sb, invariantCulture))
                                {
                                    this.m_jsonSerializer.Serialize(writer, value);
                                }

                                value = sb.ToString();
                                value = ((string)value).Substring(1, ((string)value).Length - 2);

                                toQueryString.Add(methodCall.GetInArgName(argIndex), (value != null) ? value.ToString() : string.Empty);
                            }
                            else
                            {
                                toQueryString.Add(methodCall.GetInArgName(argIndex), (value != null) ? HttpUtility.UrlEncode(value.ToString()) : string.Empty);
                            }
                        }
                        else
                        {
                            toSerialize.Add(methodCall.GetInArgName(argIndex), value);
                        }
                    }

                    {
                        // Prepare the post content.
                        byte[] postData = null;

                        string responseData;

                        if (toSerialize.Count > 0)
                        {
                            StringBuilder sb = new StringBuilder();
                            using (TextWriter writer = new StringWriter(sb, invariantCulture))
                            {
                                if (toSerialize.Count == 1)
                                {
                                    this.m_jsonSerializer.Serialize(writer, toSerialize.Values.First());
                                }
                                else
                                {
                                    this.m_jsonSerializer.Serialize(writer, toSerialize);
                                }
                            }

                            postData = Encoding.UTF8.GetBytes(sb.ToString());
                        }

                        if ((postData == null || postData.Length == 0) && httpMethod != HttpMethod.Get)
                        {
                            postData = Encoding.UTF8.GetBytes("{}");
                        }

                        // Assemble the querystring.
                        object[] urlParameters = null;

                        if (null != resourceUrlAttribute && resourceUrlAttribute.ParameterNames.Count() > 0)
                        {
                            urlParameters = new object[resourceUrlAttribute.ParameterNames.Count()];

                            for (int i = 0, total = resourceUrlAttribute.ParameterNames.Count(); i < total; i++)
                            {
                                string parameterName = resourceUrlAttribute.ParameterNames[i];

                                if (toQueryString.ContainsKey(parameterName))
                                {
                                    urlParameters[i] = toQueryString[parameterName];
                                    toQueryString.Remove(parameterName);
                                }
                                else if (toSerialize.ContainsKey(parameterName))
                                {
                                    urlParameters[i] = toSerialize[parameterName];
                                    toSerialize.Remove(parameterName);
                                }
                            }
                        }

                        var queryString = string.Empty;

                        if (toQueryString.Count > 0)
                        {
                            queryString = "?" + string.Join("&", (from kvp in toQueryString select kvp.Key + "=" + kvp.Value).ToArray());
                        }

                        // Determine the final url
                        if (null != urlParameters)
                        {
                            actionUrl = string.Format(invariantCulture, actionUrl, urlParameters);
                        }

                        string serviceUrl = this.Configuration.Root + this.Configuration.Relative + actionUrl + queryString;

                        // Create the request context
                        RequestContext context = this.Context.CreateRequestContext();

                        context.RequestUrl = new Uri(serviceUrl);

                        // Create and configure the HTTP request
                        HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(context.RequestUrl);
                        {
                            webRequest.Method  = httpMethod.ToString().ToUpper();
                            webRequest.Timeout = this.Configuration.RequestTimeout ?? (5 * 60 * 1000);

                            if (null != this.Configuration.RequestHeaders)
                            {
                                foreach (var kvp in this.Configuration.RequestHeaders)
                                {
                                    webRequest.Headers[kvp.Key] = kvp.Value;
                                }
                            }

                            if (null != postData && postData.Length > 0)
                            {
                                webRequest.ContentLength = postData.Length;
                                webRequest.ContentType   = "application/json; charset=UTF-8";

                                Stream postStream = webRequest.GetRequestStream();
                                postStream.Write(postData, 0, postData.Length);
                                postStream.Close();
                            }
                        }

                        HttpWebResponse response = null;

                        {
                            Stopwatch timer = Stopwatch.StartNew();

                            try
                            {
                                // Add a HTTP header with a random number to help tracking the request here and on the remote server
                                int randomNumber = new Random().Next(int.MaxValue);

                                webRequest.Headers["X-SP-Unique-Identifier"] = randomNumber.ToString(invariantCulture);

                                // Send the request
                                response = (HttpWebResponse)webRequest.GetResponse();
                            }
                            catch (WebException ex)
                            {
                                string errorContent = null;

                                if (ex.Response != null)
                                {
                                    context.ResponseStatus = (int)((HttpWebResponse)ex.Response).StatusCode;

                                    if (ex.Response.ContentLength != 0)
                                    {
                                        using (var stream = ex.Response.GetResponseStream())
                                        {
                                            if (null != stream)
                                            {
                                                using (var reader = new StreamReader(stream))
                                                {
                                                    errorContent = reader.ReadToEnd();

                                                    context.ResponseSize = errorContent.Length;
                                                }
                                            }
                                        }

                                        string errorResult = null;

                                        if (null != errorContent)
                                        {
                                            using (StringReader r = new StringReader(errorContent))
                                            {
                                                errorResult = r.ReadToEnd();
                                            }
                                        }

                                        if (!string.IsNullOrWhiteSpace(errorResult))
                                        {
                                            context.ResponseContent = errorResult;

                                            throw new ProxyException(errorResult, (HttpWebResponse)ex.Response);
                                        }
                                    }
                                }

                                throw new ProxyException(string.Format(invariantCulture, "Exception caught while performing a {0} request to url '{1}'. {2}: {3}", httpMethod.ToString(), serviceUrl, ex.GetType().Name, ex.Message), ex);
                            }
                            finally
                            {
                                var elapsedMilliseconds = timer.ElapsedMilliseconds;

                                timer.Stop();

                                context.RequestElapsedMilliseconds = elapsedMilliseconds;
                                context.RequestElapsedTime         = new TimeSpan(0, 0, 0, 0, (int)elapsedMilliseconds);
                            }

                            context.ResponseHeaders.Clear();

                            // Add the response information to the context
                            for (int index = 0, total = response.Headers.Count; index < total; index++)
                            {
                                context.ResponseHeaders[response.Headers.GetKey(index)] = response.Headers.Get(index);
                            }

                            context.ResponseStatus = (int)response.StatusCode;

                            if ((int)response.StatusCode >= 400)
                            {
                                throw new ProxyException("Invalid HTTP status code.", response);
                            }

                            // Read the response contents
                            Stream responseStream = response.GetResponseStream();

                            using (StreamReader responseReader = new StreamReader(responseStream))
                            {
                                responseData = responseReader.ReadToEnd();

                                // note: context.ResponseSize should be in bytes, not string length
                                // ContentLength should be length reported in the Content-Length header (number of octets)
                                context.ResponseSize = response.ContentLength;

                                context.ResponseContent = responseData;

                                responseReader.Close();
                            }

                            responseStream.Close();
                            response.Close();
                        }

                        // Attempt to deserialize the response contents
                        if (context.ResponseHeaders.ContainsKey("Content-Type"))
                        {
                            string contentType = (context.ResponseHeaders["Content-Type"] ?? string.Empty).Split(';').FirstOrDefault(h => !h.Trim().StartsWith("charset", StringComparison.OrdinalIgnoreCase));

                            string temp = contentType.Split('/').Last();

                            if (temp.EndsWith("json", StringComparison.OrdinalIgnoreCase) || temp.EndsWith("javascript", StringComparison.OrdinalIgnoreCase))
                            {
                                using (StringReader r = new StringReader(responseData))
                                {
                                    using (JsonReader r2 = new JsonTextReader(r))
                                    {
                                        r2.DateTimeZoneHandling = DateTimeZoneHandling.Utc;

                                        if (expectedReturn != typeof(void))
                                        {
                                            retVal = this.m_jsonSerializer.Deserialize(r2, expectedReturn);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                throw new ProxyException("Unknown response content type: " + contentType, response);
                            }
                        }
                    }

                    int outArgsCount = null != outArgs ? outArgs.Length : 0;

                    IMethodReturnMessage callResult = new ReturnMessage(retVal, outArgs, outArgsCount, methodCall.LogicalCallContext, methodCall);

                    return(callResult);
                }
                catch (Exception e)
                {
                    return(new ReturnMessage(e, methodCall));
                }
            }
            else
            {
                throw new NotSupportedException();
            }
        }