2019-07-19 15:01:34 +08:00
|
|
|
|
using LeanCloud.Storage.Internal;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Net;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace LeanCloud
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// AVClient contains static functions that handle global
|
|
|
|
|
/// configuration for the LeanCloud library.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static partial class AVClient
|
|
|
|
|
{
|
|
|
|
|
public static readonly string[] DateFormatStrings = {
|
|
|
|
|
// Official ISO format
|
|
|
|
|
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'",
|
|
|
|
|
// It's possible that the string converter server-side may trim trailing zeroes,
|
|
|
|
|
// so these two formats cover ourselves from that.
|
|
|
|
|
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'ff'Z'",
|
|
|
|
|
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'f'Z'",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Represents the configuration of the LeanCloud SDK.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public struct Configuration
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 与 SDK 通讯的云端节点
|
|
|
|
|
/// </summary>
|
|
|
|
|
public enum AVRegion
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 默认值,LeanCloud 华北节点,同 Public_North_China
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Obsolete("please use Configuration.AVRegion.Public_North_China")]
|
|
|
|
|
Public_CN = 0,
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 默认值,华北公有云节点,同 Public_CN
|
|
|
|
|
/// </summary>
|
|
|
|
|
Public_North_China = 0,
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// LeanCloud 北美区公有云节点,同 Public_North_America
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Obsolete("please use Configuration.AVRegion.Public_North_America")]
|
|
|
|
|
Public_US = 1,
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// LeanCloud 北美区公有云节点,同 Public_US
|
|
|
|
|
/// </summary>
|
|
|
|
|
Public_North_America = 1,
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 华东公有云节点,同 Public_East_China
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Obsolete("please use Configuration.AVRegion.Public_East_China")]
|
|
|
|
|
Vendor_Tencent = 2,
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 华东公有云节点,同 Vendor_Tencent
|
|
|
|
|
/// </summary>
|
|
|
|
|
Public_East_China = 2,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// In the event that you would like to use the LeanCloud SDK
|
|
|
|
|
/// from a completely portable project, with no platform-specific library required,
|
|
|
|
|
/// to get full access to all of our features available on LeanCloud.com
|
|
|
|
|
/// (A/B testing, slow queries, etc.), you must set the values of this struct
|
|
|
|
|
/// to be appropriate for your platform.
|
|
|
|
|
///
|
|
|
|
|
/// Any values set here will overwrite those that are automatically configured by
|
|
|
|
|
/// any platform-specific migration library your app includes.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public struct VersionInformation
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The build number of your app.
|
|
|
|
|
/// </summary>
|
2019-08-28 17:00:03 +08:00
|
|
|
|
public string BuildVersion { get; set; }
|
2019-07-19 15:01:34 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The human friendly version number of your happ.
|
|
|
|
|
/// </summary>
|
2019-08-28 17:00:03 +08:00
|
|
|
|
public string DisplayVersion { get; set; }
|
2019-07-19 15:01:34 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The operating system version of the platform the SDK is operating in..
|
|
|
|
|
/// </summary>
|
2019-08-28 17:00:03 +08:00
|
|
|
|
public string OSVersion { get; set; }
|
2019-07-19 15:01:34 +08:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The LeanCloud application ID of your app.
|
|
|
|
|
/// </summary>
|
2019-07-23 14:35:07 +08:00
|
|
|
|
public string ApplicationId { get; set; }
|
2019-07-19 15:01:34 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// LeanCloud C# SDK 支持的服务节点,目前支持华北,华东和北美公有云节点和私有节点,以及专属节点
|
|
|
|
|
/// </summary>
|
|
|
|
|
public AVRegion Region { get; set; }
|
|
|
|
|
|
|
|
|
|
internal int RegionValue
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return (int)Region;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The LeanCloud application key for your app.
|
|
|
|
|
/// </summary>
|
2019-07-23 14:35:07 +08:00
|
|
|
|
public string ApplicationKey { get; set; }
|
2019-07-19 15:01:34 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The LeanCloud master key for your app.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <value>The master key.</value>
|
2019-07-23 14:35:07 +08:00
|
|
|
|
public string MasterKey { get; set; }
|
2019-07-19 15:01:34 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets additional HTTP headers to be sent with network requests from the SDK.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public IDictionary<string, string> AdditionalHTTPHeaders { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The version information of your application environment.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public VersionInformation VersionInfo { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-07-23 14:35:07 +08:00
|
|
|
|
/// 存储服务器地址
|
2019-07-19 15:01:34 +08:00
|
|
|
|
/// </summary>
|
2019-07-23 14:35:07 +08:00
|
|
|
|
/// <value>The API server.</value>
|
|
|
|
|
public string ApiServer { get; set; }
|
2019-07-19 15:01:34 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-07-23 14:35:07 +08:00
|
|
|
|
/// 云引擎服务器地址
|
2019-07-19 15:01:34 +08:00
|
|
|
|
/// </summary>
|
2019-07-23 14:35:07 +08:00
|
|
|
|
/// <value>The engine server uri.</value>
|
|
|
|
|
public string EngineServer { get; set; }
|
2019-07-19 15:01:34 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-07-23 14:35:07 +08:00
|
|
|
|
/// 即时通信服务器地址
|
2019-07-19 15:01:34 +08:00
|
|
|
|
/// </summary>
|
2019-07-23 14:35:07 +08:00
|
|
|
|
/// <value>The RTMR outer.</value>
|
|
|
|
|
public string RTMServer { get; set; }
|
2019-07-19 15:01:34 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-07-23 14:35:07 +08:00
|
|
|
|
/// 直连即时通信服务器地址
|
2019-07-19 15:01:34 +08:00
|
|
|
|
/// </summary>
|
2019-07-23 14:35:07 +08:00
|
|
|
|
/// <value>The realtime server.</value>
|
|
|
|
|
public string RealtimeServer { get; set; }
|
|
|
|
|
|
|
|
|
|
public Uri PushServer { get; set; }
|
|
|
|
|
|
2019-07-19 15:01:34 +08:00
|
|
|
|
public Uri StatsServer { get; set; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static readonly object mutex = new object();
|
|
|
|
|
|
|
|
|
|
static AVClient()
|
|
|
|
|
{
|
|
|
|
|
versionString = "net-portable-" + Version;
|
|
|
|
|
|
|
|
|
|
//AVModuleController.Instance.ScanForModules();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The current configuration that LeanCloud has been initialized with.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static Configuration CurrentConfiguration { get; internal set; }
|
|
|
|
|
|
|
|
|
|
internal static Version Version
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
var assemblyName = new AssemblyName(typeof(AVClient).GetTypeInfo().Assembly.FullName);
|
|
|
|
|
return assemblyName.Version;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static readonly string versionString;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当前 SDK 版本号
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static string VersionString
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return versionString;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Authenticates this client as belonging to your application. This must be
|
|
|
|
|
/// called before your application can use the LeanCloud library. The recommended
|
|
|
|
|
/// way is to put a call to <c>AVClient.Initialize</c> in your
|
|
|
|
|
/// Application startup.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="applicationId">The Application ID provided in the LeanCloud dashboard.
|
|
|
|
|
/// </param>
|
|
|
|
|
/// <param name="applicationKey">The .NET API Key provided in the LeanCloud dashboard.
|
|
|
|
|
/// </param>
|
|
|
|
|
public static void Initialize(string applicationId, string applicationKey)
|
|
|
|
|
{
|
|
|
|
|
Initialize(new Configuration
|
|
|
|
|
{
|
|
|
|
|
ApplicationId = applicationId,
|
|
|
|
|
ApplicationKey = applicationKey
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static Action<string> LogTracker { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 启动日志打印
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="trace"></param>
|
|
|
|
|
public static void HttpLog(Action<string> trace)
|
|
|
|
|
{
|
|
|
|
|
LogTracker = trace;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 打印 HTTP 访问日志
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="log"></param>
|
|
|
|
|
public static void PrintLog(string log)
|
|
|
|
|
{
|
|
|
|
|
if (AVClient.LogTracker != null)
|
|
|
|
|
{
|
|
|
|
|
AVClient.LogTracker(log);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool useProduction = true;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets a value indicating whether send the request to production server or staging server.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <value><c>true</c> if use production; otherwise, <c>false</c>.</value>
|
|
|
|
|
public static bool UseProduction
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return useProduction;
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
useProduction = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool useMasterKey = false;
|
|
|
|
|
public static bool UseMasterKey
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return useMasterKey;
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
useMasterKey = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Authenticates this client as belonging to your application. This must be
|
|
|
|
|
/// called before your application can use the LeanCloud library. The recommended
|
|
|
|
|
/// way is to put a call to <c>AVClient.Initialize</c> in your
|
|
|
|
|
/// Application startup.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="configuration">The configuration to initialize LeanCloud with.
|
|
|
|
|
/// </param>
|
|
|
|
|
public static void Initialize(Configuration configuration)
|
|
|
|
|
{
|
|
|
|
|
Config(configuration);
|
|
|
|
|
|
|
|
|
|
AVObject.RegisterSubclass<AVUser>();
|
|
|
|
|
AVObject.RegisterSubclass<AVRole>();
|
|
|
|
|
AVObject.RegisterSubclass<AVSession>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static void Config(Configuration configuration)
|
|
|
|
|
{
|
|
|
|
|
lock (mutex)
|
|
|
|
|
{
|
|
|
|
|
var nodeHash = configuration.ApplicationId.Split('-');
|
|
|
|
|
if (nodeHash.Length > 1)
|
|
|
|
|
{
|
|
|
|
|
if (nodeHash[1].Trim() == "9Nh9j0Va")
|
|
|
|
|
{
|
|
|
|
|
configuration.Region = Configuration.AVRegion.Public_East_China;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CurrentConfiguration = configuration;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static void Clear()
|
|
|
|
|
{
|
|
|
|
|
AVPlugins.Instance.AppRouterController.Clear();
|
|
|
|
|
AVPlugins.Instance.Reset();
|
|
|
|
|
AVUser.ClearInMemoryUser();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Switch app.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="configuration">Configuration.</param>
|
|
|
|
|
public static void Switch(Configuration configuration)
|
|
|
|
|
{
|
|
|
|
|
Clear();
|
|
|
|
|
Initialize(configuration);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void Switch(string applicationId, string applicationKey, Configuration.AVRegion region = Configuration.AVRegion.Public_North_China)
|
|
|
|
|
{
|
|
|
|
|
var configuration = new Configuration
|
|
|
|
|
{
|
|
|
|
|
ApplicationId = applicationId,
|
|
|
|
|
ApplicationKey = applicationKey,
|
|
|
|
|
Region = region
|
|
|
|
|
};
|
|
|
|
|
Switch(configuration);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static string BuildQueryString(IDictionary<string, object> parameters)
|
|
|
|
|
{
|
|
|
|
|
return string.Join("&", (from pair in parameters
|
|
|
|
|
let valueString = pair.Value as string
|
|
|
|
|
select string.Format("{0}={1}",
|
|
|
|
|
Uri.EscapeDataString(pair.Key),
|
|
|
|
|
Uri.EscapeDataString(string.IsNullOrEmpty(valueString) ?
|
|
|
|
|
Json.Encode(pair.Value) : valueString)))
|
|
|
|
|
.ToArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static IDictionary<string, string> DecodeQueryString(string queryString)
|
|
|
|
|
{
|
|
|
|
|
var dict = new Dictionary<string, string>();
|
|
|
|
|
foreach (var pair in queryString.Split('&'))
|
|
|
|
|
{
|
|
|
|
|
var parts = pair.Split(new char[] { '=' }, 2);
|
|
|
|
|
dict[parts[0]] = parts.Length == 2 ? Uri.UnescapeDataString(parts[1].Replace("+", " ")) : null;
|
|
|
|
|
}
|
|
|
|
|
return dict;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static IDictionary<string, object> DeserializeJsonString(string jsonData)
|
|
|
|
|
{
|
|
|
|
|
return Json.Parse(jsonData) as IDictionary<string, object>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static string SerializeJsonString(IDictionary<string, object> jsonData)
|
|
|
|
|
{
|
|
|
|
|
return Json.Encode(jsonData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Task<Tuple<HttpStatusCode, string>> HttpGetAsync(Uri uri)
|
|
|
|
|
{
|
|
|
|
|
return RequestAsync(uri, "GET", null, body: null, contentType: null, cancellationToken: CancellationToken.None);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Task<Tuple<HttpStatusCode, string>> RequestAsync(Uri uri, string method, IList<KeyValuePair<string, string>> headers, IDictionary<string, object> body, string contentType, CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
var dataStream = body != null ? new MemoryStream(Encoding.UTF8.GetBytes(Json.Encode(body))) : null;
|
|
|
|
|
return AVClient.RequestAsync(uri, method, headers, dataStream, contentType, cancellationToken);
|
|
|
|
|
//return AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, cancellationToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Task<Tuple<HttpStatusCode, string>> RequestAsync(Uri uri, string method, IList<KeyValuePair<string, string>> headers, Stream data, string contentType, CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
HttpRequest request = new HttpRequest()
|
|
|
|
|
{
|
|
|
|
|
Data = data != null ? data : null,
|
|
|
|
|
Headers = headers,
|
|
|
|
|
Method = method,
|
|
|
|
|
Uri = uri
|
|
|
|
|
};
|
|
|
|
|
return AVPlugins.Instance.HttpClient.ExecuteAsync(request, null, null, cancellationToken).OnSuccess(t =>
|
|
|
|
|
{
|
|
|
|
|
var response = t.Result;
|
|
|
|
|
var contentString = response.Item2;
|
|
|
|
|
int responseCode = (int)response.Item1;
|
|
|
|
|
var responseLog = responseCode + ";" + contentString;
|
|
|
|
|
PrintLog(responseLog);
|
|
|
|
|
return response;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static Tuple<HttpStatusCode, IDictionary<string, object>> ReponseResolve(Tuple<HttpStatusCode, string> response, CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
Tuple<HttpStatusCode, string> result = response;
|
|
|
|
|
HttpStatusCode code = result.Item1;
|
|
|
|
|
string item2 = result.Item2;
|
|
|
|
|
|
|
|
|
|
if (item2 == null)
|
|
|
|
|
{
|
|
|
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
|
|
|
return new Tuple<HttpStatusCode, IDictionary<string, object>>(code, null);
|
|
|
|
|
}
|
|
|
|
|
IDictionary<string, object> strs = null;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
strs = (!item2.StartsWith("[", StringComparison.Ordinal) ? AVClient.DeserializeJsonString(item2) : new Dictionary<string, object>()
|
|
|
|
|
{
|
|
|
|
|
{ "results", Json.Parse(item2) }
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
catch (Exception exception)
|
|
|
|
|
{
|
|
|
|
|
throw new AVException(AVException.ErrorCode.OtherCause, "Invalid response from server", exception);
|
|
|
|
|
}
|
|
|
|
|
var codeValue = (int)code;
|
|
|
|
|
if (codeValue > 203 || codeValue < 200)
|
|
|
|
|
{
|
|
|
|
|
throw new AVException((AVException.ErrorCode)((int)((strs.ContainsKey("code") ? (long)strs["code"] : (long)-1))), (strs.ContainsKey("error") ? strs["error"] as string : item2), null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
|
|
|
return new Tuple<HttpStatusCode, IDictionary<string, object>>(code, strs);
|
|
|
|
|
}
|
|
|
|
|
internal static Task<Tuple<HttpStatusCode, IDictionary<string, object>>> RequestAsync(string method, Uri relativeUri, string sessionToken, IDictionary<string, object> data, CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
var command = new AVCommand(relativeUri.ToString(),
|
|
|
|
|
method: method,
|
|
|
|
|
sessionToken: sessionToken,
|
|
|
|
|
data: data);
|
|
|
|
|
|
|
|
|
|
return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static Task<Tuple<HttpStatusCode, IDictionary<string, object>>> RunCommandAsync(AVCommand command)
|
|
|
|
|
{
|
|
|
|
|
return AVPlugins.Instance.CommandRunner.RunCommandAsync(command);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static bool IsSuccessStatusCode(HttpStatusCode responseStatus)
|
|
|
|
|
{
|
|
|
|
|
var codeValue = (int)responseStatus;
|
|
|
|
|
return (codeValue > 199) && (codeValue < 204);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static string ToLog(this HttpRequest request)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
var start = "===HTTP Request Start===";
|
|
|
|
|
sb.AppendLine(start);
|
|
|
|
|
var urlLog = "Url: " + request.Uri;
|
|
|
|
|
sb.AppendLine(urlLog);
|
|
|
|
|
|
|
|
|
|
var methodLog = "Method: " + request.Method;
|
|
|
|
|
sb.AppendLine(methodLog);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var headers = request.Headers.ToDictionary(x => x.Key, x => x.Value as object);
|
|
|
|
|
var headersLog = "Headers: " + Json.Encode(headers);
|
|
|
|
|
sb.AppendLine(headersLog);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (request is AVCommand)
|
|
|
|
|
{
|
|
|
|
|
var command = (AVCommand)request;
|
|
|
|
|
if (command.DataObject != null)
|
|
|
|
|
{
|
|
|
|
|
var bodyLog = "Body:" + Json.Encode(command.DataObject);
|
|
|
|
|
sb.AppendLine(bodyLog);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
StreamReader reader = new StreamReader(request.Data);
|
|
|
|
|
string bodyLog = reader.ReadToEnd();
|
|
|
|
|
sb.AppendLine(bodyLog);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var end = "===HTTP Request End===";
|
|
|
|
|
sb.AppendLine(end);
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|