diff --git a/build.cake b/build.cake index 18d3a71..75a1c62 100644 --- a/build.cake +++ b/build.cake @@ -9,7 +9,7 @@ var target = Argument("target", "Default"); var configuration = Argument("configuration", "Release"); var solution = "./Anywhere.ArcGIS.sln"; -var version = "1.4.0"; +var version = "1.5.0"; var versionSuffix = Environment.GetEnvironmentVariable("VERSION_SUFFIX"); ////////////////////////////////////////////////////////////////////// diff --git a/src/Anywhere.ArcGIS/Anywhere.ArcGIS.csproj b/src/Anywhere.ArcGIS/Anywhere.ArcGIS.csproj index 73ef2be..baea4b5 100644 --- a/src/Anywhere.ArcGIS/Anywhere.ArcGIS.csproj +++ b/src/Anywhere.ArcGIS/Anywhere.ArcGIS.csproj @@ -15,17 +15,22 @@ https://github.com/davetimmins/Anywhere.ArcGIS git ArcGIS ArcGISServer ArcGISOnline Esri REST netstandard anywhere GIS Mapping Map Location GeoLocation OAuth - 1.4.0 + 1.5.0 + + + + 1701;1702;1705;UseAsyncSuffix - + - + + diff --git a/src/Anywhere.ArcGIS/App_Packages/LibLog.4.2/LibLog.cs b/src/Anywhere.ArcGIS/App_Packages/LibLog.4.2/LibLog.cs deleted file mode 100644 index 1d3e421..0000000 --- a/src/Anywhere.ArcGIS/App_Packages/LibLog.4.2/LibLog.cs +++ /dev/null @@ -1,2385 +0,0 @@ -//=============================================================================== -// LibLog -// -// https://github.com/damianh/LibLog -//=============================================================================== -// Copyright © 2011-2015 Damian Hickey. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -//=============================================================================== - -// ReSharper disable PossibleNullReferenceException - -// Define LIBLOG_PORTABLE conditional compilation symbol for PCL compatibility -// -// Define LIBLOG_PUBLIC to enable ability to GET a logger (LogProvider.For<>() etc) from outside this library. NOTE: -// this can have unintended consequences of consumers of your library using your library to resolve a logger. If the -// reason is because you want to open this functionality to other projects within your solution, -// consider [InternalsVisibleTo] instead. -// -// Define LIBLOG_PROVIDERS_ONLY if your library provides its own logging API and you just want to use the -// LibLog providers internally to provide built in support for popular logging frameworks. - -#pragma warning disable 1591 - -using System.Diagnostics.CodeAnalysis; - -[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Anywhere.ArcGIS.Logging")] -[assembly: SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Scope = "member", Target = "Anywhere.ArcGIS.Logging.Logger.#Invoke(Anywhere.ArcGIS.Logging.LogLevel,System.Func`1,System.Exception,System.Object[])")] - -// If you copied this file manually, you need to change all "Anywhere.ArcGIS" so not to clash with other libraries -// that use LibLog -#if LIBLOG_PROVIDERS_ONLY -namespace Anywhere.ArcGIS.LibLog -#else -namespace Anywhere.ArcGIS.Logging -#endif -{ - using System.Collections.Generic; - using System.Diagnostics.CodeAnalysis; -#if LIBLOG_PROVIDERS_ONLY - using Anywhere.ArcGIS.LibLog.LogProviders; -#else - using Anywhere.ArcGIS.Logging.LogProviders; -#endif - using System; -#if !LIBLOG_PROVIDERS_ONLY - using System.Diagnostics; -#if !LIBLOG_PORTABLE - using System.Runtime.CompilerServices; -#endif -#endif - -#if LIBLOG_PROVIDERS_ONLY - internal -#else - public -#endif - delegate bool Logger(LogLevel logLevel, Func messageFunc, Exception exception = null, params object[] formatParameters); - -#if !LIBLOG_PROVIDERS_ONLY - /// - /// Simple interface that represent a logger. - /// -#if LIBLOG_PUBLIC - public -#else - internal -#endif - interface ILog - { - /// - /// Log a message the specified log level. - /// - /// The log level. - /// The message function. - /// An optional exception. - /// Optional format parameters for the message generated by the messagefunc. - /// true if the message was logged. Otherwise false. - /// - /// Note to implementers: the message func should not be called if the loglevel is not enabled - /// so as not to incur performance penalties. - /// - /// To check IsEnabled call Log with only LogLevel and check the return value, no event will be written. - /// - bool Log(LogLevel logLevel, Func messageFunc, Exception exception = null, params object[] formatParameters); - } -#endif - - /// - /// The log level. - /// -#if LIBLOG_PROVIDERS_ONLY - internal -#else - public -#endif - enum LogLevel - { - Trace, - Debug, - Info, - Warn, - Error, - Fatal - } - -#if !LIBLOG_PROVIDERS_ONLY -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif -#if LIBLOG_PUBLIC - public -#else - internal -#endif - static partial class LogExtensions - { - public static bool IsDebugEnabled(this ILog logger) - { - GuardAgainstNullLogger(logger); - return logger.Log(LogLevel.Debug, null); - } - - public static bool IsErrorEnabled(this ILog logger) - { - GuardAgainstNullLogger(logger); - return logger.Log(LogLevel.Error, null); - } - - public static bool IsFatalEnabled(this ILog logger) - { - GuardAgainstNullLogger(logger); - return logger.Log(LogLevel.Fatal, null); - } - - public static bool IsInfoEnabled(this ILog logger) - { - GuardAgainstNullLogger(logger); - return logger.Log(LogLevel.Info, null); - } - - public static bool IsTraceEnabled(this ILog logger) - { - GuardAgainstNullLogger(logger); - return logger.Log(LogLevel.Trace, null); - } - - public static bool IsWarnEnabled(this ILog logger) - { - GuardAgainstNullLogger(logger); - return logger.Log(LogLevel.Warn, null); - } - - public static void Debug(this ILog logger, Func messageFunc) - { - GuardAgainstNullLogger(logger); - logger.Log(LogLevel.Debug, messageFunc); - } - - public static void Debug(this ILog logger, string message) - { - if (logger.IsDebugEnabled()) - { - logger.Log(LogLevel.Debug, message.AsFunc()); - } - } - - public static void Debug(this ILog logger, string message, params object[] args) - { - logger.DebugFormat(message, args); - } - - public static void Debug(this ILog logger, Exception exception, string message, params object[] args) - { - logger.DebugException(message, exception, args); - } - - public static void DebugFormat(this ILog logger, string message, params object[] args) - { - if (logger.IsDebugEnabled()) - { - logger.LogFormat(LogLevel.Debug, message, args); - } - } - - public static void DebugException(this ILog logger, string message, Exception exception) - { - if (logger.IsDebugEnabled()) - { - logger.Log(LogLevel.Debug, message.AsFunc(), exception); - } - } - - public static void DebugException(this ILog logger, string message, Exception exception, params object[] formatParams) - { - if (logger.IsDebugEnabled()) - { - logger.Log(LogLevel.Debug, message.AsFunc(), exception, formatParams); - } - } - - public static void Error(this ILog logger, Func messageFunc) - { - GuardAgainstNullLogger(logger); - logger.Log(LogLevel.Error, messageFunc); - } - - public static void Error(this ILog logger, string message) - { - if (logger.IsErrorEnabled()) - { - logger.Log(LogLevel.Error, message.AsFunc()); - } - } - - public static void Error(this ILog logger, string message, params object[] args) - { - logger.ErrorFormat(message, args); - } - - public static void Error(this ILog logger, Exception exception, string message, params object[] args) - { - logger.ErrorException(message, exception, args); - } - - public static void ErrorFormat(this ILog logger, string message, params object[] args) - { - if (logger.IsErrorEnabled()) - { - logger.LogFormat(LogLevel.Error, message, args); - } - } - - public static void ErrorException(this ILog logger, string message, Exception exception, params object[] formatParams) - { - if (logger.IsErrorEnabled()) - { - logger.Log(LogLevel.Error, message.AsFunc(), exception, formatParams); - } - } - - public static void Fatal(this ILog logger, Func messageFunc) - { - logger.Log(LogLevel.Fatal, messageFunc); - } - - public static void Fatal(this ILog logger, string message) - { - if (logger.IsFatalEnabled()) - { - logger.Log(LogLevel.Fatal, message.AsFunc()); - } - } - - public static void Fatal(this ILog logger, string message, params object[] args) - { - logger.FatalFormat(message, args); - } - - public static void Fatal(this ILog logger, Exception exception, string message, params object[] args) - { - logger.FatalException(message, exception, args); - } - - public static void FatalFormat(this ILog logger, string message, params object[] args) - { - if (logger.IsFatalEnabled()) - { - logger.LogFormat(LogLevel.Fatal, message, args); - } - } - - public static void FatalException(this ILog logger, string message, Exception exception, params object[] formatParams) - { - if (logger.IsFatalEnabled()) - { - logger.Log(LogLevel.Fatal, message.AsFunc(), exception, formatParams); - } - } - - public static void Info(this ILog logger, Func messageFunc) - { - GuardAgainstNullLogger(logger); - logger.Log(LogLevel.Info, messageFunc); - } - - public static void Info(this ILog logger, string message) - { - if (logger.IsInfoEnabled()) - { - logger.Log(LogLevel.Info, message.AsFunc()); - } - } - - public static void Info(this ILog logger, string message, params object[] args) - { - logger.InfoFormat(message, args); - } - - public static void Info(this ILog logger, Exception exception, string message, params object[] args) - { - logger.InfoException(message, exception, args); - } - - public static void InfoFormat(this ILog logger, string message, params object[] args) - { - if (logger.IsInfoEnabled()) - { - logger.LogFormat(LogLevel.Info, message, args); - } - } - - public static void InfoException(this ILog logger, string message, Exception exception, params object[] formatParams) - { - if (logger.IsInfoEnabled()) - { - logger.Log(LogLevel.Info, message.AsFunc(), exception, formatParams); - } - } - - public static void Trace(this ILog logger, Func messageFunc) - { - GuardAgainstNullLogger(logger); - logger.Log(LogLevel.Trace, messageFunc); - } - - public static void Trace(this ILog logger, string message) - { - if (logger.IsTraceEnabled()) - { - logger.Log(LogLevel.Trace, message.AsFunc()); - } - } - - public static void Trace(this ILog logger, string message, params object[] args) - { - logger.TraceFormat(message, args); - } - - public static void Trace(this ILog logger, Exception exception, string message, params object[] args) - { - logger.TraceException(message, exception, args); - } - - public static void TraceFormat(this ILog logger, string message, params object[] args) - { - if (logger.IsTraceEnabled()) - { - logger.LogFormat(LogLevel.Trace, message, args); - } - } - - public static void TraceException(this ILog logger, string message, Exception exception, params object[] formatParams) - { - if (logger.IsTraceEnabled()) - { - logger.Log(LogLevel.Trace, message.AsFunc(), exception, formatParams); - } - } - - public static void Warn(this ILog logger, Func messageFunc) - { - GuardAgainstNullLogger(logger); - logger.Log(LogLevel.Warn, messageFunc); - } - - public static void Warn(this ILog logger, string message) - { - if (logger.IsWarnEnabled()) - { - logger.Log(LogLevel.Warn, message.AsFunc()); - } - } - - public static void Warn(this ILog logger, string message, params object[] args) - { - logger.WarnFormat(message, args); - } - - public static void Warn(this ILog logger, Exception exception, string message, params object[] args) - { - logger.WarnException(message, exception, args); - } - - public static void WarnFormat(this ILog logger, string message, params object[] args) - { - if (logger.IsWarnEnabled()) - { - logger.LogFormat(LogLevel.Warn, message, args); - } - } - - public static void WarnException(this ILog logger, string message, Exception exception, params object[] formatParams) - { - if (logger.IsWarnEnabled()) - { - logger.Log(LogLevel.Warn, message.AsFunc(), exception, formatParams); - } - } - - // ReSharper disable once UnusedParameter.Local - private static void GuardAgainstNullLogger(ILog logger) - { - if (logger == null) - { - throw new ArgumentNullException("logger"); - } - } - - private static void LogFormat(this ILog logger, LogLevel logLevel, string message, params object[] args) - { - logger.Log(logLevel, message.AsFunc(), null, args); - } - - // Avoid the closure allocation, see https://gist.github.com/AArnott/d285feef75c18f6ecd2b - private static Func AsFunc(this T value) where T : class - { - return value.Return; - } - - private static T Return(this T value) - { - return value; - } - } -#endif - - /// - /// Represents a way to get a - /// -#if LIBLOG_PROVIDERS_ONLY - internal -#else - public -#endif - interface ILogProvider - { - /// - /// Gets the specified named logger. - /// - /// Name of the logger. - /// The logger reference. - Logger GetLogger(string name); - - /// - /// Opens a nested diagnostics context. Not supported in EntLib logging. - /// - /// The message to add to the diagnostics context. - /// A disposable that when disposed removes the message from the context. - IDisposable OpenNestedContext(string message); - - /// - /// Opens a mapped diagnostics context. Not supported in EntLib logging. - /// - /// A key. - /// A value. - /// A disposable that when disposed removes the map from the context. - IDisposable OpenMappedContext(string key, string value); - } - - /// - /// Provides a mechanism to create instances of objects. - /// -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif -#if LIBLOG_PROVIDERS_ONLY - internal -#else - public -#endif - static class LogProvider - { -#if !LIBLOG_PROVIDERS_ONLY - private const string NullLogProvider = "Current Log Provider is not set. Call SetCurrentLogProvider " + - "with a non-null value first."; - private static dynamic s_currentLogProvider; - private static Action s_onCurrentLogProviderSet; - - [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] - static LogProvider() - { - IsDisabled = false; - } - - /// - /// Sets the current log provider. - /// - /// The log provider. - public static void SetCurrentLogProvider(ILogProvider logProvider) - { - s_currentLogProvider = logProvider; - - RaiseOnCurrentLogProviderSet(); - } - - /// - /// Gets or sets a value indicating whether this is logging is disabled. - /// - /// - /// true if logging is disabled; otherwise, false. - /// - public static bool IsDisabled { get; set; } - - /// - /// Sets an action that is invoked when a consumer of your library has called SetCurrentLogProvider. It is - /// important that hook into this if you are using child libraries (especially ilmerged ones) that are using - /// LibLog (or other logging abstraction) so you adapt and delegate to them. - /// - /// - internal static Action OnCurrentLogProviderSet - { - set - { - s_onCurrentLogProviderSet = value; - RaiseOnCurrentLogProviderSet(); - } - } - - internal static ILogProvider CurrentLogProvider - { - get - { - return s_currentLogProvider; - } - } - - /// - /// Gets a logger for the specified type. - /// - /// The type whose name will be used for the logger. - /// An instance of -#if LIBLOG_PUBLIC - public -#else - internal -#endif - static ILog For() - { - return GetLogger(typeof(T)); - } - -#if !LIBLOG_PORTABLE - /// - /// Gets a logger for the current class. - /// - /// An instance of - [MethodImpl(MethodImplOptions.NoInlining)] -#if LIBLOG_PUBLIC - public -#else - internal -#endif - static ILog GetCurrentClassLogger() - { - var stackFrame = new StackFrame(1, false); - return GetLogger(stackFrame.GetMethod().DeclaringType); - } -#endif - - /// - /// Gets a logger for the specified type. - /// - /// The type whose name will be used for the logger. - /// If the type is null then this name will be used as the log name instead - /// An instance of -#if LIBLOG_PUBLIC - public -#else - internal -#endif - static ILog GetLogger(Type type, string fallbackTypeName = "System.Object") - { - // If the type passed in is null then fallback to the type name specified - return GetLogger(type != null ? type.FullName : fallbackTypeName); - } - - /// - /// Gets a logger with the specified name. - /// - /// The name. - /// An instance of -#if LIBLOG_PUBLIC - public -#else - internal -#endif - static ILog GetLogger(string name) - { - ILogProvider logProvider = CurrentLogProvider ?? ResolveLogProvider(); - return logProvider == null - ? NoOpLogger.Instance - : (ILog)new LoggerExecutionWrapper(logProvider.GetLogger(name), () => IsDisabled); - } - - /// - /// Opens a nested diagnostics context. - /// - /// A message. - /// An that closes context when disposed. - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "SetCurrentLogProvider")] -#if LIBLOG_PUBLIC - public -#else - internal -#endif - static IDisposable OpenNestedContext(string message) - { - ILogProvider logProvider = CurrentLogProvider ?? ResolveLogProvider(); - - return logProvider == null - ? new DisposableAction(() => { }) - : logProvider.OpenNestedContext(message); - } - - /// - /// Opens a mapped diagnostics context. - /// - /// A key. - /// A value. - /// An that closes context when disposed. - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "SetCurrentLogProvider")] -#if LIBLOG_PUBLIC - public -#else - internal -#endif - static IDisposable OpenMappedContext(string key, string value) - { - ILogProvider logProvider = CurrentLogProvider ?? ResolveLogProvider(); - - return logProvider == null - ? new DisposableAction(() => { }) - : logProvider.OpenMappedContext(key, value); - } -#endif - -#if LIBLOG_PROVIDERS_ONLY - private -#else - internal -#endif - delegate bool IsLoggerAvailable(); - -#if LIBLOG_PROVIDERS_ONLY - private -#else - internal -#endif - delegate ILogProvider CreateLogProvider(); - -#if LIBLOG_PROVIDERS_ONLY - private -#else - internal -#endif - static readonly List> LogProviderResolvers = - new List> - { - new Tuple(SerilogLogProvider.IsLoggerAvailable, () => new SerilogLogProvider()), - new Tuple(NLogLogProvider.IsLoggerAvailable, () => new NLogLogProvider()), - new Tuple(Log4NetLogProvider.IsLoggerAvailable, () => new Log4NetLogProvider()), - new Tuple(EntLibLogProvider.IsLoggerAvailable, () => new EntLibLogProvider()), - new Tuple(LoupeLogProvider.IsLoggerAvailable, () => new LoupeLogProvider()), - }; - -#if !LIBLOG_PROVIDERS_ONLY - private static void RaiseOnCurrentLogProviderSet() - { - if (s_onCurrentLogProviderSet != null) - { - s_onCurrentLogProviderSet(s_currentLogProvider); - } - } -#endif - - [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Console.WriteLine(System.String,System.Object,System.Object)")] - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - internal static ILogProvider ResolveLogProvider() - { - try - { - foreach (var providerResolver in LogProviderResolvers) - { - if (providerResolver.Item1()) - { - return providerResolver.Item2(); - } - } - } - catch (Exception ex) - { -#if LIBLOG_PORTABLE - Debug.WriteLine( -#else - Console.WriteLine( -#endif - "Exception occurred resolving a log provider. Logging for this assembly {0} is disabled. {1}", - typeof(LogProvider).GetAssemblyPortable().FullName, - ex); - } - return null; - } - -#if !LIBLOG_PROVIDERS_ONLY -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal class NoOpLogger : ILog - { - internal static readonly NoOpLogger Instance = new NoOpLogger(); - - public bool Log(LogLevel logLevel, Func messageFunc, Exception exception, params object[] formatParameters) - { - return false; - } - } -#endif - } - -#if !LIBLOG_PROVIDERS_ONLY -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal class LoggerExecutionWrapper : ILog - { - private readonly Logger _logger; - private readonly Func _getIsDisabled; - internal const string FailedToGenerateLogMessage = "Failed to generate log message"; - - internal LoggerExecutionWrapper(Logger logger, Func getIsDisabled = null) - { - _logger = logger; - _getIsDisabled = getIsDisabled ?? (() => false); - } - - internal Logger WrappedLogger - { - get { return _logger; } - } - - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - public bool Log(LogLevel logLevel, Func messageFunc, Exception exception = null, params object[] formatParameters) - { - if (_getIsDisabled()) - { - return false; - } - if (messageFunc == null) - { - return _logger(logLevel, null); - } - - Func wrappedMessageFunc = () => - { - try - { - return messageFunc(); - } - catch (Exception ex) - { - Log(LogLevel.Error, () => FailedToGenerateLogMessage, ex); - } - return null; - }; - return _logger(logLevel, wrappedMessageFunc, exception, formatParameters); - } - } -#endif -} - -#if LIBLOG_PROVIDERS_ONLY -namespace Anywhere.ArcGIS.LibLog.LogProviders -#else -namespace Anywhere.ArcGIS.Logging.LogProviders -#endif -{ - using System; - using System.Collections.Generic; - using System.Diagnostics.CodeAnalysis; -#if !LIBLOG_PORTABLE - using System.Diagnostics; -#endif - using System.Globalization; - using System.Linq; - using System.Linq.Expressions; - using System.Reflection; -#if !LIBLOG_PORTABLE - using System.Text; -#endif - using System.Text.RegularExpressions; - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal abstract class LogProviderBase : ILogProvider - { - protected delegate IDisposable OpenNdc(string message); - protected delegate IDisposable OpenMdc(string key, string value); - - private readonly Lazy _lazyOpenNdcMethod; - private readonly Lazy _lazyOpenMdcMethod; - private static readonly IDisposable NoopDisposableInstance = new DisposableAction(); - - protected LogProviderBase() - { - _lazyOpenNdcMethod - = new Lazy(GetOpenNdcMethod); - _lazyOpenMdcMethod - = new Lazy(GetOpenMdcMethod); - } - - public abstract Logger GetLogger(string name); - - public IDisposable OpenNestedContext(string message) - { - return _lazyOpenNdcMethod.Value(message); - } - - public IDisposable OpenMappedContext(string key, string value) - { - return _lazyOpenMdcMethod.Value(key, value); - } - - protected virtual OpenNdc GetOpenNdcMethod() - { - return _ => NoopDisposableInstance; - } - - protected virtual OpenMdc GetOpenMdcMethod() - { - return (_, __) => NoopDisposableInstance; - } - } - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal class NLogLogProvider : LogProviderBase - { - private readonly Func _getLoggerByNameDelegate; - private static bool s_providerIsAvailableOverride = true; - - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "LogManager")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "NLog")] - public NLogLogProvider() - { - if (!IsLoggerAvailable()) - { - throw new InvalidOperationException("NLog.LogManager not found"); - } - _getLoggerByNameDelegate = GetGetLoggerMethodCall(); - } - - public static bool ProviderIsAvailableOverride - { - get { return s_providerIsAvailableOverride; } - set { s_providerIsAvailableOverride = value; } - } - - public override Logger GetLogger(string name) - { - return new NLogLogger(_getLoggerByNameDelegate(name)).Log; - } - - public static bool IsLoggerAvailable() - { - return ProviderIsAvailableOverride && GetLogManagerType() != null; - } - - protected override OpenNdc GetOpenNdcMethod() - { - Type ndcContextType = Type.GetType("NLog.NestedDiagnosticsContext, NLog"); - MethodInfo pushMethod = ndcContextType.GetMethodPortable("Push", typeof(string)); - ParameterExpression messageParam = Expression.Parameter(typeof(string), "message"); - MethodCallExpression pushMethodCall = Expression.Call(null, pushMethod, messageParam); - return Expression.Lambda(pushMethodCall, messageParam).Compile(); - } - - protected override OpenMdc GetOpenMdcMethod() - { - Type mdcContextType = Type.GetType("NLog.MappedDiagnosticsContext, NLog"); - - MethodInfo setMethod = mdcContextType.GetMethodPortable("Set", typeof(string), typeof(string)); - MethodInfo removeMethod = mdcContextType.GetMethodPortable("Remove", typeof(string)); - ParameterExpression keyParam = Expression.Parameter(typeof(string), "key"); - ParameterExpression valueParam = Expression.Parameter(typeof(string), "value"); - - MethodCallExpression setMethodCall = Expression.Call(null, setMethod, keyParam, valueParam); - MethodCallExpression removeMethodCall = Expression.Call(null, removeMethod, keyParam); - - Action set = Expression - .Lambda>(setMethodCall, keyParam, valueParam) - .Compile(); - Action remove = Expression - .Lambda>(removeMethodCall, keyParam) - .Compile(); - - return (key, value) => - { - set(key, value); - return new DisposableAction(() => remove(key)); - }; - } - - private static Type GetLogManagerType() - { - return Type.GetType("NLog.LogManager, NLog"); - } - - private static Func GetGetLoggerMethodCall() - { - Type logManagerType = GetLogManagerType(); - MethodInfo method = logManagerType.GetMethodPortable("GetLogger", typeof(string)); - ParameterExpression nameParam = Expression.Parameter(typeof(string), "name"); - MethodCallExpression methodCall = Expression.Call(null, method, nameParam); - return Expression.Lambda>(methodCall, nameParam).Compile(); - } - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal class NLogLogger - { - private readonly dynamic _logger; - - private static Func _logEventInfoFact; - - private static readonly object _levelTrace; - private static readonly object _levelDebug; - private static readonly object _levelInfo; - private static readonly object _levelWarn; - private static readonly object _levelError; - private static readonly object _levelFatal; - - static NLogLogger() - { - try - { - var logEventLevelType = Type.GetType("NLog.LogLevel, NLog"); - if (logEventLevelType == null) - { - throw new InvalidOperationException("Type NLog.LogLevel was not found."); - } - - var levelFields = logEventLevelType.GetFieldsPortable().ToList(); - _levelTrace = levelFields.First(x => x.Name == "Trace").GetValue(null); - _levelDebug = levelFields.First(x => x.Name == "Debug").GetValue(null); - _levelInfo = levelFields.First(x => x.Name == "Info").GetValue(null); - _levelWarn = levelFields.First(x => x.Name == "Warn").GetValue(null); - _levelError = levelFields.First(x => x.Name == "Error").GetValue(null); - _levelFatal = levelFields.First(x => x.Name == "Fatal").GetValue(null); - - var logEventInfoType = Type.GetType("NLog.LogEventInfo, NLog"); - if (logEventInfoType == null) - { - throw new InvalidOperationException("Type NLog.LogEventInfo was not found."); - } - MethodInfo createLogEventInfoMethodInfo = logEventInfoType.GetMethodPortable("Create", - logEventLevelType, typeof(string), typeof(Exception), typeof(IFormatProvider), typeof(string), typeof(object[])); - ParameterExpression loggerNameParam = Expression.Parameter(typeof(string)); - ParameterExpression levelParam = Expression.Parameter(typeof(object)); - ParameterExpression messageParam = Expression.Parameter(typeof(string)); - ParameterExpression exceptionParam = Expression.Parameter(typeof(Exception)); - UnaryExpression levelCast = Expression.Convert(levelParam, logEventLevelType); - MethodCallExpression createLogEventInfoMethodCall = Expression.Call(null, - createLogEventInfoMethodInfo, - levelCast, loggerNameParam, exceptionParam, - Expression.Constant(null, typeof(IFormatProvider)), messageParam, Expression.Constant(null, typeof(object[]))); - _logEventInfoFact = Expression.Lambda>(createLogEventInfoMethodCall, - loggerNameParam, levelParam, messageParam, exceptionParam).Compile(); - } - catch { } - } - - internal NLogLogger(dynamic logger) - { - _logger = logger; - } - - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - public bool Log(LogLevel logLevel, Func messageFunc, Exception exception, params object[] formatParameters) - { - if (messageFunc == null) - { - return IsLogLevelEnable(logLevel); - } - messageFunc = LogMessageFormatter.SimulateStructuredLogging(messageFunc, formatParameters); - - if (_logEventInfoFact != null) - { - if (IsLogLevelEnable(logLevel)) - { - var nlogLevel = this.TranslateLevel(logLevel); - Type s_callerStackBoundaryType; -#if !LIBLOG_PORTABLE - StackTrace stack = new StackTrace(); - Type thisType = GetType(); - Type knownType0 = typeof(LoggerExecutionWrapper); - Type knownType1 = typeof(LogExtensions); - //Maybe inline, so we may can't found any LibLog classes in stack - s_callerStackBoundaryType = null; - for (var i = 0; i < stack.FrameCount; i++) - { - var declaringType = stack.GetFrame(i).GetMethod().DeclaringType; - if (!IsInTypeHierarchy(thisType, declaringType) && - !IsInTypeHierarchy(knownType0, declaringType) && - !IsInTypeHierarchy(knownType1, declaringType)) - { - if (i > 1) - s_callerStackBoundaryType = stack.GetFrame(i - 1).GetMethod().DeclaringType; - break; - } - } -#else - s_callerStackBoundaryType = null; -#endif - if (s_callerStackBoundaryType != null) - _logger.Log(s_callerStackBoundaryType, _logEventInfoFact(_logger.Name, nlogLevel, messageFunc(), exception)); - else - _logger.Log(_logEventInfoFact(_logger.Name, nlogLevel, messageFunc(), exception)); - return true; - } - return false; - } - - if (exception != null) - { - return LogException(logLevel, messageFunc, exception); - } - switch (logLevel) - { - case LogLevel.Debug: - if (_logger.IsDebugEnabled) - { - _logger.Debug(messageFunc()); - return true; - } - break; - case LogLevel.Info: - if (_logger.IsInfoEnabled) - { - _logger.Info(messageFunc()); - return true; - } - break; - case LogLevel.Warn: - if (_logger.IsWarnEnabled) - { - _logger.Warn(messageFunc()); - return true; - } - break; - case LogLevel.Error: - if (_logger.IsErrorEnabled) - { - _logger.Error(messageFunc()); - return true; - } - break; - case LogLevel.Fatal: - if (_logger.IsFatalEnabled) - { - _logger.Fatal(messageFunc()); - return true; - } - break; - default: - if (_logger.IsTraceEnabled) - { - _logger.Trace(messageFunc()); - return true; - } - break; - } - return false; - } - - private static bool IsInTypeHierarchy(Type currentType, Type checkType) - { - while (currentType != null && currentType != typeof(object)) - { - if (currentType == checkType) - { - return true; - } - currentType = currentType.GetBaseTypePortable(); - } - return false; - } - - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - private bool LogException(LogLevel logLevel, Func messageFunc, Exception exception) - { - switch (logLevel) - { - case LogLevel.Debug: - if (_logger.IsDebugEnabled) - { - _logger.DebugException(messageFunc(), exception); - return true; - } - break; - case LogLevel.Info: - if (_logger.IsInfoEnabled) - { - _logger.InfoException(messageFunc(), exception); - return true; - } - break; - case LogLevel.Warn: - if (_logger.IsWarnEnabled) - { - _logger.WarnException(messageFunc(), exception); - return true; - } - break; - case LogLevel.Error: - if (_logger.IsErrorEnabled) - { - _logger.ErrorException(messageFunc(), exception); - return true; - } - break; - case LogLevel.Fatal: - if (_logger.IsFatalEnabled) - { - _logger.FatalException(messageFunc(), exception); - return true; - } - break; - default: - if (_logger.IsTraceEnabled) - { - _logger.TraceException(messageFunc(), exception); - return true; - } - break; - } - return false; - } - - private bool IsLogLevelEnable(LogLevel logLevel) - { - switch (logLevel) - { - case LogLevel.Debug: - return _logger.IsDebugEnabled; - case LogLevel.Info: - return _logger.IsInfoEnabled; - case LogLevel.Warn: - return _logger.IsWarnEnabled; - case LogLevel.Error: - return _logger.IsErrorEnabled; - case LogLevel.Fatal: - return _logger.IsFatalEnabled; - default: - return _logger.IsTraceEnabled; - } - } - - private object TranslateLevel(LogLevel logLevel) - { - switch (logLevel) - { - case LogLevel.Trace: - return _levelTrace; - case LogLevel.Debug: - return _levelDebug; - case LogLevel.Info: - return _levelInfo; - case LogLevel.Warn: - return _levelWarn; - case LogLevel.Error: - return _levelError; - case LogLevel.Fatal: - return _levelFatal; - default: - throw new ArgumentOutOfRangeException("logLevel", logLevel, null); - } - } - } - } - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal class Log4NetLogProvider : LogProviderBase - { - private readonly Func _getLoggerByNameDelegate; - private static bool s_providerIsAvailableOverride = true; - - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "LogManager")] - public Log4NetLogProvider() - { - if (!IsLoggerAvailable()) - { - throw new InvalidOperationException("log4net.LogManager not found"); - } - _getLoggerByNameDelegate = GetGetLoggerMethodCall(); - } - - public static bool ProviderIsAvailableOverride - { - get { return s_providerIsAvailableOverride; } - set { s_providerIsAvailableOverride = value; } - } - - public override Logger GetLogger(string name) - { - return new Log4NetLogger(_getLoggerByNameDelegate(name)).Log; - } - - internal static bool IsLoggerAvailable() - { - return ProviderIsAvailableOverride && GetLogManagerType() != null; - } - - protected override OpenNdc GetOpenNdcMethod() - { - Type logicalThreadContextType = Type.GetType("log4net.LogicalThreadContext, log4net"); - PropertyInfo stacksProperty = logicalThreadContextType.GetPropertyPortable("Stacks"); - Type logicalThreadContextStacksType = stacksProperty.PropertyType; - PropertyInfo stacksIndexerProperty = logicalThreadContextStacksType.GetPropertyPortable("Item"); - Type stackType = stacksIndexerProperty.PropertyType; - MethodInfo pushMethod = stackType.GetMethodPortable("Push"); - - ParameterExpression messageParameter = - Expression.Parameter(typeof(string), "message"); - - // message => LogicalThreadContext.Stacks.Item["NDC"].Push(message); - MethodCallExpression callPushBody = - Expression.Call( - Expression.Property(Expression.Property(null, stacksProperty), - stacksIndexerProperty, - Expression.Constant("NDC")), - pushMethod, - messageParameter); - - OpenNdc result = - Expression.Lambda(callPushBody, messageParameter) - .Compile(); - - return result; - } - - protected override OpenMdc GetOpenMdcMethod() - { - Type logicalThreadContextType = Type.GetType("log4net.LogicalThreadContext, log4net"); - PropertyInfo propertiesProperty = logicalThreadContextType.GetPropertyPortable("Properties"); - Type logicalThreadContextPropertiesType = propertiesProperty.PropertyType; - PropertyInfo propertiesIndexerProperty = logicalThreadContextPropertiesType.GetPropertyPortable("Item"); - - MethodInfo removeMethod = logicalThreadContextPropertiesType.GetMethodPortable("Remove"); - - ParameterExpression keyParam = Expression.Parameter(typeof(string), "key"); - ParameterExpression valueParam = Expression.Parameter(typeof(string), "value"); - - MemberExpression propertiesExpression = Expression.Property(null, propertiesProperty); - - // (key, value) => LogicalThreadContext.Properties.Item[key] = value; - BinaryExpression setProperties = Expression.Assign(Expression.Property(propertiesExpression, propertiesIndexerProperty, keyParam), valueParam); - - // key => LogicalThreadContext.Properties.Remove(key); - MethodCallExpression removeMethodCall = Expression.Call(propertiesExpression, removeMethod, keyParam); - - Action set = Expression - .Lambda>(setProperties, keyParam, valueParam) - .Compile(); - - Action remove = Expression - .Lambda>(removeMethodCall, keyParam) - .Compile(); - - return (key, value) => - { - set(key, value); - return new DisposableAction(() => remove(key)); - }; - } - - private static Type GetLogManagerType() - { - return Type.GetType("log4net.LogManager, log4net"); - } - - private static Func GetGetLoggerMethodCall() - { - Type logManagerType = GetLogManagerType(); - MethodInfo method = logManagerType.GetMethodPortable("GetLogger", typeof(string)); - ParameterExpression nameParam = Expression.Parameter(typeof(string), "name"); - MethodCallExpression methodCall = Expression.Call(null, method, nameParam); - return Expression.Lambda>(methodCall, nameParam).Compile(); - } - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal class Log4NetLogger - { - private readonly dynamic _logger; - private static Type s_callerStackBoundaryType; - private static readonly object CallerStackBoundaryTypeSync = new object(); - - private static readonly object _levelDebug; - private static readonly object _levelInfo; - private static readonly object _levelWarn; - private static readonly object _levelError; - private static readonly object _levelFatal; - private static readonly Func _isEnabledForDelegate; - private static readonly Action _logDelegate; - private static readonly Func _createLoggingEvent; - private static readonly Action _loggingEventPropertySetter; - - static Log4NetLogger() - { - var logEventLevelType = Type.GetType("log4net.Core.Level, log4net"); - if (logEventLevelType == null) - { - throw new InvalidOperationException("Type log4net.Core.Level was not found."); - } - - var levelFields = logEventLevelType.GetFieldsPortable().ToList(); - _levelDebug = levelFields.First(x => x.Name == "Debug").GetValue(null); - _levelInfo = levelFields.First(x => x.Name == "Info").GetValue(null); - _levelWarn = levelFields.First(x => x.Name == "Warn").GetValue(null); - _levelError = levelFields.First(x => x.Name == "Error").GetValue(null); - _levelFatal = levelFields.First(x => x.Name == "Fatal").GetValue(null); - - // Func isEnabledFor = (logger, level) => { return ((log4net.Core.ILogger)logger).IsEnabled(level); } - var loggerType = Type.GetType("log4net.Core.ILogger, log4net"); - if (loggerType == null) - { - throw new InvalidOperationException("Type log4net.Core.ILogger, was not found."); - } - ParameterExpression instanceParam = Expression.Parameter(typeof(object)); - UnaryExpression instanceCast = Expression.Convert(instanceParam, loggerType); - ParameterExpression levelParam = Expression.Parameter(typeof(object)); - UnaryExpression levelCast = Expression.Convert(levelParam, logEventLevelType); - _isEnabledForDelegate = GetIsEnabledFor(loggerType, logEventLevelType, instanceCast, levelCast, instanceParam, levelParam); - - Type loggingEventType = Type.GetType("log4net.Core.LoggingEvent, log4net"); - - _createLoggingEvent = GetCreateLoggingEvent(instanceParam, instanceCast, levelParam, levelCast, loggingEventType); - - _logDelegate = GetLogDelegate(loggerType, loggingEventType, instanceCast, instanceParam); - - _loggingEventPropertySetter = GetLoggingEventPropertySetter(loggingEventType); - } - - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "ILogger")] - internal Log4NetLogger(dynamic logger) - { - _logger = logger.Logger; - } - - private static Action GetLogDelegate(Type loggerType, Type loggingEventType, UnaryExpression instanceCast, - ParameterExpression instanceParam) - { - //Action Log = - //(logger, callerStackBoundaryDeclaringType, level, message, exception) => { ((ILogger)logger).Log(new LoggingEvent(callerStackBoundaryDeclaringType, logger.Repository, logger.Name, level, message, exception)); } - MethodInfo writeExceptionMethodInfo = loggerType.GetMethodPortable("Log", - loggingEventType); - - ParameterExpression loggingEventParameter = - Expression.Parameter(typeof(object), "loggingEvent"); - - UnaryExpression loggingEventCasted = - Expression.Convert(loggingEventParameter, loggingEventType); - - var writeMethodExp = Expression.Call( - instanceCast, - writeExceptionMethodInfo, - loggingEventCasted); - - var logDelegate = Expression.Lambda>( - writeMethodExp, - instanceParam, - loggingEventParameter).Compile(); - - return logDelegate; - } - - private static Func GetCreateLoggingEvent(ParameterExpression instanceParam, UnaryExpression instanceCast, ParameterExpression levelParam, UnaryExpression levelCast, Type loggingEventType) - { - ParameterExpression callerStackBoundaryDeclaringTypeParam = Expression.Parameter(typeof(Type)); - ParameterExpression messageParam = Expression.Parameter(typeof(string)); - ParameterExpression exceptionParam = Expression.Parameter(typeof(Exception)); - - PropertyInfo repositoryProperty = loggingEventType.GetPropertyPortable("Repository"); - PropertyInfo levelProperty = loggingEventType.GetPropertyPortable("Level"); - - ConstructorInfo loggingEventConstructor = - loggingEventType.GetConstructorPortable(typeof(Type), repositoryProperty.PropertyType, typeof(string), levelProperty.PropertyType, typeof(object), typeof(Exception)); - - //Func Log = - //(logger, callerStackBoundaryDeclaringType, level, message, exception) => new LoggingEvent(callerStackBoundaryDeclaringType, ((ILogger)logger).Repository, ((ILogger)logger).Name, (Level)level, message, exception); } - NewExpression newLoggingEventExpression = - Expression.New(loggingEventConstructor, - callerStackBoundaryDeclaringTypeParam, - Expression.Property(instanceCast, "Repository"), - Expression.Property(instanceCast, "Name"), - levelCast, - messageParam, - exceptionParam); - - var createLoggingEvent = - Expression.Lambda>( - newLoggingEventExpression, - instanceParam, - callerStackBoundaryDeclaringTypeParam, - levelParam, - messageParam, - exceptionParam) - .Compile(); - - return createLoggingEvent; - } - - private static Func GetIsEnabledFor(Type loggerType, Type logEventLevelType, - UnaryExpression instanceCast, - UnaryExpression levelCast, - ParameterExpression instanceParam, - ParameterExpression levelParam) - { - MethodInfo isEnabledMethodInfo = loggerType.GetMethodPortable("IsEnabledFor", logEventLevelType); - MethodCallExpression isEnabledMethodCall = Expression.Call(instanceCast, isEnabledMethodInfo, levelCast); - - Func result = - Expression.Lambda>(isEnabledMethodCall, instanceParam, levelParam) - .Compile(); - - return result; - } - - private static Action GetLoggingEventPropertySetter(Type loggingEventType) - { - ParameterExpression loggingEventParameter = Expression.Parameter(typeof(object), "loggingEvent"); - ParameterExpression keyParameter = Expression.Parameter(typeof(string), "key"); - ParameterExpression valueParameter = Expression.Parameter(typeof(object), "value"); - - PropertyInfo propertiesProperty = loggingEventType.GetPropertyPortable("Properties"); - PropertyInfo item = propertiesProperty.PropertyType.GetPropertyPortable("Item"); - - // ((LoggingEvent)loggingEvent).Properties[key] = value; - var body = - Expression.Assign( - Expression.Property( - Expression.Property(Expression.Convert(loggingEventParameter, loggingEventType), - propertiesProperty), item, keyParameter), valueParameter); - - Action result = - Expression.Lambda> - (body, loggingEventParameter, keyParameter, - valueParameter) - .Compile(); - - return result; - } - - public bool Log(LogLevel logLevel, Func messageFunc, Exception exception, params object[] formatParameters) - { - if (messageFunc == null) - { - return IsLogLevelEnable(logLevel); - } - - if (!IsLogLevelEnable(logLevel)) - { - return false; - } - - string message = messageFunc(); - - IEnumerable patternMatches; - - string formattedMessage = - LogMessageFormatter.FormatStructuredMessage(message, - formatParameters, - out patternMatches); - - // determine correct caller - this might change due to jit optimizations with method inlining - if (s_callerStackBoundaryType == null) - { - lock (CallerStackBoundaryTypeSync) - { -#if !LIBLOG_PORTABLE - StackTrace stack = new StackTrace(); - Type thisType = GetType(); - s_callerStackBoundaryType = Type.GetType("LoggerExecutionWrapper"); - for (var i = 1; i < stack.FrameCount; i++) - { - if (!IsInTypeHierarchy(thisType, stack.GetFrame(i).GetMethod().DeclaringType)) - { - s_callerStackBoundaryType = stack.GetFrame(i - 1).GetMethod().DeclaringType; - break; - } - } -#else - s_callerStackBoundaryType = typeof (LoggerExecutionWrapper); -#endif - } - } - - var translatedLevel = TranslateLevel(logLevel); - - object loggingEvent = _createLoggingEvent(_logger, s_callerStackBoundaryType, translatedLevel, formattedMessage, exception); - - PopulateProperties(loggingEvent, patternMatches, formatParameters); - - _logDelegate(_logger, loggingEvent); - - return true; - } - - private void PopulateProperties(object loggingEvent, IEnumerable patternMatches, object[] formatParameters) - { - IEnumerable> keyToValue = - patternMatches.Zip(formatParameters, - (key, value) => new KeyValuePair(key, value)); - - foreach (KeyValuePair keyValuePair in keyToValue) - { - _loggingEventPropertySetter(loggingEvent, keyValuePair.Key, keyValuePair.Value); - } - } - - private static bool IsInTypeHierarchy(Type currentType, Type checkType) - { - while (currentType != null && currentType != typeof(object)) - { - if (currentType == checkType) - { - return true; - } - currentType = currentType.GetBaseTypePortable(); - } - return false; - } - - private bool IsLogLevelEnable(LogLevel logLevel) - { - var level = TranslateLevel(logLevel); - return _isEnabledForDelegate(_logger, level); - } - - private object TranslateLevel(LogLevel logLevel) - { - switch (logLevel) - { - case LogLevel.Trace: - case LogLevel.Debug: - return _levelDebug; - case LogLevel.Info: - return _levelInfo; - case LogLevel.Warn: - return _levelWarn; - case LogLevel.Error: - return _levelError; - case LogLevel.Fatal: - return _levelFatal; - default: - throw new ArgumentOutOfRangeException("logLevel", logLevel, null); - } - } - } - } - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal class EntLibLogProvider : LogProviderBase - { - private const string TypeTemplate = "Microsoft.Practices.EnterpriseLibrary.Logging.{0}, Microsoft.Practices.EnterpriseLibrary.Logging"; - private static bool s_providerIsAvailableOverride = true; - private static readonly Type LogEntryType; - private static readonly Type LoggerType; - private static readonly Type TraceEventTypeType; - private static readonly Action WriteLogEntry; - private static readonly Func ShouldLogEntry; - - [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] - static EntLibLogProvider() - { - LogEntryType = Type.GetType(string.Format(CultureInfo.InvariantCulture, TypeTemplate, "LogEntry")); - LoggerType = Type.GetType(string.Format(CultureInfo.InvariantCulture, TypeTemplate, "Logger")); - TraceEventTypeType = TraceEventTypeValues.Type; - if (LogEntryType == null - || TraceEventTypeType == null - || LoggerType == null) - { - return; - } - WriteLogEntry = GetWriteLogEntry(); - ShouldLogEntry = GetShouldLogEntry(); - } - - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "EnterpriseLibrary")] - public EntLibLogProvider() - { - if (!IsLoggerAvailable()) - { - throw new InvalidOperationException("Microsoft.Practices.EnterpriseLibrary.Logging.Logger not found"); - } - } - - public static bool ProviderIsAvailableOverride - { - get { return s_providerIsAvailableOverride; } - set { s_providerIsAvailableOverride = value; } - } - - public override Logger GetLogger(string name) - { - return new EntLibLogger(name, WriteLogEntry, ShouldLogEntry).Log; - } - - internal static bool IsLoggerAvailable() - { - return ProviderIsAvailableOverride - && TraceEventTypeType != null - && LogEntryType != null; - } - - private static Action GetWriteLogEntry() - { - // new LogEntry(...) - var logNameParameter = Expression.Parameter(typeof(string), "logName"); - var messageParameter = Expression.Parameter(typeof(string), "message"); - var severityParameter = Expression.Parameter(typeof(int), "severity"); - - MemberInitExpression memberInit = GetWriteLogExpression( - messageParameter, - Expression.Convert(severityParameter, TraceEventTypeType), - logNameParameter); - - //Logger.Write(new LogEntry(....)); - MethodInfo writeLogEntryMethod = LoggerType.GetMethodPortable("Write", LogEntryType); - var writeLogEntryExpression = Expression.Call(writeLogEntryMethod, memberInit); - - return Expression.Lambda>( - writeLogEntryExpression, - logNameParameter, - messageParameter, - severityParameter).Compile(); - } - - private static Func GetShouldLogEntry() - { - // new LogEntry(...) - var logNameParameter = Expression.Parameter(typeof(string), "logName"); - var severityParameter = Expression.Parameter(typeof(int), "severity"); - - MemberInitExpression memberInit = GetWriteLogExpression( - Expression.Constant("***dummy***"), - Expression.Convert(severityParameter, TraceEventTypeType), - logNameParameter); - - //Logger.Write(new LogEntry(....)); - MethodInfo writeLogEntryMethod = LoggerType.GetMethodPortable("ShouldLog", LogEntryType); - var writeLogEntryExpression = Expression.Call(writeLogEntryMethod, memberInit); - - return Expression.Lambda>( - writeLogEntryExpression, - logNameParameter, - severityParameter).Compile(); - } - - private static MemberInitExpression GetWriteLogExpression(Expression message, - Expression severityParameter, ParameterExpression logNameParameter) - { - var entryType = LogEntryType; - MemberInitExpression memberInit = Expression.MemberInit(Expression.New(entryType), - Expression.Bind(entryType.GetPropertyPortable("Message"), message), - Expression.Bind(entryType.GetPropertyPortable("Severity"), severityParameter), - Expression.Bind( - entryType.GetPropertyPortable("TimeStamp"), - Expression.Property(null, typeof(DateTime).GetPropertyPortable("UtcNow"))), - Expression.Bind( - entryType.GetPropertyPortable("Categories"), - Expression.ListInit( - Expression.New(typeof(List)), - typeof(List).GetMethodPortable("Add", typeof(string)), - logNameParameter))); - return memberInit; - } - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal class EntLibLogger - { - private readonly string _loggerName; - private readonly Action _writeLog; - private readonly Func _shouldLog; - - internal EntLibLogger(string loggerName, Action writeLog, Func shouldLog) - { - _loggerName = loggerName; - _writeLog = writeLog; - _shouldLog = shouldLog; - } - - public bool Log(LogLevel logLevel, Func messageFunc, Exception exception, params object[] formatParameters) - { - var severity = MapSeverity(logLevel); - if (messageFunc == null) - { - return _shouldLog(_loggerName, severity); - } - - - messageFunc = LogMessageFormatter.SimulateStructuredLogging(messageFunc, formatParameters); - if (exception != null) - { - return LogException(logLevel, messageFunc, exception); - } - _writeLog(_loggerName, messageFunc(), severity); - return true; - } - - public bool LogException(LogLevel logLevel, Func messageFunc, Exception exception) - { - var severity = MapSeverity(logLevel); - var message = messageFunc() + Environment.NewLine + exception; - _writeLog(_loggerName, message, severity); - return true; - } - - private static int MapSeverity(LogLevel logLevel) - { - switch (logLevel) - { - case LogLevel.Fatal: - return TraceEventTypeValues.Critical; - case LogLevel.Error: - return TraceEventTypeValues.Error; - case LogLevel.Warn: - return TraceEventTypeValues.Warning; - case LogLevel.Info: - return TraceEventTypeValues.Information; - default: - return TraceEventTypeValues.Verbose; - } - } - } - } - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal class SerilogLogProvider : LogProviderBase - { - private readonly Func _getLoggerByNameDelegate; - private static bool s_providerIsAvailableOverride = true; - private static Func _pushProperty; - - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "Serilog")] - public SerilogLogProvider() - { - if (!IsLoggerAvailable()) - { - throw new InvalidOperationException("Serilog.Log not found"); - } - _getLoggerByNameDelegate = GetForContextMethodCall(); - _pushProperty = GetPushProperty(); - } - - public static bool ProviderIsAvailableOverride - { - get { return s_providerIsAvailableOverride; } - set { s_providerIsAvailableOverride = value; } - } - - public override Logger GetLogger(string name) - { - return new SerilogLogger(_getLoggerByNameDelegate(name)).Log; - } - - internal static bool IsLoggerAvailable() - { - return ProviderIsAvailableOverride && GetLogManagerType() != null; - } - - protected override OpenNdc GetOpenNdcMethod() - { - return message => _pushProperty("NDC", message); - } - - protected override OpenMdc GetOpenMdcMethod() - { - return (key, value) => _pushProperty(key, value); - } - - private static Func GetPushProperty() - { - Type ndcContextType = Type.GetType("Serilog.Context.LogContext, Serilog") ?? - Type.GetType("Serilog.Context.LogContext, Serilog.FullNetFx"); - - MethodInfo pushPropertyMethod = ndcContextType.GetMethodPortable( - "PushProperty", - typeof(string), - typeof(object), - typeof(bool)); - - ParameterExpression nameParam = Expression.Parameter(typeof(string), "name"); - ParameterExpression valueParam = Expression.Parameter(typeof(object), "value"); - ParameterExpression destructureObjectParam = Expression.Parameter(typeof(bool), "destructureObjects"); - MethodCallExpression pushPropertyMethodCall = Expression - .Call(null, pushPropertyMethod, nameParam, valueParam, destructureObjectParam); - var pushProperty = Expression - .Lambda>( - pushPropertyMethodCall, - nameParam, - valueParam, - destructureObjectParam) - .Compile(); - - return (key, value) => pushProperty(key, value, false); - } - - private static Type GetLogManagerType() - { - return Type.GetType("Serilog.Log, Serilog"); - } - - private static Func GetForContextMethodCall() - { - Type logManagerType = GetLogManagerType(); - MethodInfo method = logManagerType.GetMethodPortable("ForContext", typeof(string), typeof(object), typeof(bool)); - ParameterExpression propertyNameParam = Expression.Parameter(typeof(string), "propertyName"); - ParameterExpression valueParam = Expression.Parameter(typeof(object), "value"); - ParameterExpression destructureObjectsParam = Expression.Parameter(typeof(bool), "destructureObjects"); - MethodCallExpression methodCall = Expression.Call(null, method, new Expression[] - { - propertyNameParam, - valueParam, - destructureObjectsParam - }); - var func = Expression.Lambda>( - methodCall, - propertyNameParam, - valueParam, - destructureObjectsParam) - .Compile(); - return name => func("SourceContext", name, false); - } - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal class SerilogLogger - { - private readonly object _logger; - private static readonly object DebugLevel; - private static readonly object ErrorLevel; - private static readonly object FatalLevel; - private static readonly object InformationLevel; - private static readonly object VerboseLevel; - private static readonly object WarningLevel; - private static readonly Func IsEnabled; - private static readonly Action Write; - private static readonly Action WriteException; - - [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] - [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "ILogger")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "LogEventLevel")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "Serilog")] - static SerilogLogger() - { - var logEventLevelType = Type.GetType("Serilog.Events.LogEventLevel, Serilog"); - if (logEventLevelType == null) - { - throw new InvalidOperationException("Type Serilog.Events.LogEventLevel was not found."); - } - DebugLevel = Enum.Parse(logEventLevelType, "Debug", false); - ErrorLevel = Enum.Parse(logEventLevelType, "Error", false); - FatalLevel = Enum.Parse(logEventLevelType, "Fatal", false); - InformationLevel = Enum.Parse(logEventLevelType, "Information", false); - VerboseLevel = Enum.Parse(logEventLevelType, "Verbose", false); - WarningLevel = Enum.Parse(logEventLevelType, "Warning", false); - - // Func isEnabled = (logger, level) => { return ((SeriLog.ILogger)logger).IsEnabled(level); } - var loggerType = Type.GetType("Serilog.ILogger, Serilog"); - if (loggerType == null) - { - throw new InvalidOperationException("Type Serilog.ILogger was not found."); - } - MethodInfo isEnabledMethodInfo = loggerType.GetMethodPortable("IsEnabled", logEventLevelType); - ParameterExpression instanceParam = Expression.Parameter(typeof(object)); - UnaryExpression instanceCast = Expression.Convert(instanceParam, loggerType); - ParameterExpression levelParam = Expression.Parameter(typeof(object)); - UnaryExpression levelCast = Expression.Convert(levelParam, logEventLevelType); - MethodCallExpression isEnabledMethodCall = Expression.Call(instanceCast, isEnabledMethodInfo, levelCast); - IsEnabled = Expression.Lambda>(isEnabledMethodCall, instanceParam, levelParam).Compile(); - - // Action Write = - // (logger, level, message, params) => { ((SeriLog.ILoggerILogger)logger).Write(level, message, params); } - MethodInfo writeMethodInfo = loggerType.GetMethodPortable("Write", logEventLevelType, typeof(string), typeof(object[])); - ParameterExpression messageParam = Expression.Parameter(typeof(string)); - ParameterExpression propertyValuesParam = Expression.Parameter(typeof(object[])); - MethodCallExpression writeMethodExp = Expression.Call( - instanceCast, - writeMethodInfo, - levelCast, - messageParam, - propertyValuesParam); - var expression = Expression.Lambda>( - writeMethodExp, - instanceParam, - levelParam, - messageParam, - propertyValuesParam); - Write = expression.Compile(); - - // Action WriteException = - // (logger, level, exception, message) => { ((ILogger)logger).Write(level, exception, message, new object[]); } - MethodInfo writeExceptionMethodInfo = loggerType.GetMethodPortable("Write", - logEventLevelType, - typeof(Exception), - typeof(string), - typeof(object[])); - ParameterExpression exceptionParam = Expression.Parameter(typeof(Exception)); - writeMethodExp = Expression.Call( - instanceCast, - writeExceptionMethodInfo, - levelCast, - exceptionParam, - messageParam, - propertyValuesParam); - WriteException = Expression.Lambda>( - writeMethodExp, - instanceParam, - levelParam, - exceptionParam, - messageParam, - propertyValuesParam).Compile(); - } - - internal SerilogLogger(object logger) - { - _logger = logger; - } - - public bool Log(LogLevel logLevel, Func messageFunc, Exception exception, params object[] formatParameters) - { - var translatedLevel = TranslateLevel(logLevel); - if (messageFunc == null) - { - return IsEnabled(_logger, translatedLevel); - } - - if (!IsEnabled(_logger, translatedLevel)) - { - return false; - } - - if (exception != null) - { - LogException(translatedLevel, messageFunc, exception, formatParameters); - } - else - { - LogMessage(translatedLevel, messageFunc, formatParameters); - } - - return true; - } - - private void LogMessage(object translatedLevel, Func messageFunc, object[] formatParameters) - { - Write(_logger, translatedLevel, messageFunc(), formatParameters); - } - - private void LogException(object logLevel, Func messageFunc, Exception exception, object[] formatParams) - { - WriteException(_logger, logLevel, exception, messageFunc(), formatParams); - } - - private static object TranslateLevel(LogLevel logLevel) - { - switch (logLevel) - { - case LogLevel.Fatal: - return FatalLevel; - case LogLevel.Error: - return ErrorLevel; - case LogLevel.Warn: - return WarningLevel; - case LogLevel.Info: - return InformationLevel; - case LogLevel.Trace: - return VerboseLevel; - default: - return DebugLevel; - } - } - } - } - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal class LoupeLogProvider : LogProviderBase - { - /// - /// The form of the Loupe Log.Write method we're using - /// - internal delegate void WriteDelegate( - int severity, - string logSystem, - int skipFrames, - Exception exception, - bool attributeToException, - int writeMode, - string detailsXml, - string category, - string caption, - string description, - params object[] args - ); - - private static bool s_providerIsAvailableOverride = true; - private readonly WriteDelegate _logWriteDelegate; - - public LoupeLogProvider() - { - if (!IsLoggerAvailable()) - { - throw new InvalidOperationException("Gibraltar.Agent.Log (Loupe) not found"); - } - - _logWriteDelegate = GetLogWriteDelegate(); - } - - /// - /// Gets or sets a value indicating whether [provider is available override]. Used in tests. - /// - /// - /// true if [provider is available override]; otherwise, false. - /// - public static bool ProviderIsAvailableOverride - { - get { return s_providerIsAvailableOverride; } - set { s_providerIsAvailableOverride = value; } - } - - public override Logger GetLogger(string name) - { - return new LoupeLogger(name, _logWriteDelegate).Log; - } - - public static bool IsLoggerAvailable() - { - return ProviderIsAvailableOverride && GetLogManagerType() != null; - } - - private static Type GetLogManagerType() - { - return Type.GetType("Gibraltar.Agent.Log, Gibraltar.Agent"); - } - - private static WriteDelegate GetLogWriteDelegate() - { - Type logManagerType = GetLogManagerType(); - Type logMessageSeverityType = Type.GetType("Gibraltar.Agent.LogMessageSeverity, Gibraltar.Agent"); - Type logWriteModeType = Type.GetType("Gibraltar.Agent.LogWriteMode, Gibraltar.Agent"); - - MethodInfo method = logManagerType.GetMethodPortable( - "Write", - logMessageSeverityType, typeof(string), typeof(int), typeof(Exception), typeof(bool), - logWriteModeType, typeof(string), typeof(string), typeof(string), typeof(string), typeof(object[])); - - var callDelegate = (WriteDelegate)method.CreateDelegate(typeof(WriteDelegate)); - return callDelegate; - } - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal class LoupeLogger - { - private const string LogSystem = "LibLog"; - - private readonly string _category; - private readonly WriteDelegate _logWriteDelegate; - private readonly int _skipLevel; - - internal LoupeLogger(string category, WriteDelegate logWriteDelegate) - { - _category = category; - _logWriteDelegate = logWriteDelegate; -#if DEBUG - _skipLevel = 2; -#else - _skipLevel = 1; -#endif - } - - public bool Log(LogLevel logLevel, Func messageFunc, Exception exception, params object[] formatParameters) - { - if (messageFunc == null) - { - //nothing to log.. - return true; - } - - messageFunc = LogMessageFormatter.SimulateStructuredLogging(messageFunc, formatParameters); - - _logWriteDelegate(ToLogMessageSeverity(logLevel), LogSystem, _skipLevel, exception, true, 0, null, - _category, null, messageFunc.Invoke()); - - return true; - } - - private static int ToLogMessageSeverity(LogLevel logLevel) - { - switch (logLevel) - { - case LogLevel.Trace: - return TraceEventTypeValues.Verbose; - case LogLevel.Debug: - return TraceEventTypeValues.Verbose; - case LogLevel.Info: - return TraceEventTypeValues.Information; - case LogLevel.Warn: - return TraceEventTypeValues.Warning; - case LogLevel.Error: - return TraceEventTypeValues.Error; - case LogLevel.Fatal: - return TraceEventTypeValues.Critical; - default: - throw new ArgumentOutOfRangeException("logLevel"); - } - } - } - } - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal static class TraceEventTypeValues - { - internal static readonly Type Type; - internal static readonly int Verbose; - internal static readonly int Information; - internal static readonly int Warning; - internal static readonly int Error; - internal static readonly int Critical; - - [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] - static TraceEventTypeValues() - { - var assembly = typeof(Uri).GetAssemblyPortable(); // This is to get to the System.dll assembly in a PCL compatible way. - if (assembly == null) - { - return; - } - Type = assembly.GetType("System.Diagnostics.TraceEventType"); - if (Type == null) return; - Verbose = (int)Enum.Parse(Type, "Verbose", false); - Information = (int)Enum.Parse(Type, "Information", false); - Warning = (int)Enum.Parse(Type, "Warning", false); - Error = (int)Enum.Parse(Type, "Error", false); - Critical = (int)Enum.Parse(Type, "Critical", false); - } - } - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal static class LogMessageFormatter - { - //private static readonly Regex Pattern = new Regex(@"\{@?\w{1,}\}"); -#if LIBLOG_PORTABLE - private static readonly Regex Pattern = new Regex(@"(?[^\d{][^ }]*)}"); -#else - private static readonly Regex Pattern = new Regex(@"(?[^ :{}]+)(?:[^}]+)?}", RegexOptions.Compiled); -#endif - - /// - /// Some logging frameworks support structured logging, such as serilog. This will allow you to add names to structured data in a format string: - /// For example: Log("Log message to {user}", user). This only works with serilog, but as the user of LibLog, you don't know if serilog is actually - /// used. So, this class simulates that. it will replace any text in {curly braces} with an index number. - /// - /// "Log {message} to {user}" would turn into => "Log {0} to {1}". Then the format parameters are handled using regular .net string.Format. - /// - /// The message builder. - /// The format parameters. - /// - public static Func SimulateStructuredLogging(Func messageBuilder, object[] formatParameters) - { - if (formatParameters == null || formatParameters.Length == 0) - { - return messageBuilder; - } - - return () => - { - string targetMessage = messageBuilder(); - IEnumerable patternMatches; - return FormatStructuredMessage(targetMessage, formatParameters, out patternMatches); - }; - } - - private static string ReplaceFirst(string text, string search, string replace) - { - int pos = text.IndexOf(search, StringComparison.Ordinal); - if (pos < 0) - { - return text; - } - return text.Substring(0, pos) + replace + text.Substring(pos + search.Length); - } - - public static string FormatStructuredMessage(string targetMessage, object[] formatParameters, out IEnumerable patternMatches) - { - if (formatParameters.Length == 0) - { - patternMatches = Enumerable.Empty(); - return targetMessage; - } - - List processedArguments = new List(); - patternMatches = processedArguments; - - foreach (Match match in Pattern.Matches(targetMessage)) - { - var arg = match.Groups["arg"].Value; - - int notUsed; - if (!int.TryParse(arg, out notUsed)) - { - int argumentIndex = processedArguments.IndexOf(arg); - if (argumentIndex == -1) - { - argumentIndex = processedArguments.Count; - processedArguments.Add(arg); - } - - targetMessage = ReplaceFirst(targetMessage, match.Value, - "{" + argumentIndex + match.Groups["format"].Value + "}"); - } - } - try - { - return string.Format(CultureInfo.InvariantCulture, targetMessage, formatParameters); - } - catch (FormatException ex) - { - throw new FormatException("The input string '" + targetMessage + "' could not be formatted using string.Format", ex); - } - } - } - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal static class TypeExtensions - { - internal static ConstructorInfo GetConstructorPortable(this Type type, params Type[] types) - { -#if LIBLOG_PORTABLE - return type.GetTypeInfo().DeclaredConstructors.FirstOrDefault - (constructor => - constructor.GetParameters() - .Select(parameter => parameter.ParameterType) - .SequenceEqual(types)); -#else - return type.GetConstructor(types); -#endif - } - - internal static MethodInfo GetMethodPortable(this Type type, string name) - { -#if LIBLOG_PORTABLE - return type.GetRuntimeMethods().SingleOrDefault(m => m.Name == name); -#else - return type.GetMethod(name); -#endif - } - - internal static MethodInfo GetMethodPortable(this Type type, string name, params Type[] types) - { -#if LIBLOG_PORTABLE - return type.GetRuntimeMethod(name, types); -#else - return type.GetMethod(name, types); -#endif - } - - internal static PropertyInfo GetPropertyPortable(this Type type, string name) - { -#if LIBLOG_PORTABLE - return type.GetRuntimeProperty(name); -#else - return type.GetProperty(name); -#endif - } - - internal static IEnumerable GetFieldsPortable(this Type type) - { -#if LIBLOG_PORTABLE - return type.GetRuntimeFields(); -#else - return type.GetFields(); -#endif - } - - internal static Type GetBaseTypePortable(this Type type) - { -#if LIBLOG_PORTABLE - return type.GetTypeInfo().BaseType; -#else - return type.BaseType; -#endif - } - -#if LIBLOG_PORTABLE - internal static MethodInfo GetGetMethod(this PropertyInfo propertyInfo) - { - return propertyInfo.GetMethod; - } - - internal static MethodInfo GetSetMethod(this PropertyInfo propertyInfo) - { - return propertyInfo.SetMethod; - } -#endif - -#if !LIBLOG_PORTABLE - internal static object CreateDelegate(this MethodInfo methodInfo, Type delegateType) - { - return Delegate.CreateDelegate(delegateType, methodInfo); - } -#endif - - internal static Assembly GetAssemblyPortable(this Type type) - { -#if LIBLOG_PORTABLE - return type.GetTypeInfo().Assembly; -#else - return type.Assembly; -#endif - } - } - -#if !LIBLOG_PORTABLE - [ExcludeFromCodeCoverage] -#endif - internal class DisposableAction : IDisposable - { - private readonly Action _onDispose; - - public DisposableAction(Action onDispose = null) - { - _onDispose = onDispose; - } - - public void Dispose() - { - if (_onDispose != null) - { - _onDispose(); - } - } - } -} \ No newline at end of file diff --git a/src/Anywhere.ArcGIS/ArcGISOnlineAppLoginOAuthProvider.cs b/src/Anywhere.ArcGIS/ArcGISOnlineAppLoginOAuthProvider.cs index 6aa33fc..841f740 100644 --- a/src/Anywhere.ArcGIS/ArcGISOnlineAppLoginOAuthProvider.cs +++ b/src/Anywhere.ArcGIS/ArcGISOnlineAppLoginOAuthProvider.cs @@ -39,9 +39,7 @@ internal ArcGISOnlineAppLoginOAuthProvider(Func log, string clientId, stri throw new ArgumentNullException(nameof(clientSecret), "clientSecret is null."); } - Serializer = serializer ?? SerializerFactory.Get(); - LiteGuard.Guard.AgainstNullArgument(nameof(Serializer), Serializer); - + Serializer = serializer ?? SerializerFactory.Get(); OAuthRequest = new GenerateOAuthToken(clientId, clientSecret); _httpClient = HttpClientFactory.Get(); diff --git a/src/Anywhere.ArcGIS/AttachmentWorker.cs b/src/Anywhere.ArcGIS/AttachmentWorker.cs index 1f275a0..417b25e 100644 --- a/src/Anywhere.ArcGIS/AttachmentWorker.cs +++ b/src/Anywhere.ArcGIS/AttachmentWorker.cs @@ -35,7 +35,6 @@ public AttachmentWorker(string rootUrl, ISerializer serializer = null, ITokenPro RootUrl = rootUrl.AsRootUrl(); TokenProvider = tokenProvider; Serializer = serializer ?? SerializerFactory.Get(); - LiteGuard.Guard.AgainstNullArgument(nameof(Serializer), Serializer); var httpFunc = httpClientFunc ?? HttpClientFactory.Get; _httpClient = httpFunc(); @@ -105,8 +104,15 @@ protected async Task Post(TRequest requestObject, CancellationTo where TRequest : ArcGISServerOperation, IAttachment where T : IPortalResponse { - LiteGuard.Guard.AgainstNullArgument(nameof(requestObject), requestObject); - LiteGuard.Guard.AgainstNullArgumentProperty(nameof(requestObject), nameof(requestObject.Endpoint), requestObject.Endpoint); + if (requestObject == null) + { + throw new ArgumentNullException(nameof(requestObject)); + } + + if (requestObject.Endpoint == null) + { + throw new ArgumentNullException(nameof(requestObject.Endpoint)); + } requestObject.BeforeRequest?.Invoke(); diff --git a/src/Anywhere.ArcGIS/Common/Feature.cs b/src/Anywhere.ArcGIS/Common/Feature.cs index 38cfd9d..caafa02 100644 --- a/src/Anywhere.ArcGIS/Common/Feature.cs +++ b/src/Anywhere.ArcGIS/Common/Feature.cs @@ -15,12 +15,40 @@ public class Feature : IEquatable> where T : IGeometry { const string ObjectIDName = "objectid"; const string GlobalIDName = "globalid"; + readonly string _idFieldName; public Feature() { Attributes = new Dictionary(); } + /// + /// Creates a feature that has the UniqueID field name set + /// + /// Name of the field to use to return the Id of the feature. Used when ObjectId is not on the layer e.g. query layer uses ESRI_OID + public Feature(string idFieldName) + : this() + { + _idFieldName = idFieldName; + } + + /// + /// Create a new feature from an existing one using that has the UniqueID field name set + /// + /// Feature that you want to copy. + /// Name of the field to use to return the Id of the feature. Used when ObjectId is not on the layer e.g. query layer uses ESRI_OID + public Feature(Feature featureToCopy, string idFieldName) + { + if (featureToCopy == null) + { + throw new ArgumentNullException(nameof(featureToCopy)); + } + + _idFieldName = idFieldName; + Attributes = new Dictionary(featureToCopy.Attributes); + Geometry = (T) featureToCopy.Geometry?.Clone(); + } + [DataMember(Name = "geometry")] public T Geometry { get; set; } @@ -44,7 +72,10 @@ public long ObjectID if (Attributes != null && Attributes.Any() && _oid == 0) { var copy = new Dictionary(Attributes, StringComparer.OrdinalIgnoreCase); - if (copy.ContainsKey(ObjectIDName)) long.TryParse(copy[ObjectIDName].ToString(), out _oid); + if (copy.ContainsKey(ObjectIDName)) + { + long.TryParse(copy[ObjectIDName].ToString(), out _oid); + } } return _oid; @@ -62,24 +93,83 @@ public Guid GlobalID if (Attributes != null && Attributes.Any() && _globalID == Guid.Empty) { var copy = new Dictionary(Attributes, StringComparer.OrdinalIgnoreCase); - if (copy.ContainsKey(GlobalIDName)) Guid.TryParse(copy[GlobalIDName].ToString(), out _globalID); + if (copy.ContainsKey(GlobalIDName)) + { + Guid.TryParse(copy[GlobalIDName].ToString(), out _globalID); + } } return _globalID; } } + long _id = 0; + /// + /// Get the UniqueID for the feature when the layer doesn't contain an ObjectID. + /// Will return 0 if not found or if the id field name is not set + /// + public long UniqueID + { + get + { + if (!string.IsNullOrWhiteSpace(_idFieldName) && Attributes != null && Attributes.Any() && _id == 0) + { + var copy = new Dictionary(Attributes, StringComparer.OrdinalIgnoreCase); + if (copy.ContainsKey(_idFieldName)) + { + long.TryParse(copy[_idFieldName].ToString(), out _id); + } + } + + return _id; + } + } + + /// + /// Get the value for an attribute + /// + /// The attribute name that you want the value of for the feature + /// The value of the attribute or null if not found + /// Case insensitive + public object AttributeValue(string attributeName) + { + if (string.IsNullOrWhiteSpace(attributeName) || Attributes == null || !Attributes.Any()) + { + return null; + } + + object result = null; + var copy = new Dictionary(Attributes, StringComparer.OrdinalIgnoreCase); + if (copy.ContainsKey(attributeName)) + { + result = copy[attributeName]; + } + + return result; + } + public bool AttributesAreTheSame(Feature other) { - if (other == null || other.Attributes == null || Attributes == null || !Attributes.Any()) return false; + if (other == null || other.Attributes == null || Attributes == null || !Attributes.Any()) + { + return false; + } return (Attributes.Count == other.Attributes.Count) && !(Attributes.Except(other.Attributes)).Any(); } public bool Equals(Feature other) { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; + if (ReferenceEquals(null, other)) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + return EqualityComparer.Default.Equals(Geometry, other.Geometry) && AttributesAreTheSame(other); } @@ -87,14 +177,23 @@ public override int GetHashCode() { unchecked { - return (EqualityComparer.Default.GetHashCode(Geometry) * 397) ^ (Attributes != null ? Attributes.GetHashCode() : 0); + return (EqualityComparer.Default.GetHashCode(Geometry) * 397) + ^ (Attributes != null ? Attributes.GetHashCode() : 0); } } public override bool Equals(object obj) { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; + if (ReferenceEquals(null, obj)) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + var other = obj as Feature; return other != null && Equals(other); } diff --git a/src/Anywhere.ArcGIS/Common/IGeometry.cs b/src/Anywhere.ArcGIS/Common/IGeometry.cs index 0f5ddf0..0cb31b8 100644 --- a/src/Anywhere.ArcGIS/Common/IGeometry.cs +++ b/src/Anywhere.ArcGIS/Common/IGeometry.cs @@ -15,7 +15,7 @@ namespace Anywhere.ArcGIS.Common /// Envelopes /// /// Starting at ArcGIS Server 10.1, geometries containing m and z values are supported - public interface IGeometry + public interface IGeometry : ICloneable { /// /// The spatial reference can be defined using a well-known ID (wkid) or well-known text (wkt) @@ -46,7 +46,7 @@ public interface IGeometry /// Spatial reference used for operations. If WKT is set then other properties are nulled /// [DataContract] - public class SpatialReference : IEquatable + public class SpatialReference : IEquatable, ICloneable { /// /// World Geodetic System 1984 (WGS84) @@ -136,6 +136,18 @@ public override int GetHashCode() return hashCode; } } + + public object Clone() + { + return new SpatialReference + { + LatestVCSWkid = LatestVCSWkid, + LatestWkid = LatestWkid, + VCSWkid = VCSWkid, + Wkid = Wkid, + Wkt = string.IsNullOrWhiteSpace(Wkt) ? null : string.Copy(Wkt) + }; + } } [DataContract] @@ -198,6 +210,18 @@ public IGeoJsonGeometry ToGeoJson() { return new GeoJsonPoint { Type = "Point", Coordinates = new[] { X, Y } }; } + + public object Clone() + { + return new Point + { + X = X, + Y = Y, + M = M, + Z = Z, + SpatialReference = (SpatialReference) SpatialReference?.Clone() + }; + } } [DataContract] @@ -256,6 +280,17 @@ public IGeoJsonGeometry ToGeoJson() { return new GeoJsonLineString { Type = "MultiPoint", Coordinates = Points }; } + + public object Clone() + { + return new MultiPoint + { + HasM = HasM, + HasZ = HasZ, + Points = (PointCollection) Points?.Clone(), + SpatialReference = (SpatialReference) SpatialReference?.Clone() + }; + } } [DataContract] @@ -324,6 +359,17 @@ public IGeoJsonGeometry ToGeoJson() { return Paths.Any() ? new GeoJsonLineString { Type = "LineString", Coordinates = Paths.First() } : null; } + + public object Clone() + { + return new Polyline + { + HasM = HasM, + HasZ = HasZ, + Paths = Paths?.Clone(), + SpatialReference = (SpatialReference) SpatialReference?.Clone() + }; + } } public class PointCollection : List @@ -356,10 +402,19 @@ public List Points get { return this.Select(point => point != null ? new Point { X = point.First(), Y = point.Last() } : null).ToList(); } } + public List Clone() + { + return Points.Select(x => new double[] { x.X, x.Y }).ToList(); + } } public class PointCollectionList : List - { } + { + public PointCollectionList Clone() + { + return this; + } + } [DataContract] public class Polygon : IGeometry, IEquatable @@ -427,6 +482,17 @@ public IGeoJsonGeometry ToGeoJson() { return new GeoJsonPolygon { Type = "Polygon", Coordinates = Rings }; } + + public object Clone() + { + return new Polygon + { + HasM = HasM, + HasZ = HasZ, + Rings = Rings?.Clone(), + SpatialReference = (SpatialReference) SpatialReference?.Clone() + }; + } } [DataContract] @@ -541,5 +607,17 @@ public IGeoJsonGeometry ToGeoJson() } }; } + + public object Clone() + { + return new Extent + { + XMax = XMax, + XMin = XMin, + YMax = YMax, + YMin = YMin, + SpatialReference = (SpatialReference) SpatialReference?.Clone() + }; + } } } diff --git a/src/Anywhere.ArcGIS/CryptoProviderFactory.cs b/src/Anywhere.ArcGIS/CryptoProviderFactory.cs index 1514cdb..8108f3b 100644 --- a/src/Anywhere.ArcGIS/CryptoProviderFactory.cs +++ b/src/Anywhere.ArcGIS/CryptoProviderFactory.cs @@ -19,9 +19,20 @@ public class RsaEncrypter : ICryptoProvider { public Operation.GenerateToken Encrypt(Operation.GenerateToken tokenRequest, byte[] exponent, byte[] modulus) { - LiteGuard.Guard.AgainstNullArgument(nameof(tokenRequest), tokenRequest); - LiteGuard.Guard.AgainstNullArgument(nameof(exponent), exponent); - LiteGuard.Guard.AgainstNullArgument(nameof(modulus), modulus); + if (tokenRequest == null) + { + throw new ArgumentNullException(nameof(tokenRequest)); + } + + if (exponent == null) + { + throw new ArgumentNullException(nameof(exponent)); + } + + if (modulus == null) + { + throw new ArgumentNullException(nameof(modulus)); + } if (tokenRequest.Encrypted == true) { diff --git a/src/Anywhere.ArcGIS/FederatedTokenProvider.cs b/src/Anywhere.ArcGIS/FederatedTokenProvider.cs index 9bab1a0..257d376 100644 --- a/src/Anywhere.ArcGIS/FederatedTokenProvider.cs +++ b/src/Anywhere.ArcGIS/FederatedTokenProvider.cs @@ -32,12 +32,22 @@ public FederatedTokenProvider(ITokenProvider tokenProvider, string rootUrl, stri internal FederatedTokenProvider(Func log, ITokenProvider tokenProvider, string rootUrl, string serverUrl, ISerializer serializer = null, string referer = null) { - LiteGuard.Guard.AgainstNullArgument(nameof(tokenProvider), tokenProvider); - if (string.IsNullOrWhiteSpace(rootUrl)) throw new ArgumentNullException(nameof(rootUrl), "rootUrl is null."); - if (string.IsNullOrWhiteSpace(serverUrl)) throw new ArgumentNullException(nameof(serverUrl), "serverUrl is null."); + if (tokenProvider == null) + { + throw new ArgumentNullException(nameof(tokenProvider)); + } + + if (string.IsNullOrWhiteSpace(rootUrl)) + { + throw new ArgumentNullException(nameof(rootUrl), "rootUrl is null."); + } + + if (string.IsNullOrWhiteSpace(serverUrl)) + { + throw new ArgumentNullException(nameof(serverUrl), "serverUrl is null."); + } Serializer = serializer ?? SerializerFactory.Get(); - LiteGuard.Guard.AgainstNullArgument(nameof(Serializer), Serializer); RootUrl = rootUrl.AsRootUrl(); _httpClient = HttpClientFactory.Get(); diff --git a/src/Anywhere.ArcGIS/Operation/ArcGISServerOperation.cs b/src/Anywhere.ArcGIS/Operation/ArcGISServerOperation.cs index c0c1856..052e7fc 100644 --- a/src/Anywhere.ArcGIS/Operation/ArcGISServerOperation.cs +++ b/src/Anywhere.ArcGIS/Operation/ArcGISServerOperation.cs @@ -11,9 +11,7 @@ public class ArcGISServerOperation : CommonParameters, IHttpOperation { public ArcGISServerOperation(IEndpoint endpoint, Action beforeRequest = null, Action afterRequest = null) { - LiteGuard.Guard.AgainstNullArgument(nameof(endpoint), endpoint); - - Endpoint = endpoint; + Endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint)); BeforeRequest = beforeRequest; AfterRequest = afterRequest; } diff --git a/src/Anywhere.ArcGIS/Operation/CustomGeocode.cs b/src/Anywhere.ArcGIS/Operation/CustomGeocode.cs index 2a39279..a566c25 100644 --- a/src/Anywhere.ArcGIS/Operation/CustomGeocode.cs +++ b/src/Anywhere.ArcGIS/Operation/CustomGeocode.cs @@ -20,9 +20,10 @@ public SingleInputCustomGeocode(ArcGISServerEndpoint endpoint, Action beforeRequ { } /// - /// Specifies the location to be searched for. + /// Specifies the location to be geocoded. This can be a street address, place-name, postal code, or POI. + /// The input address components need to be formatted as a single string /// - [DataMember(Name = "text")] + [DataMember(Name = "singleLine")] public string Text { get; set; } /// @@ -75,5 +76,8 @@ public class Candidate [DataMember(Name = "attributes")] public Dictionary Attributes { get; set; } + + [DataMember(Name = "extent")] + public Extent Extent { get; set; } } } diff --git a/src/Anywhere.ArcGIS/Operation/ServiceDescriptionDetails.cs b/src/Anywhere.ArcGIS/Operation/ServiceDescriptionDetails.cs index 446bbb5..5ac4518 100644 --- a/src/Anywhere.ArcGIS/Operation/ServiceDescriptionDetails.cs +++ b/src/Anywhere.ArcGIS/Operation/ServiceDescriptionDetails.cs @@ -19,7 +19,10 @@ public class ServiceDescriptionDetails : ArcGISServerOperation public ServiceDescriptionDetails(ServiceDescription serviceDescription, Action beforeRequest = null, Action afterRequest = null) : base(serviceDescription.ArcGISServerEndpoint, beforeRequest, afterRequest) { - LiteGuard.Guard.AgainstNullArgument(nameof(serviceDescription), serviceDescription); + if (serviceDescription == null) + { + throw new ArgumentNullException(nameof(serviceDescription)); + } } /// diff --git a/src/Anywhere.ArcGIS/Operation/Token.cs b/src/Anywhere.ArcGIS/Operation/Token.cs index 02602f3..3507577 100644 --- a/src/Anywhere.ArcGIS/Operation/Token.cs +++ b/src/Anywhere.ArcGIS/Operation/Token.cs @@ -68,13 +68,34 @@ public GenerateToken(string username, string password) public void Encrypt(string username, string password, string expiration = "", string client = "", string referer = "") { - LiteGuard.Guard.AgainstNullArgument("username", username); - LiteGuard.Guard.AgainstNullArgument("password", password); + if (string.IsNullOrWhiteSpace(username)) + { + throw new ArgumentNullException(nameof(username), "username is null."); + } + + if (string.IsNullOrWhiteSpace(password)) + { + throw new ArgumentNullException(nameof(password), "password is null."); + } + Username = username; Password = password; - if (!string.IsNullOrWhiteSpace(expiration)) _expiration = expiration; - if (!string.IsNullOrWhiteSpace(client)) _client = client; - if (!string.IsNullOrWhiteSpace(referer)) _referer = referer; + + if (!string.IsNullOrWhiteSpace(expiration)) + { + _expiration = expiration; + } + + if (!string.IsNullOrWhiteSpace(client)) + { + _client = client; + } + + if (!string.IsNullOrWhiteSpace(referer)) + { + _referer = referer; + } + Encrypted = true; DontForceHttps = false; } diff --git a/src/Anywhere.ArcGIS/PortalGateway.cs b/src/Anywhere.ArcGIS/PortalGateway.cs index 4efaca9..e14ccd1 100644 --- a/src/Anywhere.ArcGIS/PortalGateway.cs +++ b/src/Anywhere.ArcGIS/PortalGateway.cs @@ -185,9 +185,16 @@ public PortalGateway(string rootUrl, string username, string password, ISerializ /// A collection of service description details public virtual Task> DescribeServices(SiteDescription siteDescription, CancellationToken ct = default(CancellationToken)) { - LiteGuard.Guard.AgainstNullArgument(nameof(siteDescription), siteDescription); - LiteGuard.Guard.AgainstNullArgumentProperty(nameof(siteDescription), nameof(siteDescription.Services) , siteDescription.Services); + if (siteDescription == null) + { + throw new ArgumentNullException(nameof(siteDescription)); + } + if (siteDescription.Services == null) + { + throw new ArgumentNullException(nameof(siteDescription.Services)); + } + return DescribeServices(siteDescription.Services.ToList(), ct); } @@ -199,7 +206,10 @@ public PortalGateway(string rootUrl, string username, string password, ISerializ /// A collection of service description details public virtual async Task> DescribeServices(List services, CancellationToken ct = default(CancellationToken)) { - LiteGuard.Guard.AgainstNullArgument(nameof(services), services); + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } var result = new List(); @@ -219,7 +229,10 @@ public PortalGateway(string rootUrl, string username, string password, ISerializ /// The service description details public virtual Task DescribeService(IEndpoint serviceEndpoint, CancellationToken ct = default(CancellationToken)) { - LiteGuard.Guard.AgainstNullArgument(nameof(serviceEndpoint), serviceEndpoint); + if (serviceEndpoint == null) + { + throw new ArgumentNullException(nameof(serviceEndpoint)); + } return Get(new ServiceDescriptionDetails(serviceEndpoint), ct); } @@ -232,7 +245,10 @@ public PortalGateway(string rootUrl, string username, string password, ISerializ /// The layer description details public virtual Task DescribeLayer(IEndpoint layerEndpoint, CancellationToken ct = default(CancellationToken)) { - LiteGuard.Guard.AgainstNullArgument(nameof(layerEndpoint), layerEndpoint); + if (layerEndpoint == null) + { + throw new ArgumentNullException(nameof(layerEndpoint)); + } return Get(new ServiceLayerDescription(layerEndpoint), ct); } diff --git a/src/Anywhere.ArcGIS/PortalGatewayBase.cs b/src/Anywhere.ArcGIS/PortalGatewayBase.cs index c50f8b4..68d6afd 100644 --- a/src/Anywhere.ArcGIS/PortalGatewayBase.cs +++ b/src/Anywhere.ArcGIS/PortalGatewayBase.cs @@ -104,7 +104,7 @@ internal PortalGatewayBase(Func log, string rootUrl, ISerializer serialize RootUrl = rootUrl.AsRootUrl(); TokenProvider = tokenProvider; Serializer = serializer ?? SerializerFactory.Get(); - LiteGuard.Guard.AgainstNullArgument("Serializer", Serializer); + var httpFunc = httpClientFunc ?? HttpClientFactory.Get; _httpClient = httpFunc(); MaximumGetRequestLength = 2047; @@ -446,7 +446,7 @@ public virtual async Task DownloadAttachmentToLocal(Attachment attachm int i = 1; while (fileInfo.Exists) { - fileInfo = new FileInfo(Path.Combine(documentLocation, $"rev-{i}-" + attachment.SafeFileName)); + fileInfo = new FileInfo(Path.Combine(documentLocation, $"rev-{i}-{attachment.SafeFileName}")); i++; } @@ -545,8 +545,11 @@ async Task CheckGenerateToken(CancellationToken ct) /// public virtual async Task DownloadExportMapToLocal(ExportMapResponse exportMapResponse, string folderLocation, string fileName = null) { - LiteGuard.Guard.AgainstNullArgument(nameof(exportMapResponse), exportMapResponse); - + if (exportMapResponse == null) + { + throw new ArgumentNullException(nameof(exportMapResponse)); + } + if (string.IsNullOrWhiteSpace(exportMapResponse.ImageUrl)) { throw new ArgumentNullException(nameof(exportMapResponse.ImageUrl)); @@ -597,8 +600,15 @@ protected async Task Get(TRequest requestObject, CancellationTok where TRequest : ArcGISServerOperation where T : IPortalResponse { - LiteGuard.Guard.AgainstNullArgument(nameof(requestObject), requestObject); - LiteGuard.Guard.AgainstNullArgumentProperty(nameof(requestObject), nameof(requestObject.Endpoint), requestObject.Endpoint); + if (requestObject == null) + { + throw new ArgumentNullException(nameof(requestObject)); + } + + if (requestObject.Endpoint == null) + { + throw new ArgumentNullException(nameof(requestObject.Endpoint)); + } var endpoint = requestObject.Endpoint; var url = endpoint.BuildAbsoluteUrl(RootUrl) + AsRequestQueryString(Serializer, requestObject); @@ -678,8 +688,15 @@ protected async Task Post(TRequest requestObject, CancellationTo where TRequest : ArcGISServerOperation where T : IPortalResponse { - LiteGuard.Guard.AgainstNullArgument(nameof(requestObject), requestObject); - LiteGuard.Guard.AgainstNullArgumentProperty(nameof(requestObject), nameof(requestObject.Endpoint), requestObject.Endpoint); + if (requestObject == null) + { + throw new ArgumentNullException(nameof(requestObject)); + } + + if (requestObject.Endpoint == null) + { + throw new ArgumentNullException(nameof(requestObject.Endpoint)); + } requestObject.BeforeRequest?.Invoke(); @@ -770,8 +787,15 @@ protected async Task Post(TRequest requestObject, CancellationTo internal static string AsRequestQueryString(ISerializer serializer, T objectToConvert) where T : ArcGISServerOperation { - LiteGuard.Guard.AgainstNullArgument(nameof(serializer), serializer); - LiteGuard.Guard.AgainstNullArgument(nameof(objectToConvert), objectToConvert); + if (serializer == null) + { + throw new ArgumentNullException(nameof(serializer)); + } + + if (objectToConvert == null) + { + throw new ArgumentNullException(nameof(objectToConvert)); + } var dictionary = serializer.AsDictionary(objectToConvert); diff --git a/src/Anywhere.ArcGIS/TokenProvider.cs b/src/Anywhere.ArcGIS/TokenProvider.cs index c4591d8..1431192 100644 --- a/src/Anywhere.ArcGIS/TokenProvider.cs +++ b/src/Anywhere.ArcGIS/TokenProvider.cs @@ -52,7 +52,7 @@ internal TokenProvider(Func log, string rootUrl, string username, string p } Serializer = serializer ?? SerializerFactory.Get(); - LiteGuard.Guard.AgainstNullArgument("Serializer", Serializer); + RootUrl = rootUrl.AsRootUrl(); CryptoProvider = cryptoProvider ?? CryptoProviderFactory.Get(); _httpClient = HttpClientFactory.Get(); diff --git a/tests/Anywhere.ArcGIS.Test.Integration/Anywhere.ArcGIS.Test.Integration.csproj b/tests/Anywhere.ArcGIS.Test.Integration/Anywhere.ArcGIS.Test.Integration.csproj index fe1309b..6ec7be9 100644 --- a/tests/Anywhere.ArcGIS.Test.Integration/Anywhere.ArcGIS.Test.Integration.csproj +++ b/tests/Anywhere.ArcGIS.Test.Integration/Anywhere.ArcGIS.Test.Integration.csproj @@ -5,9 +5,9 @@ - - - + + + diff --git a/tests/Anywhere.ArcGIS.Test.Integration/ArcGISGatewayTests.cs b/tests/Anywhere.ArcGIS.Test.Integration/ArcGISGatewayTests.cs index ed96722..93cf545 100644 --- a/tests/Anywhere.ArcGIS.Test.Integration/ArcGISGatewayTests.cs +++ b/tests/Anywhere.ArcGIS.Test.Integration/ArcGISGatewayTests.cs @@ -218,7 +218,7 @@ public async Task QueryCanReturnDifferentGeometryTypes() { var gateway = new ArcGISGateway(); - var queryPoint = new Query(@"Earthquakes/EarthquakesFromLastSevenDays/MapServer/0".AsEndpoint()) { Where = "magnitude > 4.5" }; + var queryPoint = new Query(@"Earthquakes/EarthquakesFromLastSevenDays/MapServer/0".AsEndpoint()) { Where = "magnitude > 2.5" }; var resultPoint = await IntegrationTestFixture.TestPolicy.ExecuteAsync(() => { return gateway.QueryAsPost(queryPoint); @@ -306,11 +306,11 @@ public async Task QueryObjectIdsAreHonored() Assert.True(resultPoint.Features.Any()); Assert.True(resultPoint.Features.All(i => i.Geometry == null)); - + var queryPointByOID = new Query(@"Earthquakes/EarthquakesFromLastSevenDays/MapServer/0".AsEndpoint()) { ReturnGeometry = false, - ObjectIds = resultPoint.Features.Take(10).Select(f => long.Parse(f.Attributes["objectid"].ToString())).ToList() + ObjectIds = resultPoint.Features.Take(10).Select(f => long.Parse(f.Attributes[resultPoint.ObjectIdFieldName ?? "objectid"].ToString())).ToList() }; var resultPointByOID = await IntegrationTestFixture.TestPolicy.ExecuteAsync(() => { @@ -363,7 +363,8 @@ public async Task QueryOrderByIsHonored(string rootUrl, string relativeUrl, stri var query = new Query(relativeUrl.AsEndpoint()) { OrderBy = new List { orderby }, - ReturnGeometry = false + ReturnGeometry = false, + Where = "CITY = 'WA'" }; var result = await IntegrationTestFixture.TestPolicy.ExecuteAsync(() => { @@ -373,7 +374,8 @@ public async Task QueryOrderByIsHonored(string rootUrl, string relativeUrl, stri var queryDesc = new Query(relativeUrl) { OrderBy = new List { orderby + " DESC" }, - ReturnGeometry = false + ReturnGeometry = false, + Where = "CITY = 'WA'" }; var resultDesc = await IntegrationTestFixture.TestPolicy.ExecuteAsync(() => { @@ -382,7 +384,9 @@ public async Task QueryOrderByIsHonored(string rootUrl, string relativeUrl, stri Assert.True(result.Features.Any()); Assert.True(resultDesc.Features.Any()); - Assert.NotEqual(result.Features, resultDesc.Features); + Assert.True(result.Features.Count() == resultDesc.Features.Count()); + Assert.Equal(result.Features.First().Attributes[orderby], resultDesc.Features.Last().Attributes[orderby]); + Assert.Equal(result.Features.Last().Attributes[orderby], resultDesc.Features.First().Attributes[orderby]); } [Theory] diff --git a/tests/Anywhere.ArcGIS.Test/Anywhere.ArcGIS.Test.csproj b/tests/Anywhere.ArcGIS.Test/Anywhere.ArcGIS.Test.csproj index e4ae322..2d5798d 100644 --- a/tests/Anywhere.ArcGIS.Test/Anywhere.ArcGIS.Test.csproj +++ b/tests/Anywhere.ArcGIS.Test/Anywhere.ArcGIS.Test.csproj @@ -5,7 +5,7 @@ - + diff --git a/tests/Anywhere.ArcGIS.Test/GeometryTests.cs b/tests/Anywhere.ArcGIS.Test/GeometryTests.cs index 88efd40..aad28dd 100644 --- a/tests/Anywhere.ArcGIS.Test/GeometryTests.cs +++ b/tests/Anywhere.ArcGIS.Test/GeometryTests.cs @@ -26,6 +26,23 @@ public void FeaturesAreTheSame() Assert.Equal(feature1, feature2); } + [Fact] + public void FeatureCanUseUniqueID() + { + var feature1 = new Feature + { + Geometry = new Point { X = 50.342, Y = -30.331, SpatialReference = SpatialReference.WGS84 } + }; + feature1.Attributes.Add("random", "rtcxbvbx"); + feature1.Attributes.Add("something", 45445); + + var feature2 = new Feature(feature1, "something"); + + Assert.True(feature1.UniqueID == 0); + Assert.True(feature2.UniqueID > 0); + Assert.Equal(45445, feature2.UniqueID); + } + [Fact] public void FeaturesAreNotTheSame() { @@ -200,6 +217,22 @@ public void CannotGetInvalidGlobalD(string key) Assert.Equal(Guid.Empty, feature.GlobalID); } + [Theory] + [InlineData("dfds", 3443)] + [InlineData("blahblah", 34.3)] + [InlineData("Global_id", "ewe")] + [InlineData("ESRI_OID", 's')] + [InlineData("something something darkside", 453f)] + public void CanGetAttributeValue(string key, object value) + { + var feature = new Feature(); + feature.Attributes.Add(key, value); + + var expected = feature.AttributeValue(key.ToLowerInvariant()); + + Assert.Equal(expected, value); + } + [Fact] public void GlobalIDIsEmptyOnInitialise() {