diff --git a/Skeleton.Abstraction/Domain/IEntity.cs b/Skeleton.Abstraction/Domain/IEntity.cs index 40f8cdd..d892c23 100644 --- a/Skeleton.Abstraction/Domain/IEntity.cs +++ b/Skeleton.Abstraction/Domain/IEntity.cs @@ -7,7 +7,7 @@ public interface IEntity : IEntityValidatable, IEntityDescriptor, IEntityAuditable - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { object Id { get; } diff --git a/Skeleton.Abstraction/Domain/IEntityValidatable.cs b/Skeleton.Abstraction/Domain/IEntityValidatable.cs index 9ab2965..b994528 100644 --- a/Skeleton.Abstraction/Domain/IEntityValidatable.cs +++ b/Skeleton.Abstraction/Domain/IEntityValidatable.cs @@ -1,7 +1,7 @@ namespace Skeleton.Abstraction.Domain { public interface IEntityValidatable : IHideObjectMethods - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { IEntityValidationResult Validate(IEntityValidator validator); } diff --git a/Skeleton.Abstraction/Domain/IEntityValidator.cs b/Skeleton.Abstraction/Domain/IEntityValidator.cs index 764f4e8..32b70c8 100644 --- a/Skeleton.Abstraction/Domain/IEntityValidator.cs +++ b/Skeleton.Abstraction/Domain/IEntityValidator.cs @@ -3,7 +3,7 @@ namespace Skeleton.Abstraction.Domain { public interface IEntityValidator : IHideObjectMethods - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { IEnumerable BrokenRules(TEntity entity); } diff --git a/Skeleton.Abstraction/Orm/IAsyncCachedEntityReader.cs b/Skeleton.Abstraction/Orm/IAsyncCachedEntityReader.cs index 5308fc8..76d4234 100644 --- a/Skeleton.Abstraction/Orm/IAsyncCachedEntityReader.cs +++ b/Skeleton.Abstraction/Orm/IAsyncCachedEntityReader.cs @@ -5,7 +5,7 @@ namespace Skeleton.Abstraction.Orm { public interface IAsyncCachedEntityReader : IAsyncEntityReader - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { IAsyncCacheProvider Cache { get; } diff --git a/Skeleton.Abstraction/Orm/IAsyncEntityAggregate.cs b/Skeleton.Abstraction/Orm/IAsyncEntityAggregate.cs index e3b74a1..5545344 100644 --- a/Skeleton.Abstraction/Orm/IAsyncEntityAggregate.cs +++ b/Skeleton.Abstraction/Orm/IAsyncEntityAggregate.cs @@ -7,7 +7,7 @@ namespace Skeleton.Abstraction.Orm { public interface IAsyncEntityAggregate - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { Task CountAsync(); diff --git a/Skeleton.Abstraction/Orm/IAsyncEntityQuery.cs b/Skeleton.Abstraction/Orm/IAsyncEntityQuery.cs index bee449c..12e9d72 100644 --- a/Skeleton.Abstraction/Orm/IAsyncEntityQuery.cs +++ b/Skeleton.Abstraction/Orm/IAsyncEntityQuery.cs @@ -5,7 +5,7 @@ namespace Skeleton.Abstraction.Orm { public interface IAsyncEntityQuery - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { Task FirstOrDefaultAsync(); diff --git a/Skeleton.Abstraction/Orm/IAsyncEntityReader.cs b/Skeleton.Abstraction/Orm/IAsyncEntityReader.cs index 9996ac2..a3a6008 100644 --- a/Skeleton.Abstraction/Orm/IAsyncEntityReader.cs +++ b/Skeleton.Abstraction/Orm/IAsyncEntityReader.cs @@ -10,22 +10,22 @@ public interface IAsyncEntityReader : IAsyncEntityAggregate, IDisposable, IHideObjectMethods - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { IAsyncEntityReader GroupBy( Expression> expression); IAsyncEntityReader LeftJoin( Expression> expression) - where TEntity2 : class, IEntity; + where TEntity2 : class, IEntity, new(); IAsyncEntityReader RightJoin( Expression> expression) - where TEntity2 : class, IEntity; + where TEntity2 : class, IEntity, new(); IAsyncEntityReader InnerJoin( Expression> expression) - where TEntity2 : class, IEntity; + where TEntity2 : class, IEntity, new(); IAsyncEntityReader OrderBy( Expression> expression); @@ -33,7 +33,6 @@ public interface IAsyncEntityReader : IAsyncEntityReader OrderByDescending( Expression> expression); - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Select")] IAsyncEntityReader Select( params Expression>[] expressions); diff --git a/Skeleton.Abstraction/Orm/IAsyncEntityWriter.cs b/Skeleton.Abstraction/Orm/IAsyncEntityWriter.cs index 95e45d1..28db2a5 100644 --- a/Skeleton.Abstraction/Orm/IAsyncEntityWriter.cs +++ b/Skeleton.Abstraction/Orm/IAsyncEntityWriter.cs @@ -8,7 +8,7 @@ namespace Skeleton.Abstraction.Orm public interface IAsyncEntityWriter : IDisposable, IHideObjectMethods - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { Task AddAsync(TEntity entity); diff --git a/Skeleton.Abstraction/Orm/ICachedEntityReader.cs b/Skeleton.Abstraction/Orm/ICachedEntityReader.cs index d33ea1b..f761905 100644 --- a/Skeleton.Abstraction/Orm/ICachedEntityReader.cs +++ b/Skeleton.Abstraction/Orm/ICachedEntityReader.cs @@ -5,7 +5,7 @@ namespace Skeleton.Abstraction.Orm { public interface ICachedEntityReader : IEntityReader - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { ICacheProvider Cache { get; } diff --git a/Skeleton.Abstraction/Orm/IEntityAggregate.cs b/Skeleton.Abstraction/Orm/IEntityAggregate.cs index fe90128..02b2d05 100644 --- a/Skeleton.Abstraction/Orm/IEntityAggregate.cs +++ b/Skeleton.Abstraction/Orm/IEntityAggregate.cs @@ -6,7 +6,7 @@ namespace Skeleton.Abstraction.Orm { public interface IEntityAggregate - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { int Count(); diff --git a/Skeleton.Abstraction/Orm/IEntityMapper.cs b/Skeleton.Abstraction/Orm/IEntityMapper.cs index 4e455c4..ad4701f 100644 --- a/Skeleton.Abstraction/Orm/IEntityMapper.cs +++ b/Skeleton.Abstraction/Orm/IEntityMapper.cs @@ -5,8 +5,8 @@ namespace Skeleton.Abstraction.Orm { public interface IEntityMapper : IHideObjectMethods - where TEntity : class, IEntity - where TDto : class + where TEntity : class, IEntity, new() + where TDto : class, new() { TDto Map(TEntity entity); diff --git a/Skeleton.Abstraction/Orm/IEntityQuery.cs b/Skeleton.Abstraction/Orm/IEntityQuery.cs index 3d4868e..8335276 100644 --- a/Skeleton.Abstraction/Orm/IEntityQuery.cs +++ b/Skeleton.Abstraction/Orm/IEntityQuery.cs @@ -4,7 +4,7 @@ namespace Skeleton.Abstraction.Orm { public interface IEntityQuery - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { TEntity FirstOrDefault(); diff --git a/Skeleton.Abstraction/Orm/IEntityReader.cs b/Skeleton.Abstraction/Orm/IEntityReader.cs index eed808b..cca7fca 100644 --- a/Skeleton.Abstraction/Orm/IEntityReader.cs +++ b/Skeleton.Abstraction/Orm/IEntityReader.cs @@ -11,22 +11,22 @@ public interface IEntityReader : IEntityAggregate, IDisposable, IHideObjectMethods - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { IEntityReader GroupBy( Expression> expression); IEntityReader LeftJoin( Expression> expression) - where TEntity2 : class, IEntity; + where TEntity2 : class, IEntity, new(); IEntityReader RightJoin( Expression> expression) - where TEntity2 : class, IEntity; + where TEntity2 : class, IEntity, new(); IEntityReader InnerJoin( Expression> expression) - where TEntity2 : class, IEntity; + where TEntity2 : class, IEntity, new(); IEntityReader OrderBy( Expression> expression); @@ -34,7 +34,6 @@ public interface IEntityReader : IEntityReader OrderByDescending( Expression> expression); - [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Select")] IEntityReader Select( params Expression>[] expressions); diff --git a/Skeleton.Abstraction/Orm/IEntityWriter.cs b/Skeleton.Abstraction/Orm/IEntityWriter.cs index 98c7a00..e641e5e 100644 --- a/Skeleton.Abstraction/Orm/IEntityWriter.cs +++ b/Skeleton.Abstraction/Orm/IEntityWriter.cs @@ -7,7 +7,7 @@ namespace Skeleton.Abstraction.Orm public interface IEntityWriter : IDisposable, IHideObjectMethods - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { bool Add(TEntity entity); diff --git a/Skeleton.Core/Caching/MemoryCacheProvider.cs b/Skeleton.Core/Caching/MemoryCacheProvider.cs index 35fafbe..3e51d07 100644 --- a/Skeleton.Core/Caching/MemoryCacheProvider.cs +++ b/Skeleton.Core/Caching/MemoryCacheProvider.cs @@ -12,8 +12,8 @@ public sealed class MemoryCacheProvider : public T GetOrAdd(string key, Func valueFactory, Action configurator) { - key.ThrowIfNullOrEmpty(nameof(key)); - valueFactory.ThrowIfNull(nameof(valueFactory)); + key.ThrowIfNullOrEmpty(); + valueFactory.ThrowIfNull(); try { diff --git a/Skeleton.Core/ConvertExtensions.cs b/Skeleton.Core/ConvertExtensions.cs index afa464c..147df99 100644 --- a/Skeleton.Core/ConvertExtensions.cs +++ b/Skeleton.Core/ConvertExtensions.cs @@ -7,7 +7,7 @@ public static class ConvertExtensions { public static object ChangeType(this object value, Type type, IFormatProvider provider) { - type.ThrowIfNull(nameof(type)); + type.ThrowIfNull(); while (true) { diff --git a/Skeleton.Core/DictionaryExtensions.cs b/Skeleton.Core/DictionaryExtensions.cs index 4276ab9..6ef53f0 100644 --- a/Skeleton.Core/DictionaryExtensions.cs +++ b/Skeleton.Core/DictionaryExtensions.cs @@ -10,9 +10,9 @@ public static class DictionaryExtensions TKey key, Func valueFactory) { - source.ThrowIfNull(nameof(source)); - key.ThrowIfNull(nameof(key)); - valueFactory.ThrowIfNull(nameof(valueFactory)); + source.ThrowIfNull(); + key.ThrowIfNull(); + valueFactory.ThrowIfNull(); if (source.ContainsKey(key)) return source[key]; diff --git a/Skeleton.Core/Domain/EntityBase.cs b/Skeleton.Core/Domain/EntityBase.cs index 988c039..4902ab0 100644 --- a/Skeleton.Core/Domain/EntityBase.cs +++ b/Skeleton.Core/Domain/EntityBase.cs @@ -9,13 +9,13 @@ namespace Skeleton.Core.Domain { [DebuggerDisplay("Id = {ToString()}")] public abstract class EntityBase : IEntity - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { private const int HashMultiplier = 31; protected EntityBase(Expression> idExpression) { - idExpression.ThrowIfNull(nameof(idExpression)); + idExpression.ThrowIfNull(); Metadata = new MetadataProvider().GetMetadata(typeof(TEntity)); IdAccessor = Metadata.GetProperty(idExpression); @@ -58,7 +58,7 @@ public virtual bool IsTransient() public IEntityValidationResult Validate(IEntityValidator validator) { - validator.ThrowIfNull(nameof(validator)); + validator.ThrowIfNull(); return new EntityValidationResult(validator.BrokenRules(this as TEntity)); } diff --git a/Skeleton.Core/Domain/EntityValidationResult.cs b/Skeleton.Core/Domain/EntityValidationResult.cs index 4130b60..d58bf07 100644 --- a/Skeleton.Core/Domain/EntityValidationResult.cs +++ b/Skeleton.Core/Domain/EntityValidationResult.cs @@ -8,7 +8,7 @@ public sealed class EntityValidationResult : IEntityValidationResult public EntityValidationResult(IEnumerable brokenRules) { var enumerable = brokenRules.AsList(); - enumerable.ThrowIfNull(nameof(enumerable)); + enumerable.ThrowIfNull(); BrokenRules = enumerable; } diff --git a/Skeleton.Core/Domain/EntityValidatorBase.cs b/Skeleton.Core/Domain/EntityValidatorBase.cs index c70a66c..84c57d9 100644 --- a/Skeleton.Core/Domain/EntityValidatorBase.cs +++ b/Skeleton.Core/Domain/EntityValidatorBase.cs @@ -4,7 +4,7 @@ namespace Skeleton.Core.Domain { public abstract class EntityValidatorBase : IEntityValidator - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { private readonly List _brokenRules = new List(); diff --git a/Skeleton.Core/Domain/GlobalSuppressions.cs b/Skeleton.Core/Domain/GlobalSuppressions.cs deleted file mode 100644 index eeeba24..0000000 Binary files a/Skeleton.Core/Domain/GlobalSuppressions.cs and /dev/null differ diff --git a/Skeleton.Core/EnumerableExtensions.cs b/Skeleton.Core/EnumerableExtensions.cs index 024c46c..8bba7f4 100644 --- a/Skeleton.Core/EnumerableExtensions.cs +++ b/Skeleton.Core/EnumerableExtensions.cs @@ -19,7 +19,7 @@ public static List AsList(this IEnumerable source) public static bool FastAny(this IEnumerable source) { - source.ThrowIfNull(nameof(source)); + source.ThrowIfNull(); var enumerable = source as IList ?? source.ToList(); var collection = source as ICollection; @@ -37,8 +37,8 @@ public static bool FastAny(this IEnumerable source) public static void ForEach(this IEnumerable source, Action action) { - source.ThrowIfNull(nameof(source)); - action.ThrowIfNull(nameof(action)); + source.ThrowIfNull(); + action.ThrowIfNull(); var enumerable = source as IList ?? source.ToList(); @@ -58,7 +58,7 @@ public static bool IsNullOrEmpty(this IEnumerable source) public static Task> ToListAsync(this IEnumerable source) { - source.ThrowIfNull(nameof(source)); + source.ThrowIfNull(); return Task.Run(() => source.ToList()); } diff --git a/Skeleton.Core/ExpressionExtensions.cs b/Skeleton.Core/ExpressionExtensions.cs index 3493c35..bbc7548 100644 --- a/Skeleton.Core/ExpressionExtensions.cs +++ b/Skeleton.Core/ExpressionExtensions.cs @@ -10,7 +10,7 @@ public static class ExpressionExtensions { public static BinaryExpression GetBinaryExpression(this Expression expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); var binaryExpression = expression as BinaryExpression; if (binaryExpression != null) @@ -21,7 +21,7 @@ public static BinaryExpression GetBinaryExpression(this Expression expression) public static object GetExpressionValue(this Expression expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); var constantExpression = expression as ConstantExpression; if (constantExpression != null) @@ -64,7 +64,7 @@ private static object GetValue(this MemberExpression expression, object instance public static MemberExpression GetMemberExpression(this Expression expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); while (true) { @@ -85,7 +85,7 @@ public static MemberExpression GetMemberExpression(this Expression expression) public static PropertyInfo GetPropertyAccess(this LambdaExpression expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); if (expression.Parameters.Count != 1) throw new ArgumentException("Expression must have at least 1 parameter"); @@ -104,7 +104,7 @@ public static PropertyInfo GetPropertyAccess(this LambdaExpression expression) public static object InvokeMethodCall(this MethodCallExpression callExpression) { - callExpression.ThrowIfNull(nameof(callExpression)); + callExpression.ThrowIfNull(); var arguments = callExpression.Arguments.Select(GetExpressionValue).ToArray(); var obj = callExpression.Object != null @@ -119,7 +119,6 @@ public static object InvokeMethodCall(this MethodCallExpression callExpression) Expression propertyAccessExpression) { var propertyInfos = new List(); - MemberExpression memberExpression; do diff --git a/Skeleton.Core/GuardExtensions.cs b/Skeleton.Core/GuardExtensions.cs index 4c98af3..7b72844 100644 --- a/Skeleton.Core/GuardExtensions.cs +++ b/Skeleton.Core/GuardExtensions.cs @@ -1,28 +1,27 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; namespace Skeleton.Core { [DebuggerStepThrough] public static class GuardExtensions { - public static void ThrowIfNull(this T value, string parameterName) + public static void ThrowIfNull(this T value, [CallerMemberName] string parameterName = null) { if (value.Equals(default(T))) throw new ArgumentNullException(parameterName ?? "object"); } - public static void ThrowIfNullOrEmpty(this IEnumerable value, string parameterName) + public static void ThrowIfNullOrEmpty(this IEnumerable value, [CallerMemberName] string parameterName = null) { if (value.IsNullOrEmpty()) throw new ArgumentNullException(parameterName ?? "collection"); } - public static void ThrowIfNullOrEmpty(this string value, string parameterName) + public static void ThrowIfNullOrEmpty(this string value, [CallerMemberName] string parameterName = null) { - value.ThrowIfNull(nameof(parameterName)); - if (string.IsNullOrEmpty(value)) throw new ArgumentException("Argument cannot be null", parameterName ?? "string"); } diff --git a/Skeleton.Core/LazyRef.cs b/Skeleton.Core/LazyRef.cs index 512c4b5..cb11979 100644 --- a/Skeleton.Core/LazyRef.cs +++ b/Skeleton.Core/LazyRef.cs @@ -9,7 +9,7 @@ public sealed class LazyRef : HideObjectMethodsBase public LazyRef(Func initializer) { - initializer.ThrowIfNull(nameof(initializer)); + initializer.ThrowIfNull(); _initializer = initializer; } diff --git a/Skeleton.Core/Reflection/ConstructorAccessor.cs b/Skeleton.Core/Reflection/ConstructorAccessor.cs index aebb0bd..039c500 100644 --- a/Skeleton.Core/Reflection/ConstructorAccessor.cs +++ b/Skeleton.Core/Reflection/ConstructorAccessor.cs @@ -1,5 +1,4 @@ using Skeleton.Abstraction.Reflection; -using Skeleton.Core.Reflection.Emitter; using System; namespace Skeleton.Core.Reflection @@ -10,8 +9,8 @@ public sealed class ConstructorAccessor : IInstanceAccessor public ConstructorAccessor(Type type, Type[] paramTypes) { - type.ThrowIfNull(nameof(type)); - paramTypes.ThrowIfNull(nameof(paramTypes)); + type.ThrowIfNull(); + paramTypes.ThrowIfNull(); var emitter = new ConstructorEmitter(type, paramTypes); _constructorDelegate = emitter.CreateDelegate(); diff --git a/Skeleton.Core/Reflection/Emitter/ConstructorEmitter.cs b/Skeleton.Core/Reflection/ConstructorEmitter.cs similarity index 96% rename from Skeleton.Core/Reflection/Emitter/ConstructorEmitter.cs rename to Skeleton.Core/Reflection/ConstructorEmitter.cs index 0530d1a..f52aac3 100644 --- a/Skeleton.Core/Reflection/Emitter/ConstructorEmitter.cs +++ b/Skeleton.Core/Reflection/ConstructorEmitter.cs @@ -1,7 +1,7 @@ using System; using System.Reflection.Emit; -namespace Skeleton.Core.Reflection.Emitter +namespace Skeleton.Core.Reflection { internal sealed class ConstructorEmitter : EmitterBase { diff --git a/Skeleton.Core/Reflection/Emitter/EmitExtensions.cs b/Skeleton.Core/Reflection/EmitExtensions.cs similarity index 98% rename from Skeleton.Core/Reflection/Emitter/EmitExtensions.cs rename to Skeleton.Core/Reflection/EmitExtensions.cs index 22fe973..5d0c3c1 100644 --- a/Skeleton.Core/Reflection/Emitter/EmitExtensions.cs +++ b/Skeleton.Core/Reflection/EmitExtensions.cs @@ -2,7 +2,7 @@ using System.Reflection; using System.Reflection.Emit; -namespace Skeleton.Core.Reflection.Emitter +namespace Skeleton.Core.Reflection { internal static class EmitExtensions { diff --git a/Skeleton.Core/Reflection/Emitter/EmitterBase.cs b/Skeleton.Core/Reflection/EmitterBase.cs similarity index 93% rename from Skeleton.Core/Reflection/Emitter/EmitterBase.cs rename to Skeleton.Core/Reflection/EmitterBase.cs index 8af17da..a00786a 100644 --- a/Skeleton.Core/Reflection/Emitter/EmitterBase.cs +++ b/Skeleton.Core/Reflection/EmitterBase.cs @@ -1,7 +1,7 @@ using System; using System.Reflection.Emit; -namespace Skeleton.Core.Reflection.Emitter +namespace Skeleton.Core.Reflection { internal abstract class EmitterBase { diff --git a/Skeleton.Core/Reflection/FieldAccessor.cs b/Skeleton.Core/Reflection/FieldAccessor.cs index 2d17532..02ef5f5 100644 --- a/Skeleton.Core/Reflection/FieldAccessor.cs +++ b/Skeleton.Core/Reflection/FieldAccessor.cs @@ -1,5 +1,4 @@ using Skeleton.Abstraction.Reflection; -using Skeleton.Core.Reflection.Emitter; using System; using System.Diagnostics; using System.Reflection; @@ -15,7 +14,7 @@ public sealed class FieldAccessor : MemberAccessorBase public FieldAccessor(FieldInfo fieldInfo) { - fieldInfo.ThrowIfNull(nameof(fieldInfo)); + fieldInfo.ThrowIfNull(); _fieldInfo = fieldInfo; Name = fieldInfo.Name; diff --git a/Skeleton.Core/Reflection/Emitter/FieldEmitter.cs b/Skeleton.Core/Reflection/FieldEmitter.cs similarity index 97% rename from Skeleton.Core/Reflection/Emitter/FieldEmitter.cs rename to Skeleton.Core/Reflection/FieldEmitter.cs index 780f0b8..5fcf15c 100644 --- a/Skeleton.Core/Reflection/Emitter/FieldEmitter.cs +++ b/Skeleton.Core/Reflection/FieldEmitter.cs @@ -2,7 +2,7 @@ using System.Reflection; using System.Reflection.Emit; -namespace Skeleton.Core.Reflection.Emitter +namespace Skeleton.Core.Reflection { internal sealed class FieldEmitter : EmitterBase { diff --git a/Skeleton.Core/Reflection/Metadata.cs b/Skeleton.Core/Reflection/Metadata.cs index defe54b..13c26a1 100644 --- a/Skeleton.Core/Reflection/Metadata.cs +++ b/Skeleton.Core/Reflection/Metadata.cs @@ -36,7 +36,7 @@ public sealed class Metadata : HideObjectMethodsBase, IMetadata public Metadata(Type type) { - type.ThrowIfNull(nameof(type)); + type.ThrowIfNull(); Type = type; } @@ -96,7 +96,7 @@ public IEnumerable GetProperties() public IMemberAccessor GetProperty(string name) { - name.ThrowIfNullOrEmpty(nameof(name)); + name.ThrowIfNullOrEmpty(); IMemberAccessor accessor; if (_propertyCache.Value.TryGetValue(name, out accessor)) @@ -112,7 +112,7 @@ public IMemberAccessor GetProperty(string name) public IMemberAccessor GetProperty(Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); var propertyInfo = expression.GetPropertyAccess(); @@ -129,7 +129,7 @@ public IMemberAccessor GetProperty(Expression> expression) private IMemberAccessor GetField(string name, BindingFlags bindings) { - name.ThrowIfNullOrEmpty(nameof(name)); + name.ThrowIfNullOrEmpty(); IMemberAccessor accessor; if (_fieldCache.Value.TryGetValue(name, out accessor)) @@ -146,6 +146,7 @@ private IMemberAccessor GetField(string name, BindingFlags bindings) private IEnumerable GetFields(BindingFlags bindings) { var fields = Type.GetFields(bindings); + foreach (var fieldInfo in fields) yield return _fieldCache.Value.GetOrAdd( fieldInfo.Name, @@ -155,6 +156,7 @@ private IEnumerable GetFields(BindingFlags bindings) private IEnumerable GetProperties(BindingFlags bindings) { var properties = Type.GetProperties(bindings); + foreach (var propertyInfo in properties) yield return _propertyCache.Value.GetOrAdd( propertyInfo.Name, diff --git a/Skeleton.Core/Reflection/MetadataProvider.cs b/Skeleton.Core/Reflection/MetadataProvider.cs index 9c56bcc..a226be1 100644 --- a/Skeleton.Core/Reflection/MetadataProvider.cs +++ b/Skeleton.Core/Reflection/MetadataProvider.cs @@ -19,7 +19,7 @@ public IMetadata GetMetadata() public IMetadata GetMetadata(Type type) { - type.ThrowIfNull(nameof(type)); + type.ThrowIfNull(); return TypeCache.GetOrAdd(type, new Metadata(type)); } diff --git a/Skeleton.Core/Reflection/MethodAccessor.cs b/Skeleton.Core/Reflection/MethodAccessor.cs index 023b1ad..3edfeef 100644 --- a/Skeleton.Core/Reflection/MethodAccessor.cs +++ b/Skeleton.Core/Reflection/MethodAccessor.cs @@ -1,5 +1,4 @@ using Skeleton.Abstraction.Reflection; -using Skeleton.Core.Reflection.Emitter; using System; using System.Diagnostics; using System.Globalization; @@ -14,7 +13,7 @@ public sealed class MethodAccessor : IMethodAccessor public MethodAccessor(MethodInfo methodInfo) { - methodInfo.ThrowIfNull(nameof(methodInfo)); + methodInfo.ThrowIfNull(); MethodInfo = methodInfo; Name = methodInfo.Name; @@ -31,8 +30,8 @@ public MethodAccessor(MethodInfo methodInfo) internal static IMethodAccessor Create(Type type, string name, Type[] parameterTypes) { - type.ThrowIfNull(nameof(type)); - name.ThrowIfNullOrEmpty(nameof(name)); + type.ThrowIfNull(); + name.ThrowIfNullOrEmpty(); const BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; diff --git a/Skeleton.Core/Reflection/Emitter/MethodEmitter.cs b/Skeleton.Core/Reflection/MethodEmitter.cs similarity index 98% rename from Skeleton.Core/Reflection/Emitter/MethodEmitter.cs rename to Skeleton.Core/Reflection/MethodEmitter.cs index 2b4d1a1..df78f99 100644 --- a/Skeleton.Core/Reflection/Emitter/MethodEmitter.cs +++ b/Skeleton.Core/Reflection/MethodEmitter.cs @@ -2,8 +2,8 @@ using System.Reflection; using System.Reflection.Emit; -namespace Skeleton.Core.Reflection.Emitter -{ +namespace Skeleton.Core.Reflection +{ internal sealed class MethodEmitter : EmitterBase { private readonly MethodInfo _methodInfo; diff --git a/Skeleton.Core/Reflection/PropertyAccessor.cs b/Skeleton.Core/Reflection/PropertyAccessor.cs index d776dc9..e30f1a0 100644 --- a/Skeleton.Core/Reflection/PropertyAccessor.cs +++ b/Skeleton.Core/Reflection/PropertyAccessor.cs @@ -1,5 +1,4 @@ using Skeleton.Abstraction.Reflection; -using Skeleton.Core.Reflection.Emitter; using System; using System.Diagnostics; using System.Reflection; @@ -15,7 +14,7 @@ public sealed class PropertyAccessor : MemberAccessorBase public PropertyAccessor(PropertyInfo propertyInfo) { - propertyInfo.ThrowIfNull(nameof(propertyInfo)); + propertyInfo.ThrowIfNull(); _propertyInfo = propertyInfo; Name = propertyInfo.Name; diff --git a/Skeleton.Core/Reflection/Emitter/PropertyEmitter.cs b/Skeleton.Core/Reflection/PropertyEmitter.cs similarity index 97% rename from Skeleton.Core/Reflection/Emitter/PropertyEmitter.cs rename to Skeleton.Core/Reflection/PropertyEmitter.cs index e1b5d53..e718d8d 100644 --- a/Skeleton.Core/Reflection/Emitter/PropertyEmitter.cs +++ b/Skeleton.Core/Reflection/PropertyEmitter.cs @@ -2,7 +2,7 @@ using System.Reflection; using System.Reflection.Emit; -namespace Skeleton.Core.Reflection.Emitter +namespace Skeleton.Core.Reflection { internal sealed class PropertyEmitter : EmitterBase { diff --git a/Skeleton.Core/Skeleton.Core.csproj b/Skeleton.Core/Skeleton.Core.csproj index e1f1aaf..00df8d0 100644 --- a/Skeleton.Core/Skeleton.Core.csproj +++ b/Skeleton.Core/Skeleton.Core.csproj @@ -61,7 +61,6 @@ - @@ -73,12 +72,12 @@ - - - - - - + + + + + + diff --git a/Skeleton.Core/StringExtensions.cs b/Skeleton.Core/StringExtensions.cs index 724a3bf..18d9a96 100644 --- a/Skeleton.Core/StringExtensions.cs +++ b/Skeleton.Core/StringExtensions.cs @@ -12,15 +12,15 @@ public static bool IsNullOrEmpty(this string value) public static bool EquivalentTo(this string value, string other) { - value.ThrowIfNullOrEmpty(nameof(value)); - other.ThrowIfNullOrEmpty(nameof(other)); + value.ThrowIfNullOrEmpty(); + other.ThrowIfNullOrEmpty(); return string.Equals(value, other, StringComparison.OrdinalIgnoreCase); } public static string FormatWith(this string value, params object[] parameters) { - value.ThrowIfNullOrEmpty(nameof(value)); + value.ThrowIfNullOrEmpty(); return string.Format(CultureInfo.InvariantCulture, value, parameters); } diff --git a/Skeleton.Core/TypeExtensions.cs b/Skeleton.Core/TypeExtensions.cs index 59c5b76..9b3ee2a 100644 --- a/Skeleton.Core/TypeExtensions.cs +++ b/Skeleton.Core/TypeExtensions.cs @@ -6,7 +6,7 @@ public static class TypeExtensions { public static bool IsPrimitiveExtended(this Type type) { - type.ThrowIfNull(nameof(type)); + type.ThrowIfNull(); if (type.IsPrimitive) return true; diff --git a/Skeleton.Documentation.Swagger/Program.cs b/Skeleton.Documentation.Swagger/Program.cs index 29e0aa0..b16958a 100644 --- a/Skeleton.Documentation.Swagger/Program.cs +++ b/Skeleton.Documentation.Swagger/Program.cs @@ -13,7 +13,7 @@ private static void Main() { using (var server = new OwinTestServer()) { - server.Start(AppConfiguration.BaseUrl); + server.Start(AppConfiguration.BaseAddress); Console.WriteLine(Started); Process.Start(SwaggerUri); diff --git a/Skeleton.Infrastructure.Data/DatabaseContext.cs b/Skeleton.Infrastructure.Data/DatabaseContext.cs index 06b659f..c777701 100644 --- a/Skeleton.Infrastructure.Data/DatabaseContext.cs +++ b/Skeleton.Infrastructure.Data/DatabaseContext.cs @@ -165,7 +165,7 @@ private void AttachParameters(IDictionary parameters) [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2100:Vérifier si les requêtes SQL présentent des failles de sécurité")] private IDbCommand CreateCommand(CommandType commandType, ISqlCommand sqlCommand) { - sqlCommand.SqlQuery.ThrowIfNullOrEmpty(nameof(sqlCommand.SqlQuery)); + sqlCommand.SqlQuery.ThrowIfNullOrEmpty(); _command = new SqlCommand(); _command.Connection = _connection; diff --git a/Skeleton.Infrastructure.Dependency/Bootstrapper.cs b/Skeleton.Infrastructure.Dependency/Bootstrapper.cs index 4ed1741..1bcca41 100644 --- a/Skeleton.Infrastructure.Dependency/Bootstrapper.cs +++ b/Skeleton.Infrastructure.Dependency/Bootstrapper.cs @@ -15,7 +15,7 @@ public Bootstrapper() : this(DependencyContainer.Instance) public Bootstrapper(IDependencyContainer container) { - container.ThrowIfNull(nameof(container)); + container.ThrowIfNull(); _container = container; _container.AddPlugin(new CorePlugin()); @@ -25,7 +25,7 @@ public Bootstrapper(IDependencyContainer container) public IBootstrapOrm UseSqlServer(Func configurator) { - configurator.ThrowIfNull(nameof(configurator)); + configurator.ThrowIfNull(); var builder = _container.Resolve(); _container.Register.Instance(configurator(builder)); diff --git a/Skeleton.Infrastructure.Dependency/Configuration/CreationStackTrackerStrategy.cs b/Skeleton.Infrastructure.Dependency/Configuration/CreationStackTrackerStrategy.cs index a869df6..a3541ff 100644 --- a/Skeleton.Infrastructure.Dependency/Configuration/CreationStackTrackerStrategy.cs +++ b/Skeleton.Infrastructure.Dependency/Configuration/CreationStackTrackerStrategy.cs @@ -7,7 +7,7 @@ public sealed class CreationStackTrackerStrategy : BuilderStrategy { public override void PostBuildUp(IBuilderContext context) { - context.ThrowIfNull(nameof(context)); + context.ThrowIfNull(); var policy = context.Policies.Get(null, true); @@ -19,7 +19,7 @@ public override void PostBuildUp(IBuilderContext context) public override void PreBuildUp(IBuilderContext context) { - context.ThrowIfNull(nameof(context)); + context.ThrowIfNull(); var policy = context.Policies.Get(null, true); diff --git a/Skeleton.Infrastructure.Dependency/Configuration/DatabaseConfiguration.cs b/Skeleton.Infrastructure.Dependency/Configuration/DatabaseConfiguration.cs index 80b7049..62efddd 100644 --- a/Skeleton.Infrastructure.Dependency/Configuration/DatabaseConfiguration.cs +++ b/Skeleton.Infrastructure.Dependency/Configuration/DatabaseConfiguration.cs @@ -9,11 +9,11 @@ public sealed class DatabaseConfiguration : HideObjectMethodsBase, IDatabaseConfiguration { - public static readonly int DefaultTimeout = 300; - public static readonly int DefaultRetryCount = 10; - public static readonly int DefaultRetryInterval = 1; - public static readonly string DefaultProvider = "System.Data.SqlClient"; - public static readonly string DefaultName = "Default"; + private static readonly int DefaultTimeout = 300; + private static readonly int DefaultRetryCount = 10; + private static readonly int DefaultRetryInterval = 1; + private static readonly string DefaultProvider = "System.Data.SqlClient"; + private static readonly string DefaultName = "Default"; private int _commandTimeout; private int _retryCount; diff --git a/Skeleton.Infrastructure.Dependency/Configuration/DatabaseConfigurationBuilder.cs b/Skeleton.Infrastructure.Dependency/Configuration/DatabaseConfigurationBuilder.cs index 8fb058e..415750e 100644 --- a/Skeleton.Infrastructure.Dependency/Configuration/DatabaseConfigurationBuilder.cs +++ b/Skeleton.Infrastructure.Dependency/Configuration/DatabaseConfigurationBuilder.cs @@ -30,7 +30,7 @@ public IDatabaseConfigurationProperties UsingConfigConnectionString(string conne public IDatabaseConfigurationProperties UsingConnectionString(string connectionString) { - connectionString.ThrowIfNullOrEmpty(nameof(connectionString)); + connectionString.ThrowIfNullOrEmpty(); var settings = new ConnectionStringSettings { ConnectionString = connectionString }; Initialize(settings); diff --git a/Skeleton.Infrastructure.Dependency/Configuration/LogBuilderStrategy.cs b/Skeleton.Infrastructure.Dependency/Configuration/LogBuilderStrategy.cs index 8b6d7b3..20e426a 100644 --- a/Skeleton.Infrastructure.Dependency/Configuration/LogBuilderStrategy.cs +++ b/Skeleton.Infrastructure.Dependency/Configuration/LogBuilderStrategy.cs @@ -9,7 +9,7 @@ public sealed class LogBuilderStrategy : BuilderStrategy { public override void PreBuildUp(IBuilderContext context) { - context.ThrowIfNull(nameof(context)); + context.ThrowIfNull(); var policy = context.Policies.Get(null, true); diff --git a/Skeleton.Infrastructure.Dependency/DependencyContainer.cs b/Skeleton.Infrastructure.Dependency/DependencyContainer.cs index 162f3da..8dd8fe2 100644 --- a/Skeleton.Infrastructure.Dependency/DependencyContainer.cs +++ b/Skeleton.Infrastructure.Dependency/DependencyContainer.cs @@ -21,7 +21,7 @@ public DependencyContainer() : this(new UnityContainer()) public DependencyContainer(IUnityContainer unityContainer) { - unityContainer.ThrowIfNull(nameof(unityContainer)); + unityContainer.ThrowIfNull(); _unityContainer = unityContainer; _registrar = new DependencyRegistrar(unityContainer); @@ -42,7 +42,7 @@ public DependencyContainer(IUnityContainer unityContainer) public IDependencyContainer AddPlugin(IPlugin plugin) { - plugin.ThrowIfNull(nameof(plugin)); + plugin.ThrowIfNull(); plugin.Configure(this); _plugins.Add(plugin); @@ -52,7 +52,7 @@ public IDependencyContainer AddPlugin(IPlugin plugin) public IDependencyContainer AddPlugins(IEnumerable plugins) { - plugins.ThrowIfNull(nameof(plugins)); + plugins.ThrowIfNull(); foreach (var plugin in plugins) AddPlugin(plugin); diff --git a/Skeleton.Infrastructure.Dependency/DependencyRegistrar.cs b/Skeleton.Infrastructure.Dependency/DependencyRegistrar.cs index 88e808e..63a1216 100644 --- a/Skeleton.Infrastructure.Dependency/DependencyRegistrar.cs +++ b/Skeleton.Infrastructure.Dependency/DependencyRegistrar.cs @@ -11,7 +11,7 @@ public sealed class DependencyRegistrar : HideObjectMethodsBase, IDependencyRegi public DependencyRegistrar(IUnityContainer unityContainer) { - unityContainer.ThrowIfNull(nameof(unityContainer)); + unityContainer.ThrowIfNull(); _unityContainer = unityContainer; } diff --git a/Skeleton.Infrastructure.Dependency/Plugins/CachePlugin.cs b/Skeleton.Infrastructure.Dependency/Plugins/CachePlugin.cs index df9fb0e..2b4d135 100644 --- a/Skeleton.Infrastructure.Dependency/Plugins/CachePlugin.cs +++ b/Skeleton.Infrastructure.Dependency/Plugins/CachePlugin.cs @@ -9,7 +9,7 @@ public sealed class CachePlugin : IPlugin { public void Configure(IDependencyContainer container) { - container.ThrowIfNull(nameof(container)); + container.ThrowIfNull(); container.Register .Type() diff --git a/Skeleton.Infrastructure.Dependency/Plugins/ConfigurationPlugin.cs b/Skeleton.Infrastructure.Dependency/Plugins/ConfigurationPlugin.cs index 29709f4..99c1e09 100644 --- a/Skeleton.Infrastructure.Dependency/Plugins/ConfigurationPlugin.cs +++ b/Skeleton.Infrastructure.Dependency/Plugins/ConfigurationPlugin.cs @@ -8,7 +8,7 @@ public sealed class ConfigurationPlugin : IPlugin { public void Configure(IDependencyContainer container) { - container.ThrowIfNull(nameof(container)); + container.ThrowIfNull(); container.Register.Type(); } diff --git a/Skeleton.Infrastructure.Dependency/Plugins/CorePlugin.cs b/Skeleton.Infrastructure.Dependency/Plugins/CorePlugin.cs index 52dd24e..e5c9d1e 100644 --- a/Skeleton.Infrastructure.Dependency/Plugins/CorePlugin.cs +++ b/Skeleton.Infrastructure.Dependency/Plugins/CorePlugin.cs @@ -16,7 +16,7 @@ public sealed class CorePlugin : IPlugin public void Configure(IDependencyContainer container) { - container.ThrowIfNull(nameof(container)); + container.ThrowIfNull(); container.AddPlugins(_corePlugins); } diff --git a/Skeleton.Infrastructure.Dependency/Plugins/DatabasePlugin.cs b/Skeleton.Infrastructure.Dependency/Plugins/DatabasePlugin.cs index 78b17da..717c183 100644 --- a/Skeleton.Infrastructure.Dependency/Plugins/DatabasePlugin.cs +++ b/Skeleton.Infrastructure.Dependency/Plugins/DatabasePlugin.cs @@ -9,7 +9,7 @@ public sealed class DatabasePlugin : IPlugin { public void Configure(IDependencyContainer container) { - container.ThrowIfNull(nameof(container)); + container.ThrowIfNull(); container.Register .Type(DependencyLifetime.Scoped) diff --git a/Skeleton.Infrastructure.Dependency/Plugins/LoggerPlugin.cs b/Skeleton.Infrastructure.Dependency/Plugins/LoggerPlugin.cs index fbcd3dc..6be91c3 100644 --- a/Skeleton.Infrastructure.Dependency/Plugins/LoggerPlugin.cs +++ b/Skeleton.Infrastructure.Dependency/Plugins/LoggerPlugin.cs @@ -10,7 +10,7 @@ public sealed class LoggerPlugin : IPlugin { public void Configure(IDependencyContainer container) { - container.ThrowIfNull(nameof(container)); + container.ThrowIfNull(); var configuration = new LoggerConfiguration(); configuration.Configure(); diff --git a/Skeleton.Infrastructure.Dependency/Plugins/MetadataPlugin.cs b/Skeleton.Infrastructure.Dependency/Plugins/MetadataPlugin.cs index 3d55092..d1f582f 100644 --- a/Skeleton.Infrastructure.Dependency/Plugins/MetadataPlugin.cs +++ b/Skeleton.Infrastructure.Dependency/Plugins/MetadataPlugin.cs @@ -9,7 +9,7 @@ public sealed class MetadataPlugin : IPlugin { public void Configure(IDependencyContainer container) { - container.ThrowIfNull(nameof(container)); + container.ThrowIfNull(); container.Register.Type(); } diff --git a/Skeleton.Infrastructure.Dependency/Plugins/OrmPlugin.cs b/Skeleton.Infrastructure.Dependency/Plugins/OrmPlugin.cs index 46d8c2f..cec5bd4 100644 --- a/Skeleton.Infrastructure.Dependency/Plugins/OrmPlugin.cs +++ b/Skeleton.Infrastructure.Dependency/Plugins/OrmPlugin.cs @@ -9,7 +9,7 @@ public sealed class OrmPlugin : IPlugin { public void Configure(IDependencyContainer container) { - container.ThrowIfNull(nameof(container)); + container.ThrowIfNull(); container.Register .Type(typeof(IEntityReader<>), typeof(EntityReader<>), DependencyLifetime.Scoped) diff --git a/Skeleton.Infrastructure.Logging/Logger.cs b/Skeleton.Infrastructure.Logging/Logger.cs index 3211c85..466eebc 100644 --- a/Skeleton.Infrastructure.Logging/Logger.cs +++ b/Skeleton.Infrastructure.Logging/Logger.cs @@ -89,29 +89,5 @@ public void WarnFormat(string format, params object[] args) { _log.WarnFormat(CultureInfo.CurrentCulture, format, args); } - - [EditorBrowsable(EditorBrowsableState.Never)] - public override bool Equals(object obj) - { - return base.Equals(obj); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public override int GetHashCode() - { - return base.GetHashCode(); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public new Type GetType() - { - return base.GetType(); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public override string ToString() - { - return base.ToString(); - } } } \ No newline at end of file diff --git a/Skeleton.Infrastructure.Orm/AsyncCachedEntityReader.cs b/Skeleton.Infrastructure.Orm/AsyncCachedEntityReader.cs index f89e212..59fa461 100644 --- a/Skeleton.Infrastructure.Orm/AsyncCachedEntityReader.cs +++ b/Skeleton.Infrastructure.Orm/AsyncCachedEntityReader.cs @@ -13,7 +13,7 @@ namespace Skeleton.Infrastructure.Orm public sealed class AsyncCachedEntityReader : AsyncEntityReader, IAsyncCachedEntityReader - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { private readonly CacheKeyGenerator _keyGenerator = new CacheKeyGenerator(); @@ -46,7 +46,7 @@ public override async Task> FindAsync() public override async Task FirstOrDefaultAsync(object id) { - id.ThrowIfNull(nameof(id)); + id.ThrowIfNull(); LastGeneratedCacheKey = _keyGenerator.ForFirstOrDefault(id); diff --git a/Skeleton.Infrastructure.Orm/AsyncEntityReader.cs b/Skeleton.Infrastructure.Orm/AsyncEntityReader.cs index 88b653f..4625f66 100644 --- a/Skeleton.Infrastructure.Orm/AsyncEntityReader.cs +++ b/Skeleton.Infrastructure.Orm/AsyncEntityReader.cs @@ -15,7 +15,7 @@ namespace Skeleton.Infrastructure.Orm public class AsyncEntityReader : DisposableBase, IAsyncEntityReader - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { private readonly IAsyncDatabase _database; @@ -45,7 +45,7 @@ public virtual async Task> FindAsync() public virtual async Task FirstOrDefaultAsync(object id) { - id.ThrowIfNull(nameof(id)); + id.ThrowIfNull(); Builder.QueryByPrimaryKey( e => e.Id.Equals(id)); @@ -78,7 +78,7 @@ public virtual async Task> QueryAsync(IQuery query) public IAsyncEntityReader GroupBy( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.GroupBy(expression); return this; @@ -86,9 +86,9 @@ public virtual async Task> QueryAsync(IQuery query) public IAsyncEntityReader LeftJoin( Expression> expression) - where TEntity2 : class, IEntity + where TEntity2 : class, IEntity, new() { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Join(expression, JoinType.Left); return this; @@ -96,9 +96,9 @@ public virtual async Task> QueryAsync(IQuery query) public IAsyncEntityReader RightJoin( Expression> expression) - where TEntity2 : class, IEntity + where TEntity2 : class, IEntity, new() { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Join(expression, JoinType.Right); return this; @@ -106,9 +106,9 @@ public virtual async Task> QueryAsync(IQuery query) public IAsyncEntityReader InnerJoin( Expression> expression) - where TEntity2 : class, IEntity + where TEntity2 : class, IEntity, new() { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Join(expression, JoinType.Inner); return this; @@ -117,7 +117,7 @@ public virtual async Task> QueryAsync(IQuery query) public IAsyncEntityReader OrderBy( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.OrderBy(expression); return this; @@ -126,7 +126,7 @@ public virtual async Task> QueryAsync(IQuery query) public IAsyncEntityReader OrderByDescending( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.OrderByDescending(expression); return this; @@ -135,7 +135,7 @@ public virtual async Task> QueryAsync(IQuery query) public IAsyncEntityReader Select( params Expression>[] expressions) { - expressions.ThrowIfNull(nameof(expressions)); + expressions.ThrowIfNull(); foreach (var expression in expressions) Builder.Select(expression); @@ -146,7 +146,7 @@ public virtual async Task> QueryAsync(IQuery query) public IAsyncEntityReader Distinct( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Aggregate(expression, SelectFunction.Distinct); return this; @@ -162,7 +162,8 @@ public IAsyncEntityReader Top(int take) public IAsyncEntityReader Where( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); + return And(expression); } @@ -170,7 +171,7 @@ public IAsyncEntityReader Top(int take) Expression> expression, IEnumerable values) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.WhereIsIn(expression, values); return this; @@ -180,7 +181,7 @@ public IAsyncEntityReader Top(int take) Expression> expression, IEnumerable values) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.WhereNotIn(expression, values); return this; @@ -189,7 +190,7 @@ public IAsyncEntityReader Top(int take) public async Task> AverageAsync( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Aggregate(expression, SelectFunction.Avg); return await AggregateAsync(); @@ -214,7 +215,7 @@ public async Task CountAsync() public async Task> CountAsync( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Aggregate(expression, SelectFunction.Count); return await AggregateAsync(); @@ -223,7 +224,7 @@ public async Task CountAsync() public async Task> MaxAsync( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Aggregate(expression, SelectFunction.Max); return await AggregateAsync(); @@ -232,7 +233,7 @@ public async Task CountAsync() public async Task> MinAsync( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Aggregate(expression, SelectFunction.Min); return await AggregateAsync(); @@ -241,7 +242,7 @@ public async Task CountAsync() public async Task> SumAsync( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Aggregate(expression, SelectFunction.Sum); return await AggregateAsync(); @@ -270,7 +271,7 @@ protected override void DisposeManagedResources() private IAsyncEntityReader And( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.ResolveQuery(expression); return this; diff --git a/Skeleton.Infrastructure.Orm/AsyncEntityWriter.cs b/Skeleton.Infrastructure.Orm/AsyncEntityWriter.cs index 1caef02..d55a444 100644 --- a/Skeleton.Infrastructure.Orm/AsyncEntityWriter.cs +++ b/Skeleton.Infrastructure.Orm/AsyncEntityWriter.cs @@ -4,7 +4,9 @@ using Skeleton.Abstraction.Reflection; using Skeleton.Core; using Skeleton.Infrastructure.Orm.SqlBuilder; +using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Threading.Tasks; namespace Skeleton.Infrastructure.Orm @@ -12,10 +14,11 @@ namespace Skeleton.Infrastructure.Orm public class AsyncEntityWriter : DisposableBase, IAsyncEntityWriter - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { private readonly IMetadataProvider _metadataProvider; private readonly IAsyncDatabase _database; + private const string Error = "Entity Id is {0} null. {1} is canceled"; public AsyncEntityWriter( IMetadataProvider metadataProvider, @@ -27,7 +30,7 @@ public class AsyncEntityWriter : public virtual async Task AddAsync(TEntity entity) { - entity.ThrowIfNull(nameof(entity)); + entity.ThrowIfNull(); return await AddCommand(entity) != null; } @@ -35,7 +38,7 @@ public virtual async Task AddAsync(TEntity entity) public virtual async Task AddAsync(IEnumerable entities) { var enumerable = entities.AsList(); - enumerable.ThrowIfNullOrEmpty(nameof(enumerable)); + enumerable.ThrowIfNullOrEmpty(); var count = 0; using (var transaction = _database.Transaction) @@ -56,17 +59,17 @@ public virtual async Task AddAsync(IEnumerable entities) public virtual async Task DeleteAsync(TEntity entity) { - entity.ThrowIfNull(nameof(entity)); + entity.ThrowIfNull(); return await DeleteCommand(entity) > 0; } public virtual async Task DeleteAsync(IEnumerable entities) { - var enumerable = entities.AsList(); - enumerable.ThrowIfNullOrEmpty(nameof(enumerable)); int count = 0, result = 0; - + var enumerable = entities.AsList(); + enumerable.ThrowIfNullOrEmpty(); + using (var transaction = _database.Transaction) { transaction.Begin(); @@ -94,7 +97,7 @@ public virtual async Task SaveAsync(TEntity entity) public virtual async Task SaveAsync(IEnumerable entities) { var enumerable = entities.AsList(); - enumerable.ThrowIfNullOrEmpty(nameof(enumerable)); + enumerable.ThrowIfNullOrEmpty(); var result = false; using (var transaction = _database.Transaction) @@ -112,17 +115,17 @@ public virtual async Task SaveAsync(IEnumerable entities) public virtual async Task UpdateAsync(TEntity entity) { - entity.ThrowIfNull(nameof(entity)); + entity.ThrowIfNull(); return await UpdateCommand(entity) > 0; } public virtual async Task UpdateAsync(IEnumerable entities) { - var enumerable = entities.AsList(); - enumerable.ThrowIfNullOrEmpty(nameof(enumerable)); int count = 0, result = 0; - + var enumerable = entities.AsList(); + enumerable.ThrowIfNullOrEmpty(); + using (var transaction = _database.Transaction) { transaction.Begin(); @@ -147,6 +150,9 @@ protected override void DisposeManagedResources() private async Task AddCommand(TEntity entity) { + if (entity.Id.IsNotZeroOrEmpty()) + throw new ArgumentException(Error.FormatWith("not", nameof(AddCommand))); + var builder = new InsertCommandBuilder( _metadataProvider, entity); @@ -166,6 +172,8 @@ private async Task AddCommand(TEntity entity) private async Task DeleteCommand(TEntity entity) { + EnsureEntityIdExists(entity); + var builder = new DeleteCommandBuilder( _metadataProvider, entity); @@ -176,6 +184,8 @@ private async Task DeleteCommand(TEntity entity) private async Task UpdateCommand(TEntity entity) { + EnsureEntityIdExists(entity); + var builder = new UpdateCommandBuilder( _metadataProvider, entity); @@ -183,5 +193,11 @@ private async Task UpdateCommand(TEntity entity) builder.SqlCommand) .ConfigureAwait(false); } + + private static void EnsureEntityIdExists(TEntity entity, [CallerMemberName] string name = null) + { + if (entity.Id.IsZeroOrEmpty()) + throw new ArgumentException(Error.FormatWith(string.Empty, name)); + } } } \ No newline at end of file diff --git a/Skeleton.Infrastructure.Orm/AsyncStoredProcedureExecutor.cs b/Skeleton.Infrastructure.Orm/AsyncStoredProcedureExecutor.cs index 2ab9b68..281c8eb 100644 --- a/Skeleton.Infrastructure.Orm/AsyncStoredProcedureExecutor.cs +++ b/Skeleton.Infrastructure.Orm/AsyncStoredProcedureExecutor.cs @@ -20,8 +20,8 @@ public AsyncStoredProcedureExecutor(IAsyncDatabase database) public async Task ExecuteAsync(string storedProcedureName, IDictionary parameters) { - storedProcedureName.ThrowIfNullOrEmpty(nameof(storedProcedureName)); - parameters.ThrowIfNull(nameof(parameters)); + storedProcedureName.ThrowIfNullOrEmpty(); + parameters.ThrowIfNull(); var command = new SqlCommand(storedProcedureName, parameters); diff --git a/Skeleton.Infrastructure.Orm/CacheKeyGenerator.cs b/Skeleton.Infrastructure.Orm/CacheKeyGenerator.cs index 4fde6f1..bf8eeaa 100644 --- a/Skeleton.Infrastructure.Orm/CacheKeyGenerator.cs +++ b/Skeleton.Infrastructure.Orm/CacheKeyGenerator.cs @@ -4,7 +4,7 @@ namespace Skeleton.Infrastructure.Orm { internal class CacheKeyGenerator - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { public CacheKeyGenerator() { @@ -15,7 +15,7 @@ public CacheKeyGenerator() internal string ForFind(string query) { - query.ThrowIfNullOrEmpty(nameof(query)); + query.ThrowIfNullOrEmpty(); return Template.Find.FormatWith( Prefix, @@ -25,7 +25,7 @@ internal string ForFind(string query) internal string ForFirstOrDefault(object id) { - id.ThrowIfNull(nameof(id)); + id.ThrowIfNull(); return Template.FirstOrDefault.FormatWith( Prefix, @@ -35,7 +35,7 @@ internal string ForFirstOrDefault(object id) internal string ForFirstOrDefault(string query) { - query.ThrowIfNullOrEmpty(nameof(query)); + query.ThrowIfNullOrEmpty(); return Template.FirstOrDefault.FormatWith( Prefix, diff --git a/Skeleton.Infrastructure.Orm/CachedEntityReader.cs b/Skeleton.Infrastructure.Orm/CachedEntityReader.cs index aebb0ea..e129f8e 100644 --- a/Skeleton.Infrastructure.Orm/CachedEntityReader.cs +++ b/Skeleton.Infrastructure.Orm/CachedEntityReader.cs @@ -12,7 +12,7 @@ namespace Skeleton.Infrastructure.Orm public sealed class CachedEntityReader : EntityReader, ICachedEntityReader - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { private readonly CacheKeyGenerator _keyGenerator; @@ -22,7 +22,7 @@ public sealed class CachedEntityReader : ICacheProvider cacheProvider) : base(metadataProvider, database) { - cacheProvider.ThrowIfNull(nameof(cacheProvider)); + cacheProvider.ThrowIfNull(); Cache = cacheProvider; _keyGenerator = new CacheKeyGenerator(); @@ -46,7 +46,7 @@ public override IEnumerable Find() public override TEntity FirstOrDefault(object id) { - id.ThrowIfNull(nameof(id)); + id.ThrowIfNull(); LastGeneratedCacheKey = _keyGenerator.ForFirstOrDefault(id); diff --git a/Skeleton.Infrastructure.Orm/EntityMapper.cs b/Skeleton.Infrastructure.Orm/EntityMapper.cs index b3f6efe..d12d736 100644 --- a/Skeleton.Infrastructure.Orm/EntityMapper.cs +++ b/Skeleton.Infrastructure.Orm/EntityMapper.cs @@ -10,8 +10,8 @@ namespace Skeleton.Infrastructure.Orm public sealed class EntityMapper : HideObjectMethodsBase, IEntityMapper - where TEntity : class, IEntity - where TDto : class + where TEntity : class, IEntity, new() + where TDto : class, new() { private readonly IMetadata _dtoMetadata; private readonly IMetadata _entityMetadata; @@ -22,8 +22,6 @@ public sealed class EntityMapper : public EntityMapper(IMetadataProvider metadataProvider) { - metadataProvider.ThrowIfNull(nameof(metadataProvider)); - _dtoMetadata = metadataProvider.GetMetadata(); _dtoInstanceAccessor = _dtoMetadata.GetConstructor(); _dtoProperties = _dtoMetadata.GetDeclaredOnlyProperties(); @@ -35,13 +33,15 @@ public EntityMapper(IMetadataProvider metadataProvider) public IEnumerable Map(IEnumerable entities) { - entities.ThrowIfNullOrEmpty(nameof(entities)); + entities.ThrowIfNullOrEmpty(); return entities.Select(Map).AsList(); } public TDto Map(TEntity entity) { + entity.ThrowIfNull(); + var instanceDto = _dtoInstanceAccessor.InstanceCreator(null) as TDto; foreach (var entityProperty in _entityProperties) @@ -54,13 +54,15 @@ public TDto Map(TEntity entity) public IEnumerable Map(IEnumerable dtos) { - dtos.ThrowIfNullOrEmpty(nameof(dtos)); + dtos.ThrowIfNullOrEmpty(); return dtos.Select(Map).AsList(); } public TEntity Map(TDto dto) { + dto.ThrowIfNull(); + var instanceEntity = _entityInstanceAccessor.InstanceCreator(null) as TEntity; foreach (var dtoProperty in _dtoProperties) diff --git a/Skeleton.Infrastructure.Orm/EntityReader.cs b/Skeleton.Infrastructure.Orm/EntityReader.cs index 367e5b4..1ae5a54 100644 --- a/Skeleton.Infrastructure.Orm/EntityReader.cs +++ b/Skeleton.Infrastructure.Orm/EntityReader.cs @@ -14,7 +14,7 @@ namespace Skeleton.Infrastructure.Orm public class EntityReader : DisposableBase, IEntityReader - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { private readonly IDatabase _database; @@ -42,7 +42,7 @@ public virtual TEntity FirstOrDefault() public virtual TEntity FirstOrDefault(object id) { - id.ThrowIfNull(nameof(id)); + id.ThrowIfNull(); Builder.QueryByPrimaryKey(e => e.Id.Equals(id)); @@ -63,7 +63,7 @@ public virtual IEnumerable Query(IQuery query) public IEntityReader GroupBy( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.GroupBy(expression); return this; @@ -71,9 +71,9 @@ public virtual IEnumerable Query(IQuery query) public IEntityReader LeftJoin( Expression> expression) - where TEntity2 : class, IEntity + where TEntity2 : class, IEntity, new() { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Join(expression, JoinType.Left); return this; @@ -81,9 +81,9 @@ public virtual IEnumerable Query(IQuery query) public IEntityReader RightJoin( Expression> expression) - where TEntity2 : class, IEntity + where TEntity2 : class, IEntity, new() { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Join(expression, JoinType.Right); return this; @@ -91,9 +91,9 @@ public virtual IEnumerable Query(IQuery query) public IEntityReader InnerJoin( Expression> expression) - where TEntity2 : class, IEntity + where TEntity2 : class, IEntity, new() { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Join(expression, JoinType.Inner); return this; @@ -102,7 +102,7 @@ public virtual IEnumerable Query(IQuery query) public IEntityReader OrderBy( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.OrderBy(expression); return this; @@ -111,7 +111,7 @@ public virtual IEnumerable Query(IQuery query) public IEntityReader OrderByDescending( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.OrderByDescending(expression); return this; @@ -120,7 +120,7 @@ public virtual IEnumerable Query(IQuery query) public IEntityReader Select( params Expression>[] expressions) { - expressions.ThrowIfNull(nameof(expressions)); + expressions.ThrowIfNull(); foreach (var expression in expressions) Builder.Select(expression); @@ -131,7 +131,7 @@ public virtual IEnumerable Query(IQuery query) public IEntityReader Distinct( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Aggregate(expression, SelectFunction.Distinct); return this; @@ -147,7 +147,8 @@ public IEntityReader Top(int take) public IEntityReader Where( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); + return And(expression); } @@ -155,7 +156,7 @@ public IEntityReader Top(int take) Expression> expression, IEnumerable values) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.WhereIsIn(expression, values); return this; @@ -165,7 +166,7 @@ public IEntityReader Top(int take) Expression> expression, IEnumerable values) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.WhereNotIn(expression, values); return this; @@ -174,7 +175,7 @@ public IEntityReader Top(int take) public IEnumerable Average( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Aggregate(expression, SelectFunction.Avg); return Aggregate(); @@ -192,7 +193,7 @@ public int Count() public IEnumerable Count( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Aggregate(expression, SelectFunction.Count); return Aggregate(); @@ -201,7 +202,7 @@ public int Count() public IEnumerable Max( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Aggregate(expression, SelectFunction.Max); return Aggregate(); @@ -210,7 +211,7 @@ public int Count() public IEnumerable Min( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Aggregate(expression, SelectFunction.Min); return Aggregate(); @@ -219,7 +220,7 @@ public int Count() public IEnumerable Sum( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.Aggregate(expression, SelectFunction.Sum); return Aggregate(); @@ -241,7 +242,7 @@ protected override void DisposeManagedResources() private IEntityReader And( Expression> expression) { - expression.ThrowIfNull(nameof(expression)); + expression.ThrowIfNull(); Builder.ResolveQuery(expression); return this; diff --git a/Skeleton.Infrastructure.Orm/EntityWriter.cs b/Skeleton.Infrastructure.Orm/EntityWriter.cs index ead13da..acfaf16 100644 --- a/Skeleton.Infrastructure.Orm/EntityWriter.cs +++ b/Skeleton.Infrastructure.Orm/EntityWriter.cs @@ -13,11 +13,11 @@ namespace Skeleton.Infrastructure.Orm public class EntityWriter : DisposableBase, IEntityWriter - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { private readonly IMetadataProvider _metadataProvider; private readonly IDatabase _database; - private const string Error = "Entity Id is not null. {0} is canceled"; + private const string Error = "Entity Id is {0} null. {1} is canceled"; public EntityWriter( IMetadataProvider metadataProvider, @@ -29,14 +29,14 @@ public class EntityWriter : public virtual bool Add(TEntity entity) { - entity.ThrowIfNull(nameof(entity)); + entity.ThrowIfNull(); return AddCommand(entity) != null; } public virtual bool Add(IEnumerable entities) { - entities.ThrowIfNullOrEmpty(nameof(entities)); + entities.ThrowIfNullOrEmpty(); var enumerable = entities.AsList(); var count = 0; @@ -59,14 +59,14 @@ public virtual bool Add(IEnumerable entities) public virtual bool Delete(TEntity entity) { - entity.ThrowIfNull(nameof(entity)); + entity.ThrowIfNull(); return DeleteCommand(entity) > 0; } public virtual bool Delete(IEnumerable entities) { - entities.ThrowIfNullOrEmpty(nameof(entities)); + entities.ThrowIfNullOrEmpty(); var enumerable = entities.AsList(); int count = 0, result = 0; @@ -89,7 +89,7 @@ public virtual bool Delete(IEnumerable entities) public virtual bool Save(TEntity entity) { - entity.ThrowIfNull(nameof(entity)); + entity.ThrowIfNull(); return entity.Id.IsZeroOrEmpty() ? Add(entity) @@ -98,7 +98,7 @@ public virtual bool Save(TEntity entity) public virtual bool Save(IEnumerable entities) { - entities.ThrowIfNullOrEmpty(nameof(entities)); + entities.ThrowIfNullOrEmpty(); var enumerable = entities.AsList(); var result = false; @@ -117,14 +117,14 @@ public virtual bool Save(IEnumerable entities) public virtual bool Update(TEntity entity) { - entity.ThrowIfNull(nameof(entity)); + entity.ThrowIfNull(); return UpdateCommand(entity) > 0; } public virtual bool Update(IEnumerable entities) { - entities.ThrowIfNullOrEmpty(nameof(entities)); + entities.ThrowIfNullOrEmpty(); var enumerable = entities.AsList(); int count = 0, result = 0; @@ -154,7 +154,7 @@ protected override void DisposeManagedResources() private object AddCommand(TEntity entity) { if (entity.Id.IsNotZeroOrEmpty()) - throw new ArgumentException(Error.FormatWith(nameof(AddCommand))); + throw new ArgumentException(Error.FormatWith("not", nameof(AddCommand))); var builder = new InsertCommandBuilder( _metadataProvider, entity); @@ -196,7 +196,7 @@ private int UpdateCommand(TEntity entity) private static void EnsureEntityIdExists(TEntity entity, [CallerMemberName] string name = "") { if (entity.Id.IsZeroOrEmpty()) - throw new ArgumentException(Error.FormatWith(name)); + throw new ArgumentException(Error.FormatWith(string.Empty, name)); } } } \ No newline at end of file diff --git a/Skeleton.Infrastructure.Orm/SqlBuilder/DeleteCommandBuilder.cs b/Skeleton.Infrastructure.Orm/SqlBuilder/DeleteCommandBuilder.cs index b57aa5b..08410e0 100644 --- a/Skeleton.Infrastructure.Orm/SqlBuilder/DeleteCommandBuilder.cs +++ b/Skeleton.Infrastructure.Orm/SqlBuilder/DeleteCommandBuilder.cs @@ -6,7 +6,7 @@ namespace Skeleton.Infrastructure.Orm.SqlBuilder { internal sealed class DeleteCommandBuilder : SqlBuilderBase - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { private CommandContext _context = new CommandContext(); diff --git a/Skeleton.Infrastructure.Orm/SqlBuilder/InsertCommandBuilder.cs b/Skeleton.Infrastructure.Orm/SqlBuilder/InsertCommandBuilder.cs index e80f5d2..bc1088f 100644 --- a/Skeleton.Infrastructure.Orm/SqlBuilder/InsertCommandBuilder.cs +++ b/Skeleton.Infrastructure.Orm/SqlBuilder/InsertCommandBuilder.cs @@ -5,7 +5,7 @@ namespace Skeleton.Infrastructure.Orm.SqlBuilder { internal sealed class InsertCommandBuilder : SqlBuilderBase - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { private const string ScopeIdentity = "SELECT scope_identity() AS [SCOPE_IDENTITY]"; private CommandContext _context = new CommandContext(); diff --git a/Skeleton.Infrastructure.Orm/SqlBuilder/QueryEvaluator.cs b/Skeleton.Infrastructure.Orm/SqlBuilder/QueryEvaluator.cs index e36c636..905ab88 100644 --- a/Skeleton.Infrastructure.Orm/SqlBuilder/QueryEvaluator.cs +++ b/Skeleton.Infrastructure.Orm/SqlBuilder/QueryEvaluator.cs @@ -7,7 +7,7 @@ namespace Skeleton.Infrastructure.Orm.SqlBuilder { internal class QueryEvaluator - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { private readonly SelectQueryBuilder _builder; private readonly IQuery _query; diff --git a/Skeleton.Infrastructure.Orm/SqlBuilder/SelectQueryBuilder.cs b/Skeleton.Infrastructure.Orm/SqlBuilder/SelectQueryBuilder.cs index 4242a27..0f5a4b8 100644 --- a/Skeleton.Infrastructure.Orm/SqlBuilder/SelectQueryBuilder.cs +++ b/Skeleton.Infrastructure.Orm/SqlBuilder/SelectQueryBuilder.cs @@ -9,7 +9,7 @@ namespace Skeleton.Infrastructure.Orm.SqlBuilder { internal class SelectQueryBuilder : SqlBuilderBase - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { private const string PagingTemplate = " OFFSET {0} ROWS FETCH NEXT {1} ROWS ONLY"; diff --git a/Skeleton.Infrastructure.Orm/SqlBuilder/SqlBuilderBase.cs b/Skeleton.Infrastructure.Orm/SqlBuilder/SqlBuilderBase.cs index 66ecf1c..f3c865e 100644 --- a/Skeleton.Infrastructure.Orm/SqlBuilder/SqlBuilderBase.cs +++ b/Skeleton.Infrastructure.Orm/SqlBuilder/SqlBuilderBase.cs @@ -13,7 +13,7 @@ namespace Skeleton.Infrastructure.Orm.SqlBuilder { [DebuggerDisplay("EntityName = {TableName}")] internal abstract class SqlBuilderBase - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { private readonly IMetadata _metadata; private readonly IInstanceAccessor _entityInstanceAccessor; diff --git a/Skeleton.Infrastructure.Orm/SqlBuilder/UpdateCommandBuilder.cs b/Skeleton.Infrastructure.Orm/SqlBuilder/UpdateCommandBuilder.cs index a21555e..0890eb1 100644 --- a/Skeleton.Infrastructure.Orm/SqlBuilder/UpdateCommandBuilder.cs +++ b/Skeleton.Infrastructure.Orm/SqlBuilder/UpdateCommandBuilder.cs @@ -6,7 +6,7 @@ namespace Skeleton.Infrastructure.Orm.SqlBuilder { internal sealed class UpdateCommandBuilder : SqlBuilderBase - where TEntity : class, IEntity + where TEntity : class, IEntity, new() { private CommandContext _context = new CommandContext(); diff --git a/Skeleton.Infrastructure.Orm/StoredProcedureExecutor.cs b/Skeleton.Infrastructure.Orm/StoredProcedureExecutor.cs index c1567b1..e78ad7f 100644 --- a/Skeleton.Infrastructure.Orm/StoredProcedureExecutor.cs +++ b/Skeleton.Infrastructure.Orm/StoredProcedureExecutor.cs @@ -19,8 +19,8 @@ public StoredProcedureExecutor(IDatabase database) public int Execute(string storedProcedureName, IDictionary parameters) { - storedProcedureName.ThrowIfNullOrEmpty(nameof(storedProcedureName)); - parameters.ThrowIfNull(nameof(parameters)); + storedProcedureName.ThrowIfNullOrEmpty(); + parameters.ThrowIfNull(); var command = new SqlCommand(storedProcedureName, parameters); diff --git a/Skeleton.Tests.Common/AppConfiguration.cs b/Skeleton.Tests.Common/AppConfiguration.cs index d0fcb24..3f3fed6 100644 --- a/Skeleton.Tests.Common/AppConfiguration.cs +++ b/Skeleton.Tests.Common/AppConfiguration.cs @@ -5,10 +5,11 @@ namespace Skeleton.Tests.Common { public static class AppConfiguration { - private const string CustomersPath = "api/customers"; - private const string CachedCustomersPath = "api/cachedcustomers"; - private const string AsyncCustomersPath = "api/asynccustomers"; - private const string AsyncCachedCustomersPath = "api/asynccachedcustomers"; + public const string CustomersResource = "customers"; + public const string CachedCustomersResource = "cachedcustomers"; + public const string AsyncCustomersResource = "asynccustomers"; + public const string AsyncCachedCustomersResource = "asynccachedcustomers"; + public const string LogResource = "log"; public static bool AppVeyorBuild => Environment.GetEnvironmentVariable("AppVeyor")?.ToUpperInvariant() == "TRUE"; @@ -18,10 +19,6 @@ public static class AppConfiguration public static string Host => "localhost"; public static int Port => 8081; - public static IRestUriBuilder CustomersUriBuilder => new RestUriBuilder(Host, Port, CustomersPath); - public static IRestUriBuilder CachedCustomersUriBuilder => new RestUriBuilder(Host, Port, CachedCustomersPath); - public static IRestUriBuilder AsyncCustomersUriBuilder => new RestUriBuilder(Host, Port, AsyncCustomersPath); - public static IRestUriBuilder AsyncCachedCustomersUriBuilder => new RestUriBuilder(Host, Port, AsyncCachedCustomersPath); - public static Uri BaseUrl => new UriBuilder("http", Host, Port).Uri; + public static Uri BaseAddress => new UriBuilder("http", Host, Port).Uri; } } \ No newline at end of file diff --git a/Skeleton.Tests.Web/HttpClientAsyncCachedEntityReaderTests.cs b/Skeleton.Tests.Web/HttpClientAsyncCachedEntityReaderTests.cs index ec0baf2..0363fe8 100644 --- a/Skeleton.Tests.Web/HttpClientAsyncCachedEntityReaderTests.cs +++ b/Skeleton.Tests.Web/HttpClientAsyncCachedEntityReaderTests.cs @@ -1,7 +1,10 @@ using NUnit.Framework; using Skeleton.Tests.Common; using Skeleton.Web.Client; +using System; +using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading.Tasks; namespace Skeleton.Tests.Web @@ -9,53 +12,75 @@ namespace Skeleton.Tests.Web [TestFixture] public class HttpClientAsyncCachedEntityReaderTests { - private readonly AsyncJsonCrudHttpClient Client = - new AsyncJsonCrudHttpClient(AppConfiguration.AsyncCachedCustomersUriBuilder); + private const int PageSize = 50; + private const int NumberOfPages = 5; + + private readonly RestClient _client = new RestClient(new Uri(AppConfiguration.BaseAddress, "api/asynccachedcustomers")); [Test] - public async Task AsyncCachedEntityReader_GetAllAsync() + public async Task CachedEntityReader_GetAllAsync() { - var results = await Client.GetAllAsync(); + var request = new RestRequest("getall"); + var results = await _client.GetAsync>(request); Assert.IsNotNull(results); Assert.IsInstanceOf(typeof(CustomerDto), results.First()); } [Test] - public async Task AsyncCachedEntityReader_FirstOrDefaultAsync() + public async Task CachedEntityReader_FirstOrDefaultAsync() { - var data = await Client.QueryAsync(new Query { PageSize = 1, PageNumber = 1 }); - var first = data.Items.FirstOrDefault(); - - Assert.IsNotNull(first); + var data = await _client + .GetAsync>( + r => r.AddResource("query") + .AddQueryParameters(new Query { PageSize = 1, PageNumber = 1 })); - var result = await Client.FirstOrDefaultAsync(first.CustomerId); + Assert.IsNotNull(data); + var customer = data.Items.FirstOrDefault(); + var result = _client.Get( + r => r.AddResource("firstordefault") + .AddResource(customer.CustomerId.ToString())); Assert.IsNotNull(result); Assert.IsInstanceOf(typeof(CustomerDto), result); } [Test] - public void AsyncCachedEntityReader_FirstOrDefaultAsync_With_Wrong_Id() + public async Task CachedEntityReader_FirstOrDefaultAsync_With_Wrong_Id() { - Assert.CatchAsync(typeof(HttpResponseMessageException), async () => await Client.FirstOrDefaultAsync(100000)); + var result = await _client.GetAsync(r => r.AddResource("firstordefault/100000")); + Assert.IsTrue(result.StatusCode == HttpStatusCode.NotFound); } [Test] - public async Task AsyncCachedEntityReader_Page() + public async Task CachedEntityReader_PageAsync() { - const int pageSize = 50; - const int numberOfPages = 5; - - for (var page = 1; page < numberOfPages; ++page) + for (var page = 1; page < NumberOfPages; ++page) { - var response = await Client.QueryAsync(new Query - { - PageSize = pageSize, - PageNumber = page - }); - Assert.IsTrue(response.Items.Count() <= pageSize); + var request = new RestRequest("query") + .AddQueryParameters(new Query { PageSize = PageSize, PageNumber = page }); + var result = await _client.GetAsync>(request); + + Assert.IsTrue(result.Items.Count() <= PageSize); } } + + [Test] + public async Task CachedEntityReader_QueryAsync() + { + var request = new RestRequest("query") + .AddQueryParameters( + new Query + { + Fields = "CustomerId,Name", + OrderBy = "CustomerId,-Name", + PageSize = 50, + PageNumber = 1 + }); + + var response = await _client.GetAsync(request); + + Assert.IsNotNull(response); + } } } \ No newline at end of file diff --git a/Skeleton.Tests.Web/HttpClientAsyncEntityReaderTests.cs b/Skeleton.Tests.Web/HttpClientAsyncEntityReaderTests.cs index 723142f..ae96a93 100644 --- a/Skeleton.Tests.Web/HttpClientAsyncEntityReaderTests.cs +++ b/Skeleton.Tests.Web/HttpClientAsyncEntityReaderTests.cs @@ -1,7 +1,10 @@ using NUnit.Framework; using Skeleton.Tests.Common; using Skeleton.Web.Client; +using System; +using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading.Tasks; namespace Skeleton.Tests.Web @@ -9,53 +12,75 @@ namespace Skeleton.Tests.Web [TestFixture] public class HttpClientAsyncEntityReaderTests { - private readonly AsyncJsonCrudHttpClient Client = - new AsyncJsonCrudHttpClient(AppConfiguration.AsyncCustomersUriBuilder); + private const int PageSize = 50; + private const int NumberOfPages = 5; + + private readonly RestClient _client = new RestClient(new Uri(AppConfiguration.BaseAddress, "api/asynccustomers")); [Test] - public async Task AsyncEntityReader_GetAllAsync() + public async Task EntityReader_GetAllAsync() { - var results = await Client.GetAllAsync(); + var request = new RestRequest("getall"); + var results = await _client.GetAsync>(request); Assert.IsNotNull(results); Assert.IsInstanceOf(typeof(CustomerDto), results.First()); } [Test] - public async Task AsyncEntityReader_FirstOrDefaultAsync() + public async Task EntityReader_FirstOrDefaultAsync() { - var data = await Client.QueryAsync(new Query { PageSize = 1, PageNumber = 1 }); - var firstCustomer = data.Items.FirstOrDefault(); - - Assert.IsNotNull(firstCustomer); + var data = await _client + .GetAsync>( + r => r.AddResource("query") + .AddQueryParameters(new Query { PageSize = 1, PageNumber = 1 })); - var result = await Client.FirstOrDefaultAsync(firstCustomer.CustomerId); + Assert.IsNotNull(data); + var customer = data.Items.FirstOrDefault(); + var result = _client.Get( + r => r.AddResource("firstordefault") + .AddResource(customer.CustomerId.ToString())); Assert.IsNotNull(result); Assert.IsInstanceOf(typeof(CustomerDto), result); } [Test] - public void AsyncEntityReader_FirstOrDefault_With_Wrong_Id() + public async Task EntityReader_FirstOrDefaultAsync_With_Wrong_Id() { - Assert.CatchAsync(typeof(HttpResponseMessageException), async () => await Client.FirstOrDefaultAsync(100000)); + var result = await _client.GetAsync(r => r.AddResource("firstordefault/100000")); + Assert.IsTrue(result.StatusCode == HttpStatusCode.NotFound); } [Test] - public async Task AsyncEntityReader_PageAsync() + public async Task EntityReader_PageAsync() { - const int pageSize = 50; - const int numberOfPages = 5; - - for (var page = 1; page < numberOfPages; ++page) + for (var page = 1; page < NumberOfPages; ++page) { - var response = await Client.QueryAsync(new Query - { - PageSize = pageSize, - PageNumber = page - }); - Assert.IsTrue(response.Items.Count() <= pageSize); + var request = new RestRequest("query") + .AddQueryParameters(new Query { PageSize = PageSize, PageNumber = page }); + var result = await _client.GetAsync>(request); + + Assert.IsTrue(result.Items.Count() <= PageSize); } } + + [Test] + public async Task EntityReader_QueryAsync() + { + var request = new RestRequest("query") + .AddQueryParameters( + new Query + { + Fields = "CustomerId,Name", + OrderBy = "CustomerId,-Name", + PageSize = 50, + PageNumber = 1 + }); + + var response = await _client.GetAsync(request); + + Assert.IsNotNull(response); + } } } \ No newline at end of file diff --git a/Skeleton.Tests.Web/HttpClientAsyncEntityWriterTests.cs b/Skeleton.Tests.Web/HttpClientAsyncEntityWriterTests.cs index 1e6fe49..de60225 100644 --- a/Skeleton.Tests.Web/HttpClientAsyncEntityWriterTests.cs +++ b/Skeleton.Tests.Web/HttpClientAsyncEntityWriterTests.cs @@ -1,7 +1,10 @@ using NUnit.Framework; using Skeleton.Tests.Common; using Skeleton.Web.Client; +using System; +using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading.Tasks; namespace Skeleton.Tests.Web @@ -9,84 +12,129 @@ namespace Skeleton.Tests.Web [TestFixture] public class HttpClientAsyncEntityWriterTests { - private readonly AsyncJsonCrudHttpClient Client = - new AsyncJsonCrudHttpClient(AppConfiguration.AsyncCustomersUriBuilder); + private readonly RestClient _client = new RestClient(new Uri(AppConfiguration.BaseAddress, "api/asynccustomers")); [Test] - public async Task AsyncEntityWriter_UpdateAsync() + public async Task EntityWriter_UpdateAsync() { - var data = await Client.QueryAsync(new Query { PageSize = 1, PageNumber = 1 }); - var firstCustomer = data.Items.FirstOrDefault(); + var customer = GetPaginatedCustomers(1, 1).FirstOrDefault(); + Assert.IsNotNull(customer); - Assert.IsNotNull(firstCustomer); + var updatedCustomer = new CustomerDto + { + CustomerId = customer.CustomerId, + Name = "CustomerUpdated" + customer.CustomerId, + CustomerCategoryId = customer.CustomerCategoryId + }; + + var response = await _client.PutAsync( + request => request.AddResource("update") + .WithBody(updatedCustomer)); + Assert.IsTrue(response.IsSuccessStatusCode); + } + + [Test] + public async Task EntityWriter_UpdateAsync_With_Wrong_Id() + { var customer = new CustomerDto { - CustomerId = firstCustomer.CustomerId, - Name = "CustomerUpdated" + firstCustomer.CustomerId, - CustomerCategoryId = firstCustomer.CustomerCategoryId + CustomerId = 100000, + Name = "CustomerUpdated" }; - var result = await Client.UpdateAsync(customer); - Assert.IsTrue(result); + var result = await _client.PutAsync( + request => request.AddResource("update") + .WithBody(customer)); + Assert.IsTrue(result.StatusCode == HttpStatusCode.NotFound); } [Test] - public async Task AsyncEntityWriter_BatchUpdateAsync() + public async Task EntityWriter_BatchUpdateAsync() { - var customers = await Client.QueryAsync(new Query { PageSize = 5, PageNumber = 1 }); - + var customers = GetPaginatedCustomers(5, 1); Assert.IsNotNull(customers); - foreach (var customer in customers.Items) + foreach (var customer in customers) customer.Name = "CustomerUpdated" + customer.CustomerId; - var result = await Client.UpdateAsync(customers.Items); - Assert.IsTrue(result); + var result = await _client.PostAsync( + request => request.AddResource("batchupdate").WithBody(customers)); + Assert.IsTrue(result.IsSuccessStatusCode); } [Test] - public async Task AsyncEntityWriter_CreateAsync() + public async Task EntityWriter_CreateAsync() { - var customer = new CustomerDto { Name = "Customer" }; - var result = await Client.CreateAsync(customer); + var customer = MemorySeeder.SeedCustomerDto(); + var result = await _client.PostAsync( + request => request.AddResource("create").WithBody(customer)); Assert.IsNotNull(result); Assert.IsInstanceOf(typeof(CustomerDto), result); } [Test] - public async Task AsyncEntityWriter_BatchCreateAsync() + public async Task EntityWriter_CreateAsync_With_Wrong_Id() + { + var customer = GetPaginatedCustomers(1, 1).FirstOrDefault(); + Assert.IsNotNull(customer); + + var result = await _client.PostAsync( + request => request.AddResource("create").WithBody(customer)); + Assert.IsTrue(result.StatusCode == HttpStatusCode.BadRequest); + } + + [Test] + public async Task EntityWriter_BatchCreateAsync() { var customers = MemorySeeder.SeedCustomerDtos(5).ToList(); - var results = await Client.CreateAsync(customers); + var response = await _client.PostAsync( + request => request.AddResource("batchcreate").WithBody(customers)); + var results = response.AsEnumerable(); Assert.IsNotNull(results); Assert.IsInstanceOf(typeof(CustomerDto), results.First()); } [Test] - public async Task AsyncEntityWriter_DeleteAsync() + public async Task EntityWriter_DeleteAsync() { - var data = await Client.QueryAsync(new Query { PageSize = 1, PageNumber = 1 }); - var firstCustomer = data.Items.FirstOrDefault(); - - Assert.IsNotNull(firstCustomer); + var data = GetPaginatedCustomers(1, 1).FirstOrDefault(); + Assert.IsNotNull(data); - var result = await Client.DeleteAsync(firstCustomer.CustomerId); + var response = await _client.DeleteAsync( + request => request.AddResource("delete") + .AddResource(data.CustomerId.ToString())); - Assert.IsTrue(result); + Assert.IsTrue(response.IsSuccessStatusCode); } [Test] - public async Task AsyncEntityWriter_BatchDeleteAsync() + public async Task EntityWriter_BatchDelete() { - var customers = await Client.QueryAsync(new Query { PageSize = 5, PageNumber = 1 }); - + var customers = GetPaginatedCustomers(5, 1); Assert.IsNotNull(customers); - var result = await Client.DeleteAsync(customers.Items); - Assert.IsTrue(result); + var result = await _client.PostAsync( + request => request.AddResource("batchdelete") + .WithBody(customers)); + Assert.IsTrue(result.IsSuccessStatusCode); + } + + [Test] + public async Task EntityWriter_Delete_With_Wrong_Id() + { + var result = await _client.DeleteAsync(request => request.AddResource("delete/100000")); + Assert.IsTrue(result.StatusCode == HttpStatusCode.NotFound); + } + + private IEnumerable GetPaginatedCustomers(int pageSize, int pageNumber) + { + return _client.GetAsync>( + request => request.AddResource("query") + .AddQueryParameters(new Query { PageSize = pageSize, PageNumber = pageNumber })) + .Result.Items; } } } \ No newline at end of file diff --git a/Skeleton.Tests.Web/HttpClientCachedEntityReaderTests.cs b/Skeleton.Tests.Web/HttpClientCachedEntityReaderTests.cs index 7b20ed5..6de32a6 100644 --- a/Skeleton.Tests.Web/HttpClientCachedEntityReaderTests.cs +++ b/Skeleton.Tests.Web/HttpClientCachedEntityReaderTests.cs @@ -2,60 +2,85 @@ using Skeleton.Tests.Common; using Skeleton.Web.Client; using System.Linq; +using System.Net; +using System; namespace Skeleton.Tests.Web { [TestFixture] public class HttpClientCachedEntityReaderTests { - private readonly JsonCrudHttpClient Client = - new JsonCrudHttpClient(AppConfiguration.CachedCustomersUriBuilder); + private const int PageSize = 50; + private const int NumberOfPages = 5; + + private readonly RestClient _client = new RestClient(new Uri(AppConfiguration.BaseAddress, "api/cachedcustomers")); [Test] - public void CachedEntityReader_GetAll() + public void EntityReader_GetAll() { - var results = Client.GetAll(); + var request = new RestRequest("getall"); + var results = _client.Get(request).AsEnumerable(); Assert.IsNotNull(results); Assert.IsInstanceOf(typeof(CustomerDto), results.First()); } [Test] - public void CachedEntityReader_FirstOrDefault() + public void EntityReader_FirstOrDefault() { - var data = Client - .Query(new Query { PageSize = 1, PageNumber = 1 }) - .Items.FirstOrDefault(); + var data = _client + .Get>( + r => r.AddResource("query") + .AddQueryParameters(new Query { PageSize = 1, PageNumber = 1 })) + .Items + .FirstOrDefault(); Assert.IsNotNull(data); - var result = Client.FirstOrDefault(data.CustomerId); + var result = _client.Get( + r => r.AddResource("firstordefault") + .AddResource(data.CustomerId.ToString())); Assert.IsNotNull(result); Assert.IsInstanceOf(typeof(CustomerDto), result); } [Test] - public void CachedEntityReader_FirstOrDefault_With_Wrong_Id() + public void EntityReader_FirstOrDefault_With_Wrong_Id() { - Assert.Catch(typeof(HttpResponseMessageException), () => Client.FirstOrDefault(1000000)); + var result = _client.Get(r => r.AddResource("firstordefault/100000")); + Assert.IsTrue(result.StatusCode == HttpStatusCode.NotFound); } [Test] - public void CachedEntityReader_Page() + public void EntityReader_Page() { - const int pageSize = 50; - const int numberOfPages = 5; - - for (var page = 1; page < numberOfPages; ++page) + for (var page = 1; page < NumberOfPages; ++page) { - var response = Client.Query(new Query - { - PageSize = pageSize, - PageNumber = page - }); - Assert.IsTrue(response.Items.Count() <= pageSize); + var request = new RestRequest("query") + .AddQueryParameters(new Query { PageSize = PageSize, PageNumber = page }); + var result = _client.Get>(request); + + Assert.IsTrue(result.Items.Count() <= PageSize); } } + + [Test] + public void EntityReader_Query() + { + var request = new RestRequest("query") + .AddQueryParameters( + new Query + { + Fields = "CustomerId,Name", + OrderBy = "CustomerId,-Name", + PageSize = 50, + PageNumber = 1 + }); + + var response = _client.Get(request); + + Assert.IsNotNull(response); + } } } \ No newline at end of file diff --git a/Skeleton.Tests.Web/HttpClientEntityReaderTests.cs b/Skeleton.Tests.Web/HttpClientEntityReaderTests.cs index 1644ddc..8ec768b 100644 --- a/Skeleton.Tests.Web/HttpClientEntityReaderTests.cs +++ b/Skeleton.Tests.Web/HttpClientEntityReaderTests.cs @@ -1,7 +1,9 @@ using NUnit.Framework; using Skeleton.Tests.Common; using Skeleton.Web.Client; +using System; using System.Linq; +using System.Net; namespace Skeleton.Tests.Web { @@ -11,13 +13,13 @@ public class HttpClientEntityReaderTests private const int PageSize = 50; private const int NumberOfPages = 5; - private readonly JsonCrudHttpClient client = - new JsonCrudHttpClient(AppConfiguration.CustomersUriBuilder); + private readonly RestClient _client = new RestClient(new Uri(AppConfiguration.BaseAddress, "api/customers")); [Test] public void EntityReader_GetAll() { - var results = client.GetAll(); + var request = new RestRequest("getall"); + var results = _client.Get(request).AsEnumerable(); Assert.IsNotNull(results); Assert.IsInstanceOf(typeof(CustomerDto), results.First()); @@ -26,13 +28,18 @@ public void EntityReader_GetAll() [Test] public void EntityReader_FirstOrDefault() { - var data = client - .Query(new Query { PageSize = 1, PageNumber = 1 }) - .Items.FirstOrDefault(); + var data = _client + .Get>( + r => r.AddResource("query") + .AddQueryParameters(new Query { PageSize = 1, PageNumber = 1 })) + .Items + .FirstOrDefault(); Assert.IsNotNull(data); - var result = client.FirstOrDefault(data.CustomerId); + var result = _client.Get( + r => r.AddResource("firstordefault") + .AddResource(data.CustomerId.ToString())); Assert.IsNotNull(result); Assert.IsInstanceOf(typeof(CustomerDto), result); @@ -41,7 +48,8 @@ public void EntityReader_FirstOrDefault() [Test] public void EntityReader_FirstOrDefault_With_Wrong_Id() { - Assert.Catch(typeof(HttpResponseMessageException), () => client.FirstOrDefault(100000)); + var result = _client.Get(r => r.AddResource("firstordefault/100000")); + Assert.IsTrue(result.StatusCode == HttpStatusCode.NotFound); } [Test] @@ -49,26 +57,28 @@ public void EntityReader_Page() { for (var page = 1; page < NumberOfPages; ++page) { - var response = client.Query(new Query - { - PageSize = PageSize, - PageNumber = page - }); + var request = new RestRequest("query") + .AddQueryParameters(new Query { PageSize = PageSize, PageNumber = page }); + var result = _client.Get>(request); - Assert.IsTrue(response.Items.Count() <= PageSize); + Assert.IsTrue(result.Items.Count() <= PageSize); } } [Test] public void EntityReader_Query() { - var response = client.Query(new Query - { - Fields = "CustomerId,Name", - OrderBy = "CustomerId,-Name", - PageSize = 50, - PageNumber = 1 - }); + var request = new RestRequest("query") + .AddQueryParameters( + new Query + { + Fields = "CustomerId,Name", + OrderBy = "CustomerId,-Name", + PageSize = 50, + PageNumber = 1 + }); + + var response = _client.Get(request); Assert.IsNotNull(response); } diff --git a/Skeleton.Tests.Web/HttpClientEntityWriterTests.cs b/Skeleton.Tests.Web/HttpClientEntityWriterTests.cs index 5efc4b9..136a053 100644 --- a/Skeleton.Tests.Web/HttpClientEntityWriterTests.cs +++ b/Skeleton.Tests.Web/HttpClientEntityWriterTests.cs @@ -1,34 +1,36 @@ using NUnit.Framework; using Skeleton.Tests.Common; using Skeleton.Web.Client; +using System; +using System.Collections.Generic; using System.Linq; +using System.Net; namespace Skeleton.Tests.Web { [TestFixture] public class HttpClientEntityWriterTests { - private readonly JsonCrudHttpClient Client = - new JsonCrudHttpClient(AppConfiguration.CustomersUriBuilder); + private readonly RestClient _client = new RestClient(new Uri(AppConfiguration.BaseAddress, "api/customers")); [Test] public void EntityWriter_Update() { - var data = Client - .Query(new Query { PageSize = 1, PageNumber = 1 }) - .Items.FirstOrDefault(); + var customer = GetPaginatedCustomers(1, 1).FirstOrDefault(); + Assert.IsNotNull(customer); - Assert.IsNotNull(data); - - var customer = new CustomerDto + var updatedCustomer = new CustomerDto { - CustomerId = data.CustomerId, - Name = "CustomerUpdated" + data.CustomerId, - CustomerCategoryId = data.CustomerCategoryId + CustomerId = customer.CustomerId, + Name = "CustomerUpdated" + customer.CustomerId, + CustomerCategoryId = customer.CustomerCategoryId }; - var result = Client.Update(customer); - Assert.IsTrue(result); + var response = _client.Put( + request => request.AddResource("update") + .WithBody(updatedCustomer)); + + Assert.IsTrue(response.IsSuccessStatusCode); } [Test] @@ -40,28 +42,33 @@ public void EntityWriter_Update_With_Wrong_Id() Name = "CustomerUpdated" }; - Assert.Catch(typeof(HttpResponseMessageException), () => Client.Update(customer)); + var result= _client.Put( + request => request.AddResource("update") + .WithBody(customer)); + Assert.IsTrue(result.StatusCode == HttpStatusCode.NotFound); } [Test] public void EntityWriter_BatchUpdate() { - var customers = Client.Query(new Query { PageSize = 5, PageNumber = 1 }); - + var customers = GetPaginatedCustomers(5, 1); Assert.IsNotNull(customers); - foreach (var customer in customers.Items) + foreach (var customer in customers) customer.Name = "CustomerUpdated" + customer.CustomerId; - var result = Client.Update(customers.Items); - Assert.IsTrue(result); + var result = _client.Post( + request => request.AddResource("batchupdate").WithBody(customers)); + Assert.IsTrue(result.IsSuccessStatusCode); } [Test] public void EntityWriter_Create() { var customer = MemorySeeder.SeedCustomerDto(); - var result = Client.Create(customer); + var result = _client.Post( + request => request.AddResource("create").WithBody(customer)) + .As(); Assert.IsNotNull(result); Assert.IsInstanceOf(typeof(CustomerDto), result); @@ -70,17 +77,19 @@ public void EntityWriter_Create() [Test] public void EntityWriter_Create_With_Wrong_Id() { - var customer = MemorySeeder.SeedCustomerDto(); - customer.CustomerId = 100000; - - Assert.Catch(typeof(HttpResponseMessageException), () => Client.Create(customer)); + var customer = GetPaginatedCustomers(1, 1).FirstOrDefault(); + var result = _client.Post( + request => request.AddResource("create").WithBody(customer)); + Assert.IsTrue(result.StatusCode == HttpStatusCode.BadRequest); } [Test] public void EntityWriter_BatchCreate() { var customers = MemorySeeder.SeedCustomerDtos(5).ToList(); - var results = Client.Create(customers); + var results = _client.Post( + request => request.AddResource("batchcreate").WithBody(customers)) + .AsEnumerable(); Assert.IsNotNull(results); Assert.IsInstanceOf(typeof(CustomerDto), results.First()); @@ -89,11 +98,11 @@ public void EntityWriter_BatchCreate() [Test] public void EntityWriter_Delete() { - var data = Client - .Query(new Query { PageSize = 5, PageNumber = 1 }) - .Items.FirstOrDefault(); - - var result = (data != null) && Client.Delete(data.CustomerId); + var data = GetPaginatedCustomers(1, 1).FirstOrDefault(); + var result = (data != null) && _client.Delete( + request => request.AddResource("delete") + .AddResource(data.CustomerId.ToString())) + .IsSuccessStatusCode; Assert.IsTrue(result); } @@ -101,18 +110,28 @@ public void EntityWriter_Delete() [Test] public void EntityWriter_BatchDelete() { - var customers = Client.Query(new Query { PageSize = 5, PageNumber = 1 }); - + var customers = GetPaginatedCustomers(5, 1); Assert.IsNotNull(customers); - var result = Client.Delete(customers.Items); - Assert.IsTrue(result); + var result = _client.Post( + request => request.AddResource("batchdelete") + .WithBody(customers)); + Assert.IsTrue(result.IsSuccessStatusCode); } [Test] public void EntityWriter_Delete_With_Wrong_Id() { - Assert.Catch(typeof(HttpResponseMessageException), () => Client.Delete(100000)); + var result= _client.Delete(request => request.AddResource("delete/100000")); + Assert.IsTrue(result.StatusCode == HttpStatusCode.NotFound); + } + + private IEnumerable GetPaginatedCustomers(int pageSize, int pageNumber) + { + return _client.Get>( + request => request.AddResource("query") + .AddQueryParameters(new Query { PageSize = pageSize, PageNumber = pageNumber })) + .Items; } } } \ No newline at end of file diff --git a/Skeleton.Tests.Web/HttpClientHealthCheckTests.cs b/Skeleton.Tests.Web/HttpClientHealthCheckTests.cs index b152e15..fc42114 100644 --- a/Skeleton.Tests.Web/HttpClientHealthCheckTests.cs +++ b/Skeleton.Tests.Web/HttpClientHealthCheckTests.cs @@ -1,35 +1,32 @@ using NUnit.Framework; using Skeleton.Tests.Common; using Skeleton.Web.Client; +using System; namespace Skeleton.Tests.Web { [TestFixture] public class HttpClientHealthCheckTests { - private readonly JsonHttpClient Client = - new JsonHttpClient( - new RestUriBuilder(AppConfiguration.Host, AppConfiguration.Port, "api/HealthCheck")); + private readonly RestClient Client = new RestClient(AppConfiguration.BaseAddress); [Test] public void HeartBeat() { - var uri = Client.UriBuilder.Uri; - var response = Client.Get(uri); + var response = Client.Get(r => r.AddResource("api/healthcheck")); Assert.IsTrue(response.IsSuccessStatusCode); } - [Test] - public void Discover_HeartBeat() - { - ClientProvider.RegisterServices(AppConfiguration.BaseUrl); + //[Test] + //public void Discover_HeartBeat() + //{ + // ClientProvider.RegisterServices(AppConfiguration.BaseAddress); - var client = ClientProvider.FindClient("healthcheck"); - var response = client.Get(client.UriBuilder.Uri); - - Assert.IsNotNull(response); - } + // var client = ClientProvider.GetClient("healthcheck"); + // var response = client.Get(client.UriBuilder.Uri); + // Assert.IsNotNull(response); + //} } } \ No newline at end of file diff --git a/Skeleton.Tests.Web/HttpClientLoggerTests.cs b/Skeleton.Tests.Web/HttpClientLoggerTests.cs index ee89aae..1b2ea8b 100644 --- a/Skeleton.Tests.Web/HttpClientLoggerTests.cs +++ b/Skeleton.Tests.Web/HttpClientLoggerTests.cs @@ -7,15 +7,14 @@ namespace Skeleton.Tests.Web [TestFixture] public class HttpClientLoggerTests { - private readonly JsonHttpClient Client = - new JsonHttpClient( - new RestUriBuilder(AppConfiguration.Host, AppConfiguration.Port, "api/log")); + private readonly RestClient _client = new RestClient(AppConfiguration.BaseAddress, new NoRetryPolicy()); [Test] public void Logger_LogInfo() { - var uri = Client.UriBuilder.StartNew().AppendAction("info").Uri; - var response = Client.Post(uri, "This is an INFO log message"); + var response = _client.Post( + r => r.AddResource("api/log/info") + .WithBody("This is an INFO log message")); Assert.IsTrue(response.IsSuccessStatusCode); } @@ -23,8 +22,9 @@ public void Logger_LogInfo() [Test] public void Logger_LogWarn() { - var uri = Client.UriBuilder.StartNew().AppendAction("warn").Uri; - var response = Client.Post(uri, "This is a WARN log message"); + var response = _client.Post( + r => r.AddResource("api/log/warn") + .WithBody("This is a WARN log message")); Assert.IsTrue(response.IsSuccessStatusCode); } @@ -32,8 +32,9 @@ public void Logger_LogWarn() [Test] public void Logger_LogDebug() { - var uri = Client.UriBuilder.StartNew().AppendAction("debug").Uri; - var response = Client.Post(uri, "This is a DEBUG log message"); + var response = _client.Post( + r => r.AddResource("api/log/debug") + .WithBody("This is a DEBUG log message")); Assert.IsTrue(response.IsSuccessStatusCode); } @@ -41,8 +42,9 @@ public void Logger_LogDebug() [Test] public void Logger_LogError() { - var uri = Client.UriBuilder.StartNew().AppendAction("error").Uri; - var response = Client.Post(uri, "This is an ERROR log message"); + var response = _client.Post( + r => r.AddResource("api/log/error") + .WithBody("This is an ERROR log message")); Assert.IsTrue(response.IsSuccessStatusCode); } diff --git a/Skeleton.Tests.Web/HttpClientTestsSetup.cs b/Skeleton.Tests.Web/HttpClientTestsSetup.cs index 070167f..12078a7 100644 --- a/Skeleton.Tests.Web/HttpClientTestsSetup.cs +++ b/Skeleton.Tests.Web/HttpClientTestsSetup.cs @@ -12,7 +12,7 @@ public class HttpClientTestsSetup public void Init() { _server = new OwinTestServer(); - _server.Start(AppConfiguration.BaseUrl); + _server.Start(AppConfiguration.BaseAddress); } [OneTimeTearDown] diff --git a/Skeleton.Web.Client/AsyncJsonCrudHttpClient.cs b/Skeleton.Web.Client/AsyncJsonCrudHttpClient.cs deleted file mode 100644 index 724d9fa..0000000 --- a/Skeleton.Web.Client/AsyncJsonCrudHttpClient.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Net.Http; -using System.Threading.Tasks; - -namespace Skeleton.Web.Client -{ - public class AsyncJsonCrudHttpClient : - JsonHttpClient where TDto : class - { - public AsyncJsonCrudHttpClient(IRestUriBuilder uriBuilder) - : base(uriBuilder) - { - } - - public AsyncJsonCrudHttpClient(IRestUriBuilder uriBuilder, IRetryPolicy retryPolicy) - : base(uriBuilder, retryPolicy) - { - } - - public AsyncJsonCrudHttpClient(IRestUriBuilder uriBuilder, IRetryPolicy retryPolicy, HttpClientHandler handler) - : base(uriBuilder, retryPolicy, handler) - { - } - - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public async Task> GetAllAsync() - { - var requestUri = UriBuilder.GetAll(); - var response = await GetAsync(requestUri) - .ConfigureAwait(false); - - return await response - .Content - .ReadAsAsync>() - .ConfigureAwait(false); - } - - public async Task FirstOrDefaultAsync(object id) - { - var requestUri = UriBuilder.FirstOrDefault(id); - var response = await GetAsync(requestUri) - .ConfigureAwait(false); - - return await response - .Content - .ReadAsAsync() - .ConfigureAwait(false); - } - - public async Task> QueryAsync(Query query) - { - var requestUri = UriBuilder.Query(query); - var response = await GetAsync(requestUri) - .ConfigureAwait(false); - - return await response - .Content - .ReadAsAsync>() - .ConfigureAwait(false); - } - - public async Task CreateAsync(TDto dto) - { - var requestUri = UriBuilder.Create(); - var response = await PostAsync(requestUri, dto) - .ConfigureAwait(false); - - return await response - .Content - .ReadAsAsync() - .ConfigureAwait(false); - } - - public async Task UpdateAsync(TDto dto) - { - var requestUri = UriBuilder.Update(); - var response = await PutAsync(requestUri, dto) - .ConfigureAwait(false); - - return response.IsSuccessStatusCode; - } - - public async Task DeleteAsync(object id) - { - var requestUri = UriBuilder.Delete(id); - var response = await base.DeleteAsync(requestUri) - .ConfigureAwait(false); - - return response.IsSuccessStatusCode; - } - - public async Task> CreateAsync(IEnumerable dtos) - { - var requestUri = UriBuilder.BatchCreate(); - var response = await PostAsync(requestUri, dtos) - .ConfigureAwait(false); - - return await response - .Content - .ReadAsAsync>() - .ConfigureAwait(false); - } - - public async Task UpdateAsync(IEnumerable dtos) - { - var requestUri = UriBuilder.BatchUpdate(); - var response = await PostAsync(requestUri, dtos) - .ConfigureAwait(false); - - return response.IsSuccessStatusCode; - } - - public async Task DeleteAsync(IEnumerable dtos) - { - var requestUri = UriBuilder.BatchDelete(); - var response = await PostAsync(requestUri, dtos) - .ConfigureAwait(false); - - return response.IsSuccessStatusCode; - } - } -} \ No newline at end of file diff --git a/Skeleton.Web.Client/ClientProvider.cs b/Skeleton.Web.Client/ClientProvider.cs index 7b7e904..6fb46c0 100644 --- a/Skeleton.Web.Client/ClientProvider.cs +++ b/Skeleton.Web.Client/ClientProvider.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Collections.Concurrent; using System.Collections.Generic; @@ -7,12 +6,12 @@ namespace Skeleton.Web.Client { public static class ClientProvider { - private static readonly ConcurrentDictionary ClientCache = - new ConcurrentDictionary(); + private static readonly ConcurrentDictionary ClientCache = + new ConcurrentDictionary(); public static IEnumerable Keys => ClientCache.Keys; - public static IEnumerable Values => ClientCache.Values; + public static IEnumerable Values => ClientCache.Values; public static void RegisterServices(Uri baseAddress) { @@ -21,17 +20,33 @@ public static void RegisterServices(Uri baseAddress) foreach (var service in serviceRegistry) { - var serviceUri = new RestUriBuilder(new UriBuilder(service.Host)); - var clientInstance = new JsonHttpClient(serviceUri); + var serviceUri = new Uri(service.Host); + var clientInstance = new RestClient(serviceUri); ClientCache.TryAdd(service.Name.ToLower(), clientInstance); } } - public static JsonHttpClient FindClient(string key) + public static IRestClient GetClient(string key) { - JsonHttpClient value = null; + EnsureKeyNotNullOrEmpty(key); + + IRestClient value = null; return ClientCache.TryGetValue(key.ToLower(), out value) ? value : null; } + + public static bool RemoveClient(string key) + { + EnsureKeyNotNullOrEmpty(key); + + IRestClient value = null; + return ClientCache.TryRemove(key.ToLower(), out value); + } + + private static void EnsureKeyNotNullOrEmpty(string key) + { + if (string.IsNullOrEmpty(key)) + throw new ArgumentException(nameof(key)); + } } } diff --git a/Skeleton.Web.Client/ExponentialRetryPolicy.cs b/Skeleton.Web.Client/ExponentialRetryPolicy.cs index fdf84cb..923a44b 100644 --- a/Skeleton.Web.Client/ExponentialRetryPolicy.cs +++ b/Skeleton.Web.Client/ExponentialRetryPolicy.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using System.Net; -using System.Net.Http; using System.Threading.Tasks; namespace Skeleton.Web.Client @@ -49,92 +48,38 @@ public int RetryCount public TimeSpan DelayInterval { - get; - private set; - } - - public T Execute(Func func) - { - RetryCount = 0; - - for (;;) + get { - DelayInterval = CalculateExponentialBackoff(); - - try - { - return func(); - } - // Connection error - catch (HttpRequestException) - { - ++RetryCount; - - if (RetryCount == _maxRetries) - throw; - - Task.Delay(DelayInterval).Wait(); - } - // Enriched exception (statuscode) - catch (HttpResponseMessageException e) - { - ++RetryCount; - - if (RetryCount == _maxRetries) - throw; - - if (!httpStatusCodesWorthRetrying.Contains(e.StatusCode)) - throw; + int randomInterval = GetRandomInterval(); + var delta = (int)(Math.Pow(2.0, RetryCount) * randomInterval); + var interval = (int)Math.Min(checked(DefaultMinBackoff.TotalMilliseconds + delta), + DefaultMaxBackoff.TotalMilliseconds); - Task.Delay(DelayInterval).Wait(); - } + return TimeSpan.FromMilliseconds(interval); } } - public async Task ExecuteAsync(Func> func) + public async Task ExecuteAsync(Func> func) { - RetryCount = 0; - - for (;;) + IRestResponse response = null; + for (RetryCount = 0; RetryCount <= _maxRetries; RetryCount++) { - DelayInterval = CalculateExponentialBackoff(); - + if (RetryCount != 0) + Task.Delay(DelayInterval).Wait(); + try { - return await func(); + response = await func().ConfigureAwait(false); } - catch (HttpRequestException) + catch (Exception) { - ++RetryCount; - - if (RetryCount == DefaultRetryCount) - throw; - - Task.Delay(DelayInterval).Wait(); + throw; } - catch (HttpResponseMessageException e) - { - ++RetryCount; - if (RetryCount == DefaultRetryCount) - throw; - - if (!httpStatusCodesWorthRetrying.Contains(e.StatusCode)) - throw; - - Task.Delay(DelayInterval).Wait(); - } + if (!httpStatusCodesWorthRetrying.Contains(response.StatusCode)) + break; } - } - - private TimeSpan CalculateExponentialBackoff() - { - int randomInterval = GetRandomInterval(); - var delta = (int)(Math.Pow(2.0, RetryCount) * randomInterval); - var interval = (int)Math.Min(checked(DefaultMinBackoff.TotalMilliseconds + delta), - DefaultMaxBackoff.TotalMilliseconds); - - return TimeSpan.FromMilliseconds(interval); + return response; } private int GetRandomInterval() diff --git a/Skeleton.Web.Client/GlobalSuppressions.cs b/Skeleton.Web.Client/GlobalSuppressions.cs deleted file mode 100644 index 8c386cb..0000000 Binary files a/Skeleton.Web.Client/GlobalSuppressions.cs and /dev/null differ diff --git a/Skeleton.Web.Client/HttpResponseMessageException.cs b/Skeleton.Web.Client/HttpResponseMessageException.cs deleted file mode 100644 index 48488ac..0000000 --- a/Skeleton.Web.Client/HttpResponseMessageException.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Net; -using System.Net.Http; -using System.Runtime.Serialization; - -namespace Skeleton.Web.Client -{ - [Serializable] - public class HttpResponseMessageException : Exception - { - public HttpStatusCode StatusCode { get; } - public HttpResponseMessage Response { get; } - - public HttpResponseMessageException() - { - } - - public HttpResponseMessageException(HttpResponseMessage response) - : base(response.ReasonPhrase) - { - Response = response; - StatusCode = response.StatusCode; - } - - protected HttpResponseMessageException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - } -} \ No newline at end of file diff --git a/Skeleton.Web.Client/IRestClient.cs b/Skeleton.Web.Client/IRestClient.cs new file mode 100644 index 0000000..c78db36 --- /dev/null +++ b/Skeleton.Web.Client/IRestClient.cs @@ -0,0 +1,41 @@ +using System; +using System.Net.Http.Headers; +using System.Threading.Tasks; + +namespace Skeleton.Web.Client +{ + public interface IRestClient : IDisposable + { + AuthenticationHeaderValue Authentication { get; set; } + Uri BaseAddress { get; } + IRetryPolicy RetryPolicy { get; } + + IRestResponse Delete(IRestRequest request); + IRestResponse Delete(Action requestBuilder); + Task DeleteAsync(IRestRequest request); + Task DeleteAsync(Action requestBuilder); + + IRestResponse Get(IRestRequest request); + IRestResponse Get(Action requestBuilder); + T Get(IRestRequest request); + T Get(Action requestBuilder); + Task GetAsync(IRestRequest request); + Task GetAsync(Action requestBuilder); + Task GetAsync(IRestRequest request); + Task GetAsync(Action requestBuilder); + + IRestResponse Post(IRestRequest request); + IRestResponse Post(Action requestBuilder); + T Post(IRestRequest request); + T Post(Action requestBuilder); + Task PostAsync(IRestRequest request); + Task PostAsync(Action requestBuilder); + Task PostAsync(IRestRequest request); + Task PostAsync(Action requestBuilder); + + IRestResponse Put(IRestRequest request); + IRestResponse Put(Action requestBuilder); + Task PutAsync(IRestRequest request); + Task PutAsync(Action requestBuilder); + } +} \ No newline at end of file diff --git a/Skeleton.Web.Client/IRestRequest.cs b/Skeleton.Web.Client/IRestRequest.cs new file mode 100644 index 0000000..a6550c3 --- /dev/null +++ b/Skeleton.Web.Client/IRestRequest.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; + +namespace Skeleton.Web.Client +{ + public interface IRestRequest + { + HttpRequestMessage CreateRequestMessage(Uri baseAddress); + + IRestRequest AddQueryParameter(string key, object value); + IRestRequest AddQueryParameters(IDictionary parameters); + IRestRequest AddQueryParameters(T value) where T : class, new(); + IRestRequest AddResource(string resource); + IRestRequest AsPut(); + IRestRequest AsDelete(); + IRestRequest AsPost(); + IRestRequest AsGet(); + IRestRequest WithBody(T value); + + HttpMethod Method { get; } + string QueryString { get; } + string Resource { get; } + HttpContent Content { get; } + } +} \ No newline at end of file diff --git a/Skeleton.Web.Client/IRestResponse.cs b/Skeleton.Web.Client/IRestResponse.cs new file mode 100644 index 0000000..e70f827 --- /dev/null +++ b/Skeleton.Web.Client/IRestResponse.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; + +namespace Skeleton.Web.Client +{ + public interface IRestResponse + { + T As(); + IEnumerable AsEnumerable(); + Stream AsStream(); + string AsString(); + + Task AsAsync(); + Task> AsEnumerableAsync(); + Task AsStreamAsync(); + Task AsStringAsync(); + + void EnsureSuccessStatusCode(); + + SupportedFormatters Formatters { get; } + + bool IsSuccessStatusCode { get; } + + HttpResponseMessage Message { get; } + + HttpStatusCode StatusCode { get; } + } +} \ No newline at end of file diff --git a/Skeleton.Web.Client/IRestUriBuilder.cs b/Skeleton.Web.Client/IRestUriBuilder.cs deleted file mode 100644 index fcdb376..0000000 --- a/Skeleton.Web.Client/IRestUriBuilder.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Skeleton.Web.Client -{ - public interface IRestUriBuilder - { - Uri Uri { get; } - - IRestUriBuilder AppendAction(RestAction action); - - IRestUriBuilder AppendAction(object parameter); - - IRestUriBuilder StartNew(); - - IRestUriBuilder SetQueryParameter(string key, object value); - - IRestUriBuilder SetQueryParameters(IDictionary parameters); - } -} \ No newline at end of file diff --git a/Skeleton.Web.Client/IRetryPolicy.cs b/Skeleton.Web.Client/IRetryPolicy.cs index e5bb95e..f7363ca 100644 --- a/Skeleton.Web.Client/IRetryPolicy.cs +++ b/Skeleton.Web.Client/IRetryPolicy.cs @@ -9,8 +9,6 @@ public interface IRetryPolicy TimeSpan DelayInterval { get; } - T Execute(Func func); - - Task ExecuteAsync(Func> func); + Task ExecuteAsync(Func> func); } } \ No newline at end of file diff --git a/Skeleton.Web.Client/JsonCrudHttpClient.cs b/Skeleton.Web.Client/JsonCrudHttpClient.cs deleted file mode 100644 index de5e1d8..0000000 --- a/Skeleton.Web.Client/JsonCrudHttpClient.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Net.Http; - -namespace Skeleton.Web.Client -{ - public class JsonCrudHttpClient : - JsonHttpClient where TDto : class - { - public JsonCrudHttpClient(IRestUriBuilder uriBuilder) - : base(uriBuilder) - { - } - - public JsonCrudHttpClient(IRestUriBuilder uriBuilder, IRetryPolicy retryPolicy) - : base(uriBuilder, retryPolicy) - { - } - - public JsonCrudHttpClient(IRestUriBuilder uriBuilder, IRetryPolicy retryPolicy, HttpClientHandler handler) - : base(uriBuilder, retryPolicy, handler) - { - } - - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - public IEnumerable GetAll() - { - var requestUri = UriBuilder.GetAll(); - var response = Get(requestUri); - - return response.Content - .ReadAsAsync>() - .Result; - } - - public TDto FirstOrDefault(object id) - { - var requestUri = UriBuilder.FirstOrDefault(id); - var content = Get(requestUri).Content; - - return content - .ReadAsAsync() - .Result; - } - - public QueryResult Query(Query query) - { - var requestUri = UriBuilder.Query(query); - var content = Get(requestUri).Content; - - return content - .ReadAsAsync>() - .Result; - } - - public TDto Create(TDto dto) - { - var requestUri = UriBuilder.Create(); - var content = Post(requestUri, dto).Content; - - return content - .ReadAsAsync() - .Result; - } - - public IEnumerable Create(IEnumerable dtos) - { - var requestUri = UriBuilder.BatchCreate(); - var content = Post(requestUri, dtos).Content; - - return content - .ReadAsAsync>() - .Result; - } - - public bool Update(TDto dto) - { - var requestUri = UriBuilder.Update(); - var response = Put(requestUri, dto); - - return response.IsSuccessStatusCode; - } - - public bool Update(IEnumerable dtos) - { - var requestUri = UriBuilder.BatchUpdate(); - var response = Post(requestUri, dtos); - - return response.IsSuccessStatusCode; - } - - public bool Delete(object id) - { - var requestUri = UriBuilder.Delete(id); - var response = base.Delete(requestUri); - - return response.IsSuccessStatusCode; - } - - public bool Delete(IEnumerable dtos) - { - var requestUri = UriBuilder.BatchDelete(); - var response = Post(requestUri, dtos); - - return response.IsSuccessStatusCode; - } - } -} \ No newline at end of file diff --git a/Skeleton.Web.Client/JsonHttpClient.cs b/Skeleton.Web.Client/JsonHttpClient.cs deleted file mode 100644 index ba20d0f..0000000 --- a/Skeleton.Web.Client/JsonHttpClient.cs +++ /dev/null @@ -1,210 +0,0 @@ -using System; -using System.Globalization; -using System.Net.Http; -using System.Net.Http.Formatting; -using System.Net.Http.Headers; -using System.Reflection; -using System.Threading.Tasks; - -namespace Skeleton.Web.Client -{ - public class JsonHttpClient : IDisposable - { - private static int Version = Assembly.GetAssembly(typeof(JsonHttpClient)).GetName().Version.Major; - private static Lazy InnerClient; - - private readonly JsonMediaTypeFormatter _jsonFormatter = new JsonMediaTypeFormatter(); - private readonly IRetryPolicy _retryPolicy; - private readonly IRestUriBuilder _uriBuilder; - private readonly HttpClientHandler _handler; - private bool _disposed; - - public JsonHttpClient(IRestUriBuilder uriBuilder) - : this(uriBuilder, new ExponentialRetryPolicy(), new AutomaticDecompressionHandler()) - { - } - - public JsonHttpClient(IRestUriBuilder uriBuilder, IRetryPolicy retryPolicy) - : this(uriBuilder, retryPolicy, new AutomaticDecompressionHandler()) - { - } - - public JsonHttpClient(IRestUriBuilder uriBuilder, IRetryPolicy retryPolicy, HttpClientHandler handler) - { - if (uriBuilder == null) - throw new ArgumentNullException(nameof(uriBuilder)); - - if (handler == null) - throw new ArgumentNullException(nameof(handler)); - - if (retryPolicy == null) - throw new ArgumentNullException(nameof(retryPolicy)); - - _uriBuilder = uriBuilder; - _handler = handler; - _retryPolicy = retryPolicy; - - InnerClient = new Lazy( - () => new HttpClient(_handler)); - - SetDefaultRequestHeaders(); - } - - public IRestUriBuilder UriBuilder => _uriBuilder; - - public AuthenticationHeaderValue Authentication { get; set; } - - public HttpClient Client => InnerClient.Value; - - public HttpResponseMessage Send(HttpRequestMessage request) - { - if (request == null) - throw new ArgumentNullException(nameof(request)); - - CheckDisposed(); - SetAuthentication(request); - - return _retryPolicy.Execute(() => - { - var response = Client - .SendAsync(request) - .Result; - - HandleException(response); - - return response; - }); - } - - public async Task SendAsync(HttpRequestMessage request) - { - if (request == null) - throw new ArgumentNullException(nameof(request)); - - CheckDisposed(); - SetAuthentication(request); - - return await _retryPolicy.Execute(async () => - { - var response = await Client - .SendAsync(request, HttpCompletionOption.ResponseHeadersRead) - .ConfigureAwait(false); - - HandleException(response); - - return response; - }); - } - - public HttpResponseMessage Get(Uri requestUri) - { - return Send(new HttpRequestMessage(HttpMethod.Get, requestUri)); - } - - public async Task GetAsync(Uri requestUri) - { - return await SendAsync(new HttpRequestMessage(HttpMethod.Get, requestUri)); - } - - public HttpResponseMessage Delete(Uri requestUri) - { - return Send(new HttpRequestMessage(HttpMethod.Delete, requestUri)); - } - - public async Task DeleteAsync(Uri requestUri) - { - return await SendAsync(new HttpRequestMessage(HttpMethod.Delete, requestUri)); - } - - public HttpResponseMessage Put(Uri requestUri, T value) - { - var content = new ObjectContent(value, _jsonFormatter); - var request = new HttpRequestMessage(HttpMethod.Put, requestUri) { Content = content }; - - return Send(request); - } - - public async Task PutAsync(Uri requestUri, T value) - { - var content = new ObjectContent(value, _jsonFormatter); - var request = new HttpRequestMessage(HttpMethod.Put, requestUri) { Content = content }; - - return await SendAsync(request); - } - - public HttpResponseMessage Post(Uri requestUri, T value) - { - var content = new ObjectContent(value, _jsonFormatter); - var request = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = content }; - - return Send(request); - } - - public async Task PostAsync(Uri requestUri, T value) - { - var content = new ObjectContent(value, _jsonFormatter); - var request = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = content }; - - return await SendAsync(request); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void SetDefaultRequestHeaders() - { - Client.DefaultRequestHeaders.Accept.Clear(); - Client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(Constants.JsonMediaType)); - Client.DefaultRequestHeaders.UserAgent.Add(GetUserAgent()); - - if (_handler.SupportsAutomaticDecompression) - { - Client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("gzip")); - Client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("defalte")); - } - } - - private static ProductInfoHeaderValue GetUserAgent() - { - return new ProductInfoHeaderValue( - new ProductHeaderValue( - string.Format(CultureInfo.InvariantCulture, Constants.ProductHeader, Version))); - } - - private void HandleException(HttpResponseMessage responseMessage) - { - if (responseMessage == null) - throw new ArgumentNullException(nameof(responseMessage)); - - if (responseMessage.IsSuccessStatusCode) - return; - - throw new HttpResponseMessageException(responseMessage); - } - - private void SetAuthentication(HttpRequestMessage request) - { - if (Authentication != null) - request.Headers.Authorization = Authentication; - } - - private void CheckDisposed() - { - if (_disposed) - throw new ObjectDisposedException(GetType().FullName); - } - - protected virtual void Dispose(bool disposing) - { - if (_disposed || !disposing) - return; - - Client?.Dispose(); - - _disposed = true; - } - } -} \ No newline at end of file diff --git a/Skeleton.Web.Client/NoRetryPolicy.cs b/Skeleton.Web.Client/NoRetryPolicy.cs index 7c0e3a6..dc93c62 100644 --- a/Skeleton.Web.Client/NoRetryPolicy.cs +++ b/Skeleton.Web.Client/NoRetryPolicy.cs @@ -10,37 +10,13 @@ public sealed class NoRetryPolicy : IRetryPolicy public TimeSpan DelayInterval { get; } = TimeSpan.MinValue; - public T Execute(Func func) - { - try - { - return func(); - } - // Connection error - catch (HttpRequestException) - { - throw; - } - // Enriched exception (statuscode) - catch (HttpResponseMessageException) - { - throw; - } - } - - public async Task ExecuteAsync(Func> func) + public async Task ExecuteAsync(Func> func) { try { return await func().ConfigureAwait(false); } - // Connection error - catch (HttpRequestException) - { - throw; - } - // Enriched exception (statuscode) - catch (HttpResponseMessageException) + catch (Exception) { throw; } diff --git a/Skeleton.Web.Client/RestAction.cs b/Skeleton.Web.Client/RestAction.cs deleted file mode 100644 index 9b8dd74..0000000 --- a/Skeleton.Web.Client/RestAction.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Skeleton.Web.Client -{ - public enum RestAction - { - GetAll, - Query, - FirstOrDefault, - Create, - BatchCreate, - Page, - Update, - BatchUpdate, - Delete, - BatchDelete - } -} \ No newline at end of file diff --git a/Skeleton.Web.Client/RestClient.cs b/Skeleton.Web.Client/RestClient.cs new file mode 100644 index 0000000..c947bdc --- /dev/null +++ b/Skeleton.Web.Client/RestClient.cs @@ -0,0 +1,303 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Reflection; +using System.Threading.Tasks; + +namespace Skeleton.Web.Client +{ + public class RestClient : IRestClient + { + private readonly static int ClientVersion = Assembly.GetAssembly(typeof(RestClient)).GetName().Version.Major; + private readonly static SupportedFormatters Formatters = new SupportedFormatters(); + private static Lazy InnerClient; + + private readonly IRetryPolicy _retryPolicy; + private bool _disposed; + + public RestClient(Uri baseAddress) + : this(baseAddress, new ExponentialRetryPolicy(), new AutomaticDecompressionHandler()) + { + } + + public RestClient(Uri baseAddress, IRetryPolicy retryPolicy) + : this(baseAddress, retryPolicy, new AutomaticDecompressionHandler()) + { + } + + public RestClient(Uri baseAddress, IRetryPolicy retryPolicy, HttpMessageHandler handler) + { + if (baseAddress == null) + throw new ArgumentNullException(nameof(baseAddress)); + + if (handler == null) + throw new ArgumentNullException(nameof(handler)); + + if (retryPolicy == null) + throw new ArgumentNullException(nameof(retryPolicy)); + + _retryPolicy = retryPolicy; + + InnerClient = new Lazy( + () => new HttpClient(handler)); + + ConfigureHttpClient(baseAddress, handler); + } + + public AuthenticationHeaderValue Authentication { get; set; } + + public Uri BaseAddress => Client.BaseAddress; + + public IRetryPolicy RetryPolicy => _retryPolicy; + + private static HttpClient Client => InnerClient.Value; + + protected virtual async Task SendAsync(IRestRequest request) + { + CheckDisposed(); + + var requestMessage = request.CreateRequestMessage(BaseAddress); + SetAuthentication(requestMessage); + + return await RetryPolicy.ExecuteAsync(async () => + { + var response = await Client + .SendAsync(requestMessage) + .ConfigureAwait(false); + + return new RestResponse(response, Formatters); + }); + } + + public IRestResponse Get(IRestRequest request) + { + return GetAsync(request).Result; + } + + public async Task GetAsync(IRestRequest request) + { + EnsureRequestNotNull(request); + + return await SendAsync(request.AsGet()).ConfigureAwait(false); + } + + public T Get(IRestRequest request) + { + return GetAsync(request).Result; + } + + public async Task GetAsync(IRestRequest request) + { + EnsureRequestNotNull(request); + + return await GetAsync(request) + .ContinueWith(response => response.Result.As()); + } + + public IRestResponse Get(Action requestBuilder) + { + return GetAsync(requestBuilder).Result; + } + + public async Task GetAsync(Action requestBuilder) + { + EnsureRequestBuilderNotNull(requestBuilder); + + var request = new RestRequest().AsGet(); + requestBuilder(request); + + return await SendAsync(request).ConfigureAwait(false); + } + + public T Get(Action requestBuilder) + { + return GetAsync(requestBuilder).Result; + } + + public async Task GetAsync(Action requestBuilder) + { + return await GetAsync(requestBuilder) + .ContinueWith(response => response.Result.As()); + } + + public IRestResponse Delete(IRestRequest request) + { + return DeleteAsync(request).Result; + } + + public async Task DeleteAsync(IRestRequest request) + { + EnsureRequestNotNull(request); + + return await SendAsync(request.AsDelete()).ConfigureAwait(false); + } + + public IRestResponse Delete(Action requestBuilder) + { + return DeleteAsync(requestBuilder).Result; + } + + public async Task DeleteAsync(Action requestBuilder) + { + EnsureRequestBuilderNotNull(requestBuilder); + + var request = new RestRequest().AsDelete(); + requestBuilder(request); + + return await SendAsync(request).ConfigureAwait(false); + } + + public IRestResponse Put(IRestRequest request) + { + return PutAsync(request).Result; + } + + public async Task PutAsync(IRestRequest request) + { + EnsureRequestNotNull(request); + + return await SendAsync(request.AsPut()) + .ConfigureAwait(false); + } + + public IRestResponse Put(Action requestBuilder) + { + return PutAsync(requestBuilder).Result; + } + + public async Task PutAsync(Action requestBuilder) + { + EnsureRequestBuilderNotNull(requestBuilder); + + var request = new RestRequest().AsPut(); + requestBuilder(request); + + return await SendAsync(request).ConfigureAwait(false); + } + + public IRestResponse Post(IRestRequest request) + { + return PostAsync(request).Result; + } + + public async Task PostAsync(IRestRequest request) + { + EnsureRequestNotNull(request); + + return await SendAsync(request.AsPost()).ConfigureAwait(false); + } + + public T Post(IRestRequest request) + { + return PostAsync(request).Result; + } + + public async Task PostAsync(IRestRequest request) + { + EnsureRequestNotNull(request); + + return await SendAsync(request.AsPost()) + .ContinueWith(response => response.Result.As()); + } + + public IRestResponse Post(Action requestBuilder) + { + return PostAsync(requestBuilder).Result; + } + + public async Task PostAsync(Action requestBuilder) + { + EnsureRequestBuilderNotNull(requestBuilder); + + var request = new RestRequest().AsPost(); + requestBuilder(request); + + return await SendAsync(request).ConfigureAwait(false); + } + + public T Post(Action requestBuilder) + { + return PostAsync(requestBuilder).Result; + } + + public async Task PostAsync(Action requestBuilder) + { + EnsureRequestBuilderNotNull(requestBuilder); + + var request = new RestRequest().AsPost(); + requestBuilder(request); + + return await SendAsync(request) + .ContinueWith(response => response.Result.As()); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private static void ConfigureHttpClient(Uri baseAddress, HttpMessageHandler handler) + { + Client.BaseAddress = baseAddress; + + Client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("gzip")); + Client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("defalte")); + Client.DefaultRequestHeaders.UserAgent.Add(GetUserAgent()); + + Client.DefaultRequestHeaders.Accept.Clear(); + foreach (var mediaTypeHeader in Formatters.SelectMany(x => x.SupportedMediaTypes)) + Client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(mediaTypeHeader.MediaType)); + + var clientHandler = handler as HttpClientHandler; + if (clientHandler == null) + return; + + clientHandler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + } + + private static ProductInfoHeaderValue GetUserAgent() + { + return new ProductInfoHeaderValue( + new ProductHeaderValue( + string.Format(CultureInfo.InvariantCulture, Constants.ProductHeader, ClientVersion))); + } + + private static void EnsureRequestNotNull(IRestRequest request) + { + if (request == null) + throw new ArgumentNullException(nameof(request)); + } + + private static void EnsureRequestBuilderNotNull(Action requestBuilder) + { + if (requestBuilder==null) + throw new ArgumentNullException(nameof(requestBuilder)); + } + + private void SetAuthentication(HttpRequestMessage request) + { + if (Authentication != null) + request.Headers.Authorization = Authentication; + } + + private void CheckDisposed() + { + if (_disposed) + throw new ObjectDisposedException(GetType().FullName); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed || !disposing) + return; + + Client?.Dispose(); + + _disposed = true; + } + } +} \ No newline at end of file diff --git a/Skeleton.Web.Client/RestRequest.cs b/Skeleton.Web.Client/RestRequest.cs new file mode 100644 index 0000000..6f1e714 --- /dev/null +++ b/Skeleton.Web.Client/RestRequest.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net.Http; +using System.Text; + +namespace Skeleton.Web.Client +{ + public sealed class RestRequest : IRestRequest + { + private readonly static SupportedFormatters Formatters = new SupportedFormatters(); + + public RestRequest() + { + } + + public RestRequest(string resource) + { + if (string.IsNullOrEmpty(resource)) + throw new ArgumentException(nameof(resource)); + + Resource = EnsureTrailingSlash(resource); + } + + public RestRequest(string resource, HttpMethod method) + : this(resource) + { + Method = method; + } + + public HttpMethod Method { get; private set; } + + public string Resource { get; private set; } + + public string QueryString { get; private set; } + + public HttpContent Content { get; private set; } + + public IRestRequest WithBody(T value) + { + Content = new ObjectContent(typeof(T), value, Formatters.FirstOrDefault()); + + return this; + } + + public IRestRequest AsPut() + { + Method = HttpMethod.Put; + + return this; + } + + public IRestRequest AsDelete() + { + Method = HttpMethod.Delete; + + return this; + } + + public IRestRequest AsPost() + { + Method = HttpMethod.Post; + + return this; + } + + public IRestRequest AsGet() + { + Method = HttpMethod.Get; + + return this; + } + + public IRestRequest AddResource(string resource) + { + if (string.IsNullOrEmpty(resource)) + throw new ArgumentException(nameof(resource)); + + if (!string.IsNullOrEmpty(Resource)) + Resource = EnsureTrailingSlash(Resource); + + Resource += resource; + + return this; + } + + public IRestRequest AddQueryParameter(string key, object value) + { + if (string.IsNullOrEmpty(key)) + throw new ArgumentException(nameof(key)); + + if (value == null) + throw new ArgumentNullException(nameof(value)); + + if (!string.IsNullOrEmpty(QueryString)) + QueryString += "&"; + + QueryString += EncodeUriParameter(new KeyValuePair(key, value)); + + return this; + } + + public IRestRequest AddQueryParameters(IDictionary parameters) + { + if (parameters == null) + throw new ArgumentNullException(nameof(parameters)); + + var stringBuilder = new StringBuilder(); + foreach (var parameter in parameters) + { + if (parameter.Value == null) + continue; + + if (stringBuilder.Length > 0) + stringBuilder.Append("&"); + + var encodedParameter = EncodeUriParameter(parameter); + stringBuilder.Append(encodedParameter); + } + + QueryString = stringBuilder.ToString(); + + return this; + } + + public IRestRequest AddQueryParameters(T value) where T : class, new() + { + foreach (var propertyInfo in typeof(T).GetProperties()) + { + var propertyValue = propertyInfo.GetValue(value, null); + if (propertyValue == null) + continue; + + AddQueryParameter(propertyInfo.Name, propertyValue); + } + + return this; + } + + public HttpRequestMessage CreateRequestMessage(Uri baseAddress) + { + var builder = new UriBuilder(baseAddress); + var basePath = string.IsNullOrEmpty(builder.Path) + ? string.Empty + : EnsureTrailingSlash(builder.Path); + + builder.Path = basePath + Resource; + builder.Query = QueryString; + + var requestMessage = new HttpRequestMessage(Method, builder.Uri); + + if (Content != null) + requestMessage.Content = Content; + + return requestMessage; + } + + private static string EncodeUriParameter(KeyValuePair parameter) + { + var key = Uri.EscapeDataString(parameter.Key); + var value = Uri.EscapeDataString(parameter.Value.ToString()); + + return string.Format(CultureInfo.InvariantCulture, "{0}={1}", key, value); + } + + private static string EnsureTrailingSlash(string value) + { + if (!value.EndsWith("/", StringComparison.OrdinalIgnoreCase)) + value += "/"; + + return value; + } + } +} \ No newline at end of file diff --git a/Skeleton.Web.Client/RestResponse.cs b/Skeleton.Web.Client/RestResponse.cs new file mode 100644 index 0000000..09055f0 --- /dev/null +++ b/Skeleton.Web.Client/RestResponse.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; + +namespace Skeleton.Web.Client +{ + public sealed class RestResponse : IRestResponse + { + public RestResponse(HttpResponseMessage response, SupportedFormatters formatters) + { + if (response == null) + throw new ArgumentNullException(nameof(response)); + + if (formatters == null) + throw new ArgumentNullException(nameof(formatters)); + + Message = response; + Formatters = formatters; + } + + public SupportedFormatters Formatters { get; private set; } + + public HttpResponseMessage Message { get; private set; } + + public bool IsSuccessStatusCode => Message.IsSuccessStatusCode; + + public HttpStatusCode StatusCode => Message.StatusCode; + + public void EnsureSuccessStatusCode() + { + Message.EnsureSuccessStatusCode(); + } + + public string AsString() + { + return AsStringAsync().Result; + } + + public Task AsStringAsync() + { + return Message.Content.ReadAsStringAsync(); + } + + public Stream AsStream() + { + var stream = AsStreamAsync().Result; + stream.Position = 0; + + return stream; + } + + public Task AsStreamAsync() + { + return Message.Content.ReadAsStreamAsync(); + } + + public IEnumerable AsEnumerable() + { + return As>(); + } + + public Task> AsEnumerableAsync() + { + return AsAsync>(); + } + + public T As() + { + return AsAsync().Result; + } + + public Task AsAsync() + { + return Message.Content.ReadAsAsync(Formatters); + } + } +} \ No newline at end of file diff --git a/Skeleton.Web.Client/RestUriBuilder.cs b/Skeleton.Web.Client/RestUriBuilder.cs deleted file mode 100644 index cc1bd1f..0000000 --- a/Skeleton.Web.Client/RestUriBuilder.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Text; - -namespace Skeleton.Web.Client -{ - public class RestUriBuilder : UriBuilder, IRestUriBuilder - { - private readonly string _initialPath; - - public RestUriBuilder(string host, int port, string path) - { - Host = host; - Port = port; - Path = EnsureEndsWithSlash(path); - _initialPath = Path; - } - - public RestUriBuilder(UriBuilder builder) - : this(builder.Host, builder.Port, builder.Path) - { - } - - public IRestUriBuilder StartNew() - { - Path = _initialPath; - Fragment = string.Empty; - Query = string.Empty; - - return this; - } - - public IRestUriBuilder AppendAction(RestAction action) - { - switch (action) - { - case RestAction.GetAll: - Path += ActionConstants.GetAll; - break; - - case RestAction.Query: - Path += ActionConstants.Query; - break; - - case RestAction.FirstOrDefault: - Path += ActionConstants.FirstOrDefault; - break; - - case RestAction.Create: - Path += ActionConstants.Create; - break; - - case RestAction.BatchCreate: - Path += ActionConstants.BatchCreate; - break; - - case RestAction.Update: - Path += ActionConstants.Update; - break; - - case RestAction.BatchUpdate: - Path += ActionConstants.BatchUpdate; - break; - - case RestAction.Delete: - Path += ActionConstants.Delete; - break; - - case RestAction.BatchDelete: - Path += ActionConstants.BatchDelete; - break; - - default: - break; - } - - return this; - } - - public IRestUriBuilder AppendAction(object parameter) - { - if (parameter == null) - throw new ArgumentNullException(nameof(parameter)); - - if (!string.IsNullOrEmpty(Path)) - Path = EnsureEndsWithSlash(Path); - - Path += parameter.ToString(); - - return this; - } - - public IRestUriBuilder SetQueryParameter(string key, object value) - { - if (string.IsNullOrEmpty(key)) - throw new ArgumentException("Key cannot be null or empty", nameof(key)); - - if (value == null) - throw new ArgumentNullException(nameof(value)); - - Query += EncodeUriParameter(new KeyValuePair(key, value)); - - return this; - } - - public IRestUriBuilder SetQueryParameters(IDictionary parameters) - { - if (parameters == null) - throw new ArgumentNullException(nameof(parameters)); - - var stringBuilder = new StringBuilder(); - foreach (var parameter in parameters) - { - if (parameter.Value == null) - continue; - - if (stringBuilder.Length > 0) - stringBuilder.Append("&"); - - var encodedParameter = EncodeUriParameter(parameter); - - stringBuilder.Append(encodedParameter); - } - - Query = stringBuilder.ToString(); - - return this; - } - - private static string EncodeUriParameter(KeyValuePair parameter) - { - var key = Uri.EscapeDataString(parameter.Key); - var value = Uri.EscapeDataString(parameter.Value.ToString()); - - return string.Format(CultureInfo.InvariantCulture, "{0}={1}", key, value); - } - - private static string EnsureEndsWithSlash(string value) - { - if (!value.EndsWith("/", StringComparison.OrdinalIgnoreCase)) - value += "/"; - - return value; - } - - private static class ActionConstants - { - internal const string GetAll = "getall"; - internal const string Query = "query"; - internal const string FirstOrDefault = "firstordefault"; - internal const string Create = "create"; - internal const string BatchCreate = "batchcreate"; - internal const string Update = "update"; - internal const string BatchUpdate = "batchupdate"; - internal const string Delete = "delete"; - internal const string BatchDelete = "batchdelete"; - } - } -} \ No newline at end of file diff --git a/Skeleton.Web.Client/RestUriBuilderExtensions.cs b/Skeleton.Web.Client/RestUriBuilderExtensions.cs deleted file mode 100644 index c003acf..0000000 --- a/Skeleton.Web.Client/RestUriBuilderExtensions.cs +++ /dev/null @@ -1,124 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Skeleton.Web.Client -{ - public static class RestUriBuilderExtensions - { - public static Uri GetAll(this IRestUriBuilder uriBuilder) - { - if (uriBuilder == null) - throw new ArgumentNullException(nameof(uriBuilder)); - - return uriBuilder - .StartNew() - .AppendAction(RestAction.GetAll) - .Uri; - } - - public static Uri FirstOrDefault(this IRestUriBuilder uriBuilder, object id) - { - if (uriBuilder == null) - throw new ArgumentNullException(nameof(uriBuilder)); - - return uriBuilder - .StartNew() - .AppendAction(RestAction.FirstOrDefault) - .AppendAction(id) - .Uri; - } - - public static Uri Query(this IRestUriBuilder uriBuilder, Query query) - { - if (uriBuilder == null) - throw new ArgumentNullException(nameof(uriBuilder)); - - if (query == null) - throw new ArgumentNullException(nameof(query)); - - return uriBuilder - .StartNew() - .AppendAction(RestAction.Query) - .SetQueryParameters(CreateQueryParameters(query)) - .Uri; - } - - private static IDictionary CreateQueryParameters(this Query query) - { - return new Dictionary - { - { "Fields", query.Fields }, - { "OrderBy" , query.OrderBy }, - { "PageNumber", query.PageNumber }, - { "PageSize", query.PageSize } - }; - } - - public static Uri Create(this IRestUriBuilder uriBuilder) - { - if (uriBuilder == null) - throw new ArgumentNullException(nameof(uriBuilder)); - - return uriBuilder - .StartNew() - .AppendAction(RestAction.Create) - .Uri; - } - - public static Uri BatchCreate(this IRestUriBuilder uriBuilder) - { - if (uriBuilder == null) - throw new ArgumentNullException(nameof(uriBuilder)); - - return uriBuilder - .StartNew() - .AppendAction(RestAction.BatchCreate) - .Uri; - } - - public static Uri Update(this IRestUriBuilder uriBuilder) - { - if (uriBuilder == null) - throw new ArgumentNullException(nameof(uriBuilder)); - - return uriBuilder - .StartNew() - .AppendAction(RestAction.Update) - .Uri; - } - - public static Uri BatchUpdate(this IRestUriBuilder uriBuilder) - { - if (uriBuilder == null) - throw new ArgumentNullException(nameof(uriBuilder)); - - return uriBuilder - .StartNew() - .AppendAction(RestAction.BatchUpdate) - .Uri; - } - - public static Uri Delete(this IRestUriBuilder uriBuilder, object id) - { - if (uriBuilder == null) - throw new ArgumentNullException(nameof(uriBuilder)); - - return uriBuilder - .StartNew() - .AppendAction(RestAction.Delete) - .AppendAction(id) - .Uri; - } - - public static Uri BatchDelete(this IRestUriBuilder uriBuilder) - { - if (uriBuilder == null) - throw new ArgumentNullException(nameof(uriBuilder)); - - return uriBuilder - .StartNew() - .AppendAction(RestAction.BatchDelete) - .Uri; - } - } -} \ No newline at end of file diff --git a/Skeleton.Web.Client/ServiceDiscoveryClient.cs b/Skeleton.Web.Client/ServiceDiscoveryClient.cs index e9af050..7f02a8c 100644 --- a/Skeleton.Web.Client/ServiceDiscoveryClient.cs +++ b/Skeleton.Web.Client/ServiceDiscoveryClient.cs @@ -1,30 +1,23 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; -using System.Net.Http; namespace Skeleton.Web.Client { public class ServiceDiscoveryClient { - private readonly JsonHttpClient _client; - private readonly RestUriBuilder _uriBuilder; + private readonly IRestClient _client; public ServiceDiscoveryClient(Uri baseAddress) { - _uriBuilder = new RestUriBuilder(new UriBuilder(baseAddress)); - _client = new JsonHttpClient(_uriBuilder); + _client = new RestClient(baseAddress); } public IEnumerable DiscoverServices() { - _uriBuilder.AppendAction("api/discover"); - var response = _client.Get(_uriBuilder.Uri); + var request = new RestRequest("api/discover"); + var response = _client.Get(request); - return response - .Content - .ReadAsAsync>() - .Result; + return response.As>(); } } diff --git a/Skeleton.Web.Client/Skeleton.Web.Client.csproj b/Skeleton.Web.Client/Skeleton.Web.Client.csproj index 21690f6..09f0961 100644 --- a/Skeleton.Web.Client/Skeleton.Web.Client.csproj +++ b/Skeleton.Web.Client/Skeleton.Web.Client.csproj @@ -61,23 +61,21 @@ + + + + + - - - - - - + - - - + diff --git a/Skeleton.Web.Client/SupportedFOrmatters.cs b/Skeleton.Web.Client/SupportedFOrmatters.cs new file mode 100644 index 0000000..6affdd3 --- /dev/null +++ b/Skeleton.Web.Client/SupportedFOrmatters.cs @@ -0,0 +1,20 @@ +using System.Linq; +using System.Net.Http.Formatting; + +namespace Skeleton.Web.Client +{ + public sealed class SupportedFormatters : MediaTypeFormatterCollection + { + public SupportedFormatters() + { + if (!this.Any()) + { + return; + } + + var jsonFormatter = (JsonMediaTypeFormatter)this[0]; + jsonFormatter.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore; + jsonFormatter.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc; + } + } +} \ No newline at end of file diff --git a/Skeleton.Web.Server/Configuration/CachingSwaggerProvider.cs b/Skeleton.Web.Server/Configuration/CachingSwaggerProvider.cs deleted file mode 100644 index 7ebb1a4..0000000 --- a/Skeleton.Web.Server/Configuration/CachingSwaggerProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Swashbuckle.Swagger; -using System.Collections.Concurrent; - -namespace Skeleton.Web.Server.Configuration -{ - public class CachingSwaggerProvider : ISwaggerProvider - { - private static readonly ConcurrentDictionary _cache = - new ConcurrentDictionary(); - - private readonly ISwaggerProvider _swaggerProvider; - - public CachingSwaggerProvider(ISwaggerProvider swaggerProvider) - { - _swaggerProvider = swaggerProvider; - } - - public SwaggerDocument GetSwagger(string rootUrl, string apiVersion) - { - var cacheKey = string.Format("{0}_{1}", rootUrl, apiVersion); - - return _cache.GetOrAdd(cacheKey, (key) => - _swaggerProvider.GetSwagger(rootUrl, apiVersion)); - } - } -} diff --git a/Skeleton.Web.Server/Configuration/CheckModelForNullAttribute.cs b/Skeleton.Web.Server/Configuration/CheckModelForNullAttribute.cs index dfb9a29..c87ecef 100644 --- a/Skeleton.Web.Server/Configuration/CheckModelForNullAttribute.cs +++ b/Skeleton.Web.Server/Configuration/CheckModelForNullAttribute.cs @@ -32,7 +32,7 @@ public CheckModelForNullAttribute(Func, bool> checkCo public override void OnActionExecuting(HttpActionContext actionContext) { - actionContext.ThrowIfNull(nameof(actionContext)); + actionContext.ThrowIfNull(); if (CheckCondition(actionContext.ActionArguments)) actionContext.Response = actionContext.Request.CreateErrorResponse( diff --git a/Skeleton.Web.Server/Configuration/CompressionMiddleware.cs b/Skeleton.Web.Server/Configuration/CompressionMiddleware.cs index 4cdab20..b1fe6a3 100644 --- a/Skeleton.Web.Server/Configuration/CompressionMiddleware.cs +++ b/Skeleton.Web.Server/Configuration/CompressionMiddleware.cs @@ -1,4 +1,5 @@ using Microsoft.Owin; +using Skeleton.Core; using System; using System.Collections.Generic; using System.Linq; @@ -26,6 +27,8 @@ public CompressionMiddleware(Func, Task> next) public async Task Invoke(IDictionary environment) { + environment.ThrowIfNull(); + var context = new OwinContext(environment); var httpOutputStream = context.Response.Body; var compressor = GetCompressor(context.Request); diff --git a/Skeleton.Web.Server/Configuration/GlobalExceptionHandler.cs b/Skeleton.Web.Server/Configuration/GlobalExceptionHandler.cs index c6380a5..7ec3cfa 100644 --- a/Skeleton.Web.Server/Configuration/GlobalExceptionHandler.cs +++ b/Skeleton.Web.Server/Configuration/GlobalExceptionHandler.cs @@ -32,7 +32,7 @@ public class GlobalExceptionHandler : IExceptionHandler public virtual void HandleCore(ExceptionHandlerContext context) { - context.ThrowIfNull(nameof(context)); + context.ThrowIfNull(); var content = Constants.DefaultErrorMessage; #if DEBUG @@ -48,7 +48,7 @@ public virtual void HandleCore(ExceptionHandlerContext context) public virtual bool ShouldHandle(ExceptionHandlerContext context) { - context.ThrowIfNull(nameof(context)); + context.ThrowIfNull(); return context.ExceptionContext.CatchBlock.IsTopLevel; } diff --git a/Skeleton.Web.Server/Configuration/GlobalExceptionLogger.cs b/Skeleton.Web.Server/Configuration/GlobalExceptionLogger.cs index 3500d8b..dacb352 100644 --- a/Skeleton.Web.Server/Configuration/GlobalExceptionLogger.cs +++ b/Skeleton.Web.Server/Configuration/GlobalExceptionLogger.cs @@ -10,14 +10,14 @@ public class GlobalExceptionLogger : ExceptionLogger public GlobalExceptionLogger(ILoggerFactory loggerFactory) { - loggerFactory.ThrowIfNull(nameof(loggerFactory)); + loggerFactory.ThrowIfNull(); _log = loggerFactory.GetLogger(this.GetType()); } public override void Log(ExceptionLoggerContext context) { - context.ThrowIfNull(nameof(context)); + context.ThrowIfNull(); _log.Error("API internal error", context.Exception); } diff --git a/Skeleton.Web.Server/Configuration/RequestLoggingMiddleware.cs b/Skeleton.Web.Server/Configuration/RequestLoggingMiddleware.cs index e0b79ff..f06fb86 100644 --- a/Skeleton.Web.Server/Configuration/RequestLoggingMiddleware.cs +++ b/Skeleton.Web.Server/Configuration/RequestLoggingMiddleware.cs @@ -13,7 +13,7 @@ public sealed class RequestLoggingMiddleware : OwinMiddleware public RequestLoggingMiddleware(OwinMiddleware next, ILoggerFactory loggerFactory) : base(next) { - loggerFactory.ThrowIfNull(nameof(loggerFactory)); + loggerFactory.ThrowIfNull(); _log = loggerFactory.GetLogger(this.GetType()); } diff --git a/Skeleton.Web.Server/Configuration/ValidateModelStateAttribute.cs b/Skeleton.Web.Server/Configuration/ValidateModelStateAttribute.cs index a9e3c23..3c114c6 100644 --- a/Skeleton.Web.Server/Configuration/ValidateModelStateAttribute.cs +++ b/Skeleton.Web.Server/Configuration/ValidateModelStateAttribute.cs @@ -12,7 +12,7 @@ public sealed class ValidateModelStateAttribute : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { - actionContext.ThrowIfNull(nameof(actionContext)); + actionContext.ThrowIfNull(); if (!actionContext.ModelState.IsValid) actionContext.Response = actionContext.Request.CreateErrorResponse( diff --git a/Skeleton.Web.Server/Controllers/AsyncCachedEntityReaderController.cs b/Skeleton.Web.Server/Controllers/AsyncCachedEntityReaderController.cs index 032bde1..8c22ef6 100644 --- a/Skeleton.Web.Server/Controllers/AsyncCachedEntityReaderController.cs +++ b/Skeleton.Web.Server/Controllers/AsyncCachedEntityReaderController.cs @@ -6,8 +6,8 @@ namespace Skeleton.Web.Server.Controllers { public class AsyncCachedReadController : AsyncEntityReaderController - where TEntity : class, IEntity - where TDto : class + where TEntity : class, IEntity, new() + where TDto : class, new() { public AsyncCachedReadController( ILogger logger, diff --git a/Skeleton.Web.Server/Controllers/AsyncEntityCrudController.cs b/Skeleton.Web.Server/Controllers/AsyncEntityCrudController.cs index e522d9f..d370eae 100644 --- a/Skeleton.Web.Server/Controllers/AsyncEntityCrudController.cs +++ b/Skeleton.Web.Server/Controllers/AsyncEntityCrudController.cs @@ -9,8 +9,8 @@ namespace Skeleton.Web.Server.Controllers { public class AsyncEntityCrudController : AsyncEntityReaderController - where TEntity : class, IEntity - where TDto : class + where TEntity : class, IEntity, new() + where TDto : class, new() { private readonly IAsyncEntityWriter _writer; diff --git a/Skeleton.Web.Server/Controllers/AsyncEntityReaderController.cs b/Skeleton.Web.Server/Controllers/AsyncEntityReaderController.cs index ecb3bcd..2cd0de0 100644 --- a/Skeleton.Web.Server/Controllers/AsyncEntityReaderController.cs +++ b/Skeleton.Web.Server/Controllers/AsyncEntityReaderController.cs @@ -9,8 +9,8 @@ namespace Skeleton.Web.Server.Controllers { public class AsyncEntityReaderController : ControllerBase - where TEntity : class, IEntity - where TDto : class + where TEntity : class, IEntity, new() + where TDto : class, new() { private readonly IEntityMapper _mapper; private readonly IAsyncEntityReader _reader; diff --git a/Skeleton.Web.Server/Controllers/CachedEntityReaderController.cs b/Skeleton.Web.Server/Controllers/CachedEntityReaderController.cs index 65bcdb0..eaec88b 100644 --- a/Skeleton.Web.Server/Controllers/CachedEntityReaderController.cs +++ b/Skeleton.Web.Server/Controllers/CachedEntityReaderController.cs @@ -6,8 +6,8 @@ namespace Skeleton.Web.Server.Controllers { public class CachedEntityReaderController : EntityReaderController - where TEntity : class, IEntity - where TDto : class + where TEntity : class, IEntity, new() + where TDto : class, new() { public CachedEntityReaderController( ILogger logger, diff --git a/Skeleton.Web.Server/Controllers/EntityCrudController.cs b/Skeleton.Web.Server/Controllers/EntityCrudController.cs index 030717e..c704c9f 100644 --- a/Skeleton.Web.Server/Controllers/EntityCrudController.cs +++ b/Skeleton.Web.Server/Controllers/EntityCrudController.cs @@ -8,8 +8,8 @@ namespace Skeleton.Web.Server.Controllers { public class EntityCrudController : EntityReaderController - where TEntity : class, IEntity - where TDto : class + where TEntity : class, IEntity, new() + where TDto : class, new() { private readonly IEntityWriter _writer; diff --git a/Skeleton.Web.Server/Controllers/EntityReaderController.cs b/Skeleton.Web.Server/Controllers/EntityReaderController.cs index 3d0cfbb..aa28df8 100644 --- a/Skeleton.Web.Server/Controllers/EntityReaderController.cs +++ b/Skeleton.Web.Server/Controllers/EntityReaderController.cs @@ -8,8 +8,8 @@ namespace Skeleton.Web.Server.Controllers { public class EntityReaderController : ControllerBase - where TEntity : class, IEntity - where TDto : class + where TEntity : class, IEntity, new() + where TDto : class, new() { private readonly IEntityMapper _mapper; private readonly IEntityReader _reader; diff --git a/Skeleton.Web.Server/OwinStartup.cs b/Skeleton.Web.Server/OwinStartup.cs index fd441c4..bd6ff2b 100644 --- a/Skeleton.Web.Server/OwinStartup.cs +++ b/Skeleton.Web.Server/OwinStartup.cs @@ -20,8 +20,8 @@ public class OwinStartup public IDisposable StartServer(Uri url, Action bootstrap) { - url.ThrowIfNull(nameof(url)); - bootstrap.ThrowIfNull(nameof(bootstrap)); + url.ThrowIfNull(); + bootstrap.ThrowIfNull(); _bootstrapper.Configure(); bootstrap(_bootstrapper); diff --git a/Skeleton.Web.Server/Skeleton.Web.Server.csproj b/Skeleton.Web.Server/Skeleton.Web.Server.csproj index 9aa57a2..bb5efe0 100644 --- a/Skeleton.Web.Server/Skeleton.Web.Server.csproj +++ b/Skeleton.Web.Server/Skeleton.Web.Server.csproj @@ -116,7 +116,6 @@ Properties\GlobalAssemblyInfo.cs - diff --git a/Skeleton.Web.Server/UnityResolver.cs b/Skeleton.Web.Server/UnityResolver.cs index 66fb4f6..01ebc6a 100644 --- a/Skeleton.Web.Server/UnityResolver.cs +++ b/Skeleton.Web.Server/UnityResolver.cs @@ -12,7 +12,7 @@ public sealed class UnityResolver : IDependencyResolver public UnityResolver(IUnityContainer container) { - container.ThrowIfNull(nameof(container)); + container.ThrowIfNull(); _container = container; }